La classe del Connector
Implementiamo adesso la classe del Connector. Prima di procedere nell'analisi del codice, definiamo le seguenti Queue in standalone-full.xml
:
<jms-queue name="ShippingQueue2">
<entry name="java:jboss/exported/jms/queue/ShippingQueue2"/>
</jms-queue>
<jms-queue name="ShippingQueue3">
<entry name="java:jboss/exported/jms/queue/ShippingQueue3"/>
</jms-queue>
La classe del connettore JCA deve implementare l'interfaccia javax.resource.spi.ResourceAdapter
ed essere annotata con @Connector
:
@Connector(
description = "This is a MDB sample resource adapter",
eisType = "MDB Connector",
vendorName = "JBoss Wildfly",
version = "1.0"
)
public class MdbEventConnector implements ResourceAdapter { ... }
L'interfaccia prevede diversi metodi da implementare, nel nostro caso possiamo lasciar vuoti tutti i metodi tranne endPointActivation()
per il quale forniamo la seguente implementazione:
@Override
public void endpointActivation(MessageEndpointFactory messageEndpointFactory, ActivationSpec activationSpec)
throws ResourceException {
Class<?> beanClass = messageEndpointFactory.getEndpointClass();
try {
InitialContext namingContext = new InitialContext();
ConnectionFactory connectionFactory = (ConnectionFactory) namingContext
.lookup(JMS_CONNECTION_FACTORY_JNDI_NAME);
Queue shippingQueue1 = (Queue) namingContext.lookup(JMS_QUEUE_JNDI_NAME1);
Queue shippingQueue2 = (Queue) namingContext.lookup(JMS_QUEUE_JNDI_NAME2);
JMSContext jmsContext1 = connectionFactory.createContext();
JMSContext jmsContext2 = connectionFactory.createContext();
JMSConsumer jmsConsumer1= jmsContext1.createConsumer(shippingQueue1);
JMSConsumer jmsConsumer2= jmsContext2.createConsumer(shippingQueue2);
jmsConsumer1.setMessageListener(createMdbEventListener(messageEndpointFactory, beanClass, "order1"));
jmsConsumer2.setMessageListener(createMdbEventListener(messageEndpointFactory, beanClass, "order2"));
jmsContext1.start();
jmsContext2.start();
} catch (Exception e) {
e.printStackTrace();
}
}
Il metodo inizia con il recupero della classe dell'MDB collegata al Connettore attraverso messageEndpointFactory.getEndpointClass()
e successivamente ottiene una ConnectionFactory JMS e i riferimenti alle Queue già definite. Sulla ConnectionFactory recuperiamo due JMSContext che consentono di creare due consumer di messaggi, uno per ogni Queue. Sui consumer impostiamo un event listener per il recupero del messaggio e l'invocazione del metodo target dell'MDB:
private MessageListener createMdbEventListener(MessageEndpointFactory messageEndpointFactory, Class<?> beanClass,
String destinationMethod) {
for (Method method : beanClass.getMethods()) {
if (method.getName().equals(destinationMethod)) {
return new MessageListener() {
@Override
public void onMessage(Message msg) {
MessageEndpoint endpoint = null;
try {
String message = ((TextMessage) msg).getText();
endpoint = messageEndpointFactory.createEndpoint(null);
endpoint.beforeDelivery(method);
method.invoke(endpoint, message);
endpoint.afterDelivery();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (endpoint != null) {
endpoint.release();
}
}
}
};
}
}
return null;
}
Il metodo costruisce un MessageListener il cui evento onMessage()
produce l'invocazione del metodo target dell'MDB (blocco try
). Se analizziamo il log prodotto da JBoss Wildfly in fase di deploy troviamo due righe che ci mostrano come gli MDB ShippingProcessor
e ShippingProcessor2
stiano utilizzando rispettivamente gli adapter Hornet
ed MdbEventConnector
:
INFO [org.jboss.as.ejb3] (MSC service thread 1-5) WFLYEJB0042: Started message driven bean 'ShippingProcessor' with 'hornetq-ra.rar' resource adapter
INFO [org.jboss.as.ejb3] (MSC service thread 1-6) WFLYEJB0042: Started message driven bean 'ShippingProcessor2' with 'Progetto1Ear.ear#Progetto1Connector.rar' resource adapter
JUnit test per l'MDB
Concludiamo con il JUnit test per l'MDB ShippingProcessor2
:
....
private static final String JMS_QUEUE_JNDI_NAME2="/jms/queue/ShippingQueue2";
private static final String JMS_QUEUE_JNDI_NAME3="/jms/queue/ShippingQueue3";
....
@Test
public void testShippingMDBNotInt() throws NamingException, JMSException {
ConnectionFactory connectionFactory = (ConnectionFactory)
namingContext.lookup(JMS_CONNECTION_FACTORY_JNDI_NAME);
Queue shippingQueue2 = (Queue)namingContext.lookup(JMS_QUEUE_JNDI_NAME2);
Queue shippingQueue3 = (Queue)namingContext.lookup(JMS_QUEUE_JNDI_NAME3);
Connection connect = connectionFactory.createConnection();
Session session = connect.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer2 = session.createProducer(shippingQueue2);
MessageProducer producer3 = session.createProducer(shippingQueue3);
TextMessage textMsg = session.createTextMessage();
textMsg.setText("Order message for MDB no interface");
producer2.send(textMsg);
producer3.send(textMsg);
connect.close();
}
....
Da notare il recupero dei riferimenti alle Queue, la costruzione di due producer e l'invio del messaggio sulle code. Alla ricezione dei messaggi, grazie al Connector, vengono invocati i metodi order1()
e order2()
di ShippingProcessor2
.