MDB e JMS con JBoss AS 7

Nell’era delle App dove tutto è smart e veloce, parlare di Message Driven Bean (MDB) e Java Message Service (JMS) sembra retrogrado e pesante. In realtà, se sviluppate applicazioni a livello enterprise, non è così strano dover ricorrere a bus di messaggistica per risolvere determinati scenari di business. In Java EE 5 inoltre, come già affrontato a suo tempo, se avevamo l’esigenza di eseguire operazioni in modo asincrono rispetto alla chiamata del client, le code potevano essere una valida seppur complessa alternativa per ottenere lo scopo.
In passato abbiamo anche avuto modo di approfondire sia con un po’ di teoria che di pratica cosa sono le code JMS, gli MDB e come si lavora con essi con JBoss AS 6. Da tempo è uscito JBoss AS 7, ma non abbiamo mai affrontato l’argomento con la nuova versione del nostro Application Server preferito. E’ tempo di aggiornarsi un po’.

Prima di cominciare

Se gestite il vostro progetto con Maven e siete partiti dalla famiglia di archetipi

jboss-javaee6-webapp-*

per risolvere le dipendenze JMS in compilazione è necessario importare nel vostro modulo EJB le dipendenze JBoss per JMS:

<dependency>
   <groupId>org.jboss.spec.javax.jms</groupId>
   <artifactId>jboss-jms-api_1.1_spec</artifactId>
</dependency>

Facendo parte del BOM incluso nel progetto POM principale, la versione è automaticamente gestita.

Configurazione del Server

JBoss 7 raccoglie tutta la configurazione in un unico file xml. La maggior parte delle volte avremo a che fare con il file standalone.xml, ma gli stessi discorsi che faremo valgono anche se usiamo JBoss in modalità domain, gestita dal file (indovinate un po’) domain.xml. La natura modulare dell’AS ha consentito agli sviluppatori di realizzare altri file di configurazione che includono funzionalità aggiuntive, caratterizzati dai suffissi -full.xml, -ha.xml e -full-ha.xml.
Senza scendere nei dettagli, nella full si abilita tutto lo stack della specifica Java EE 6, che non sempre è completamente necessaria, mentre nella HA (High Availability), si attivano quelle funzionalità che garantiscono l’alta affidabilità e la continuità del servizio offerto da JBoss (leggi cluster).

La via semplice

JMS e gli MDB rientrano nella categoria del profilo full. Come attivarlo quindi?
Se avviamo il server come servizio o comunque tramite gli script standalone.sh/standalone.bat, basta individuare nel file JAVA_HOME/bin/standalone.conf il parametro:

-Djboss.server.default.config=standalone.xml

e aggiungere il suffisso -full.xml nel nome del file per avviare il server.

In fase di sviluppo, da Eclipse invece, basta fare doppio click sul nome del server e cliccare il link “Open lauch configuration”: in questo caso il parametro da cercare e sostituire sarà

--server-config=standalone.xml

Rimbocchiamoci le maniche

Se siamo maniaci del controllo, o non vogliamo cambiare profilo, possiamo portarci “a casa” quello che ci server dal profilo full.
Per cominciare basta copiarsi:

  • l’estensione
    <extension module="org.jboss.as.messaging"/>
    da riportare in cima al file
  • tutto il subsystem urn:jboss:domain:messaging:1.1
  • l’attivazione degli MDB:
    <mdb>
       <resource-adapter-ref resource-adapter-name="hornetq-ra"/>
       <bean-instance-pool-ref pool-name="mdb-strict-max-pool"/>
    </mdb>
    

    da riportare nel subsystem urn:jboss:domain:ejb3:1.2
  • i socket bindings:
    <socket-binding name="messaging" port="5445"/>
    <socket-binding name="messaging-throughput" port="5455"/>
    

    da aggiungere al socket-binding-group in fondo al file

Configurare la coda JMS

Indipendentemente dalla scelta presa in precedenza, la configurazione di default contenuta nel subsystem urn:jboss:domain:messaging:1.1 prevede:

  • Un Connection Factory raggiungibile dalla stessa JVM con nome JNDI:
    java:/ConnectionFactory
  • Un Connection Factory raggiungibile da remoto con nome JNDI:
    java:jboss/exported/jms/RemoteConnectionFactory.
    Da notare che in questo caso l’accesso è regolamentato dai security-settings definiti nello stesso subsystem
  • Una coda di nome testQueue che risponde ai nomi JNDI:
    queue/test e java:jboss/exported/jms/queue/test
  • Un topic di nome testTopic che risponde ai nomi JNDI:
    topic/test e java:jboss/exported/jms/topic/test

Per aggiungere o modificare le code basta intervenire in questo punto. Un semplice esempio funzionante sulla configurazione di default per inviare messaggi di testo è:

@Stateless
@LocalBean
public class JmsMessageProducer {

   @Resource(name="java:/ConnectionFactory")
   private ConnectionFactory connectionFactory;
   
   @Resource(name="java:/queue/test")
   private Queue queue;
   
   public void sendTextMessage(String text) throws JMSException {
      Connection connection = null;
      try {
         connection = connectionFactory.createConnection();
         connection.start();
         Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
         MessageProducer producer = session.createProducer(queue);
         producer.send(session.createTextMessage(text));
      } finally {
         if (connection != null) {
            connection.close();
         }
      }
   }

}

da notare la riga evidenziata: il nome della coda in questo caso richiede il prefisso java://. Nell’MDB che riceve il messaggio invece non è necessaria:

@MessageDriven(activationConfig = {
      @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
      @ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/test") })
public class JmsMessageListener implements MessageListener {

   private Logger logger = LoggerFactory.getLogger(JmsMessageListener.class);

   /**
    * @see MessageListener#onMessage(Message)
    */
   public void onMessage(Message message) {
      try {
         logger.info("Messaggio ricevuto: " + ((TextMessage) message).getText());
      } catch (JMSException e) {
         logger.error("Errore durante l'interpretazione del messaggio " + message, e);
      }
   }
}

Conclusioni

Per chi ha già usato JMS e gli MDB con JBoss AS6 non noterà nessuna differenza rispetto all’AS7 (e meno male, non è mica cambiata la specifica…). Anzi, anche l’implementazione è sempre HornetQ, introdotto con l’AS 6. Portare quindi il codice suo nuovo AS 7 è solo un questione di configurazione e richiede solo un po’ di dimestichezza con lo standalone.xml e nient’altro.

Andrea Como

Sono un software engineer focalizzato nella progettazione e sviluppo di applicazioni web in Java. Presso OmniaGroup ricopro il ruolo di Tech Leader sulle tecnologie legate alla piattaforma Java EE 5 (come WebSphere 7.0, EJB3, JPA 1 (EclipseLink), JSF 1.2 (Mojarra) e RichFaces 3) e Java EE 6 con JBoss AS 7, in particolare di CDI, JAX-RS, nonché di EJB 3.1, JPA2, JSF2 e RichFaces 4. Al momento mi occupo di ECM, in particolar modo sulla customizzazione di Alfresco 4 e sulla sua installazione con tecnologie da devops come Vagrant e Chef. In passato ho lavorato con la piattaforma alternativa alla enterprise per lo sviluppo web: Java SE 6, Tomcat 6, Hibernate 3 e Spring 2.5. Nei ritagli di tempo sviluppo siti web in PHP e ASP. Per maggiori informazioni consulta il mio curriculum pubblico. Follow me on Twitter - LinkedIn profile - Google+