Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial
  • Lezione 14 di 68
  • livello ninja
Indice lezioni

MDB: durabilità delle Topic e interfacce senza metodi

Proseguiamo il nostro approfondimento sui Message Driven Bean analizzando la durabilità delle Topic e l'implementazione delle interfacce senza metodi.
Proseguiamo il nostro approfondimento sui Message Driven Bean analizzando la durabilità delle Topic e l'implementazione delle interfacce senza metodi.
Link copiato negli appunti

Durabilità delle Topic

Una proprietà interessante, impostabile con @ActivationConfigProperty, è la durabilità per una Topic. Nel funzionamento publish and subscribe, di default, una copia del messaggio è inviata a tutti i subscriber connessi. Se un subscriber non dovesse essere connesso nella fase di ricezione di un messaggio, lo perderebbe inevitabilmente.

Impostando la durabilità su Durable, il subscriber non connesso riceverà il messaggio nel momento in cui effettua la connessione. Questo grazie al fatto che il MOM
conserva per lui una copia del messaggio in quanto registrato come subscriber durevole. Affinché un MDB sia un subscriber durevole, possiamo utilizzare l'attributo activationConfig nel seguente modo:

activationConfig={
				@ActivationConfigProperty(
						propertyName="destinationType",
						propertyValue="javax.jms.Topic"),
				@ActivationConfigProperty(
						propertyName="destinationLookup",
						propertyValue="java:jboss/exported/jms/topic/ShippingTopic"),
				@ActivationConfigProperty(
						propertyName="subscriptionDurability",
						propertyValue="Durable")
		}

Prima di definire un caso di test nella classe IntegrationTestCase per l'MDB creato, disabilitiamo l'autenticazione del MOM utilizzato da JBoss Wildfly per evitare errori. A tal fine individuiamo il tag Hornetq nel file standalone-full.xml e impostiamo il tag security-enabled su false:

<hornetq-server>
      <journal-file-size>102400</journal-file-size>
      <security-enabled>false</security-enabled>
      .....

JUnit test e connessione JMS

Possiamo ora definire un JUnit test che effettua una connessione JMS, costruisce un produttore di messaggi per ShippingQueue e invia un messaggio testuale:

....
    private static final String JMS_CONNECTION_FACTORY_JNDI_NAME="/jms/RemoteConnectionFactory";
    private static final String JMS_QUEUE_JNDI_NAME="/jms/queue/ShippingQueue";
    ....
    @Test
    public void testShippingMDB() throws NamingException, JMSException {
        ConnectionFactory  connectionFactory = (ConnectionFactory)
				namingContext.lookup(JMS_CONNECTION_FACTORY_JNDI_NAME);
        Queue shippingQueue = (Queue)namingContext.lookup(JMS_QUEUE_JNDI_NAME);
        Connection connect = connectionFactory.createConnection();
        Session session = connect.createSession(false, Session.AUTO_ACKNOWLEDGE);
        MessageProducer producer = session.createProducer(shippingQueue);
        TextMessage textMsg = session.createTextMessage();
        textMsg.setText("Order message!");
        producer.send(textMsg);
        connect.close();
    }

Esaminiamo il codice. Un oggetto ConnectionFactory incapsula le informazioni di configurazione per il collegamento al MOM, nel nostro caso Hornetq di JBoss. Oltre al collegamento al MOM dobbiamo recuperare la Queue sulla quale inviare il messaggio. Con questi oggetti possiamo aprire una connessione JMS, creare una sessione, un produttore di messaggi (in questo caso testuali) e infine inviare un messaggio.

Per ragioni di efficienza l'oggetto javax.jms.Connection rappresenta una connessione thread-safe verso il MOM, questo significa che una connessione JMS può essere condivisa.

Utilizzando il metodo createSession() di Connection, otteniamo un oggetto javax.jsm.Session che è invece un task a singolo thread necessario per poter inviare e ricevere messaggi.

