domenica 25 dicembre 2011

Esempio utilizzo MDB

Nel seguente esempio proviamo a :
  • Definire una coda JMS su Jboss 5.1;
  • Realizzare un programma client java che scriva sulla coda dei messaggi;
  • Realizzare un Message Driven Bean che legga il messaggio e lo tolga dalla coda JMS.
DEFINIRE CODA JMS

Sotto la directory default deploy creare una directory denominata code dove andremo a definire la nostra coda JMS.

A questo punto dalla console di amministrazione di Jboss (utenza e pwd di default sono admin admin).




Cliccando su Add a new Resource e seguendo il menu definiamo il nome della coda "MiaCoda" e il JNDI name "code/MiaCoda".
Una volta terminata la procedura possiamo verificare il corretto funzionamento guardando sotto la directory deploy/code, troveremo il file xml MiaCoda-service.xml.

DEFINIRE CLIENT JAVA

Definiamo un semplice progetto Java su eclipse, inserendo nel classpath tutte le librerie presenti nella directory client di Jboss.

Il codice nel main del programma è il seguente:

import java.util.Properties;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.InitialContext;

public class MessageSender {

   
   
    public static void main(String[] args) throws Exception{
        ConnectionFactory connectionFactory;
        Destination destination;
        Properties p=new Properties();
        p.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
        p.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
        p.put(Context.PROVIDER_URL, "jnp://127.0.0.1:1099");
        Context ctx=new InitialContext(p);
        connectionFactory=(ConnectionFactory)ctx.lookup("/ConnectionFactory");
        destination=(Queue)ctx.lookup("/code/MiaCoda");
        System.out.println("La coda e la connessione sono stati recuperati");
        Connection connection=null;
        connection=connectionFactory.createConnection();
        Session session=connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        MessageProducer mp=session.createProducer(destination);
         TextMessage msg = session.createTextMessage();
          for (int i = 0; i < 5; i++) {
          msg.setText("Questo è il messaggio " + (i + 1));
          mp.send(msg);
          }
          connection.close();
          System.out.println("Messaggi inviati correttamente");
         
    }
   
}


Vengono scritti e inviati 5 messaggi.
Se proviamo ad eseguire il programma con Jboss acceso vediamo che da Console ci compare il seguente messaggio:

La coda e la connessione sono stati recuperati
Messaggi inviati correttamente


Quindi andando sulla console di amministrazione di Jboss in corrispondenza della coda "MiaCoda" troviamo:

Vediamo che risultano 0 consumer (nessuno ha letto i messaggi, non essendoci ancora l'MDB) e 5 messaggi presenti nella coda.




DEFINIRE IL MESSAGE DRIVEN BEAN

L' MDB ha il compito di connettersi alla coda e leggere i messaggi presenti.
Per realizzarlo creiamo un progetto Java inserendo nel classpath le librerie client di Jboss 5.1.
Per definire l'MDB annotiamo la classe con @MessageDriven, mentre la classe deve implementare l'interfaccia MessageListener (del package javax.jms).
Da notare la definizione dell'elemento activationConfig dove si specifica il tipo di Destination (in questo caso una coda) e il nome della coda ("code/MiaCoda").

Il codice è il seguente:

import javax.annotation.Resource;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.ejb.MessageDrivenContext;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

@MessageDriven(name="MessageBean",
activationConfig= {
        @ActivationConfigProperty(propertyName="destinationType",
                                    propertyValue="javax.jms.Queue"),
        @ActivationConfigProperty(propertyName="destination",
                                    propertyValue="code/MiaCoda")
                  }
        )

public class MessageBean implements MessageListener {
    @Resource
       private MessageDrivenContext mdc;

     
       public void onMessage(Message msg) {
         TextMessage tmsg = null;

       try
       {
             tmsg = (TextMessage) msg;
             System.out.println("MESSAGE BEAN: Messaggio ricevuto: " + tmsg.getText( ));
             System.out.println ("Metodo onMessage() richiamato");
       }
       catch (JMSException e) {
                               e.printStackTrace( );
                               mdc.setRollbackOnly( );
                              }
      catch (Throwable th)    {
                              th.printStackTrace();
                              }
       }
     
}


Una volta fatto ciò possiamo esportare il progetto come jar file all'interno della directory deploy di JBoss.

Una volta deployato subito si nota sulla console di Jboss che i messaggi messi nella coda sono stati consumati dall'MDB:


13:06:53,945 INFO  [STDOUT] MESSAGE BEAN: Messaggio ricevuto: Questo è il messaggio 2
13:06:53,945 INFO  [STDOUT] Metodo onMessage() richiamato
13:06:53,946 INFO  [STDOUT] MESSAGE BEAN: Messaggio ricevuto: Questo è il messaggio 3
13:06:53,946 INFO  [STDOUT] Metodo onMessage() richiamato
13:06:53,947 INFO  [STDOUT] MESSAGE BEAN: Messaggio ricevuto: Questo è il messaggio 1
13:06:53,947 INFO  [STDOUT] Metodo onMessage() richiamato
13:06:53,947 INFO  [STDOUT] MESSAGE BEAN: Messaggio ricevuto: Questo è il messaggio 4
13:06:53,948 INFO  [STDOUT] Metodo onMessage() richiamato
13:06:53,949 INFO  [STDOUT] MESSAGE BEAN: Messaggio ricevuto: Questo è il messaggio 5
13:06:53,950 INFO  [STDOUT] Metodo onMessage() richiamato


Andando sulla coda via console di amministrazione vediamo infatti che adesso il Campo Consumer count è pari a 1 mentre il Message Count a 0.
Tutti i messaggi sono stati letti quindi dall'MDB e la coda è stata svuotata.

SCRIVERE MESSAGGI SULLA CODA JMS VIA WEB APPLICATION

In questo caso realizziamo una semplice Web appplication con un form su cui si inserisce il messaggio in una textArea e si invia il tutto ad una servlet che si occupa di aggiungere il messaggio alla coda jms.
Si noti come in questo caso i riferimenti alla ConnectionFactory e alla Destination siano recuperati tramite l'annotazione @Resource e non tramite look up JNDI.

public class ScriviMessaggioSuCoda extends HttpServlet {
    private static final long serialVersionUID = 1L;
    @Resource(name="code/MiaCoda",mappedName="code/MiaCoda")
    private javax.jms.Destination codaTest;
    @Resource(name="ConnectionFactory",mappedName="ConnectionFactory")
    private javax.jms.ConnectionFactory connentionFactory;
    /**
     * @see HttpServlet#HttpServlet()
     */
    public ScriviMessaggioSuCoda() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        try
        {
        String messaggio=request.getParameter("txtMessage");
        Connection connection = connentionFactory.createConnection();
          connection=connentionFactory.createConnection();
        Session session=connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        MessageProducer mp=session.createProducer(codaTest);
        TextMessage msg = session.createTextMessage();
        msg.setText(messaggio);
        mp.send(msg);
        connection.close();
        System.out.println("Sending message");
        session.close ();
        PrintWriter wr=response.getWriter();
        wr.write("<b>Messaggio inviato</b>");
        wr.flush();
        }
        catch(Exception ex){
            ex.printStackTrace();
        }
         
       
    }

}

4 commenti:

  1. Articolo interessante, vorrei pero' fosse un po' piu' esplicitato il fatto su come fare partire il programma di scrittura sotto jboss.

    "Se proviamo ad eseguire il programma con Jboss acceso vediamo che da Console ci compare il seguente........."

    RispondiElimina
  2. Grazie.
    Il programma che scrive sulla coda dell'MDB è un semplice client Java quindi è sufficiente da eclipse fare Run as "Java application". E' un progetto Java a parte.
    Va fatto a Jboss acceso perchè il client tramite RMI si connette all'application server creando il contesto dove puntare.

    Properties p=new Properties();
    p.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
    p.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
    p.put(Context.PROVIDER_URL, "jnp://127.0.0.1:1099");
    Context ctx=new InitialContext(p);

    RispondiElimina
    Risposte
    1. Grazie mille per la risposta,
      ti spiego meglio la mia situazione, io ho già un progetto J2EE che
      viene pacchettizzato come un .ear e poi deployato su JBOSS 5.1.0.
      Ho aggiunto la coda grazie al tuo tutorial ed ho aggiunto la classe che hai pubblicato per la scrittura sulla coda.
      A questo punto facendo Run as Java Application ottengo il seguente errore:
      Exception in thread "main" javax.naming.NoInitialContextException: Cannot instantiate class: org.jnp.interfaces.NamingContextFactory [Root exception is java.lang.ClassNotFoundException: org.jnp.interfaces.NamingContextFactory]
      at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:657)
      at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288)
      at javax.naming.InitialContext.init(InitialContext.java:223)
      at javax.naming.InitialContext.(InitialContext.java:197)
      at it.toscana.regione.git.util.MessageSender.main(MessageSender.java:26)
      Caused by: java.lang.ClassNotFoundException: org.jnp.interfaces.Nami

      --------------------------------------
      Pensi che forse mettendolo in un progetto a se stante funzioni ?
      Non ho problemi di compilazione nella classe che hai postato, quindi le libreire dovrebbe vederle.
      A presto.

      F.R




      Elimina
    2. Ciao, il problema sembra dovuto al fatto che non ci sono le giuste dipendenze nel classpath del tuo progetto client java.
      Hai provato ad aggiungerle nel classpath del progetto?
      Guarda anche qui: https://forums.oracle.com/forums/thread.jspa?threadID=2379056
      Trattano un problema simile al tuo.

      Elimina