Il primo parametro di createSession() specifica se la sessione è transazionale o meno. In caso di valore true, l'effettivo invio del messaggio avviene sulla chiamata del metodo commit() o alla chiusura della sessione. In caso di valore false il messaggio viene inviato prima possibile.

Il secondo parametro indica la modalità di acknowledge, cioè il consenso alla rimozione del messaggio dalla Queue. In generale il messaggio non viene rimosso fino a quando il consumer non lo abbia ricevuto dando il consenso alla rimozione. La modalità Session.AUTO_ACKNOWLEDGE prevede la rimozione del messaggio non appena ricevuto dal consumer.

Non possiamo inviare messaggi attraverso un oggetto Session, ma abbiamo bisogno di ottenere un produttore di messaggi javax.jms.MessageProducer, creare un particolare tipo di messaggio, ad esempio javax.jms.TextMessage, ed infine inviarlo con il metodo send().

MDB e interfacce senza metodi

A partire dalla versione EJB 3.2 gli MDB possono implementare interfacce senza metodi. Questa caratteristica permette di esporre tutti i metodi pubblici del Bean e delle classi eredidate ad eccezione di Object. In pratica possiamo fare in modo che un MDB riceva messaggi da più canali eseguendo un particolare metodo per un messaggio ricevuto da un canale. Vediamo la versione EJB 3.2 del bean shipping processor che chiamiamo ShippingProcessor2:

package it.html.progetto1.mdb.ejb32;
import javax.ejb.MessageDriven;
import org.jboss.ejb3.annotation.ResourceAdapter;
import it.html.progetto1.mdbconnect.NoMethodsListenerIntf;
@MessageDriven(
		name="ShippingProcessor2"
)
@ResourceAdapter(value="Progetto1Ear.ear#Progetto1Connector.rar")
public class ShippingProcessor2 implements NoMethodsListenerIntf  {
    public void order1(String message){
        System.out.println("Order1 invoked:"+message);
    }
    public void order2(String message){
        System.out.println("Order2 invoked:"+message);
    }
}

L'annotation @ResourceAdapter è propria di JBoss e consente di specificare un particolare resource adapter per l'MDB. Il resource adapter che dobbiamo implementare è un connettore JCA che ascolta su diverse code e, attraverso l'uso della reflection, è in grado di invocare order1() o order2().

Attraverso il menù "File" di JBoss Developer Studio creiamo un Connector Project di nome
Progetto1Connector e lo inseriamo nel Build Path del progetto ProgettoEjb1. Aggiungiamo inoltre Progetto1Connector alle proprietà Project References e Deployment Assembly del progetto Progetto1Ear.

In questo modo il connettore verrà installato come modulo Progetto1Connector.rar del pacchetto applicativo Progetto1Ear.ear. In Progetto1Connector, nel source folder connectorModule, definiamo il package it.html.progetto1.mdbconnect; al suo interno iniziamo con il definire l'interfaccia senza metodi implementata dall'MDB:

package it.html.progetto1.mdbconnect;
public interface NoMethodsListenerIntf {}

E la classe che definisce un ActivationSpec per il collegamento ad una Queue e il recupero di messaggi:

package it.html.progetto1.mdbconnect;
import java.io.Serializable;
import javax.resource.ResourceException;
import javax.resource.spi.Activation;
import javax.resource.spi.ActivationSpec;
import javax.resource.spi.InvalidPropertyException;
import javax.resource.spi.ResourceAdapter;
@Activation(
	    messageListeners = {NoMethodsListenerIntf.class}
)
public class MdbEventSpecification implements ActivationSpec, Serializable {
	private static final long serialVersionUID = 6335290773122081421L;
	private ResourceAdapter resourceAdapter;
	@Override
	public ResourceAdapter getResourceAdapter() {
		return resourceAdapter;
	}
	@Override
	public void setResourceAdapter(ResourceAdapter resourceAdapter) throws ResourceException {
	  this.resourceAdapter = resourceAdapter;
	}
	@Override
	public void validate() throws InvalidPropertyException {
	}
}

Ti consigliamo anche