L'articolo è rivolto a coloro che già conoscono le basi di JMS (Java Message Service). Impareremo, infatti, a configurare una Topic con JBoss 4.2.2GA e implementeremo un Message Driven Bean in ascolto su di essa.
Per creare una Topic è necessario creare un file XML, il cui nome termina con "-service" (html-topic-service.xml), simile al seguente, nel quale viene definito il nome della Topic. In questo file è possibile definire anche eventuali parametri relativi alla sicurezza e alla persistenza.
<?xml version="1.0" encoding="UTF-8"?>
<server>
<mbean code="org.jboss.mq.server.jmx.Topic" name="jboss.mq.destination:service=Topic,name=HtmlTopic">
<depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
</mbean>
</server>
Il file deve essere inserito nella directory deploy/jms di JBoss. Nel momento in cui JBoss elabora il file XML, restituisce un messaggio del tipo:
[HtmlTopic] Bound to JNDI name: topic/HtmlTopic.
Se accediamo alla console di Jboss (http://localhost:8080/web-console/) possiamo visualizzare i dettagli della Topic che abbiamo appena creato. Per accedere al dettaglio è necessario cliccare sul nome della nostra Topic, disponibile nel frame di sinistra al seguente percorso: "J2EE Domains/jboss.management.local/J2EE Resource/Local JMS/Topic". Nel frame di destra verrà caricato il dettaglio: nome JNDI, messaggi inviati sulla Topic, numero di sottoscrittori, e altro.
Ora che abbiamo creato la nostra Topic, occorre implementare un MDB che si metta in ascolto. Per semplicità il nostro MDB riceverà un semplice messaggio di testo e lo stamperà sulla console.
Un MDB è un EJB a tutti gli effetti ma, non essendo referenziabile, non è dotato di interfacce home e remote.
Per creare un MDB è sufficiente creare una classe che implementi sia l'interfaccia javax.jms.MessageListener che l'interfaccia javax.ejb.MessageDrivenBean. Entrambe le classi sono disponibili nella libreria jbossall-client.jar presente nella directory client di Jboss.
I metodi definiti nelle interfaccie sono i seguenti:
- public void setMessageDrivenContext(MessageDrivenContext mdc) throws EJBException
- public void ejbCreate()
- public void ejbRemove()
- public void onMessage(Message message)
Il metodo più importante è onMessage
poiché viene invocato automaticamente dal container, quando arriva un messaggio sulla Topic. I metodi ejbCreate
ed ejbRemove
, vengono richiamati per creare e per eliminare l'MDB. Il metodo setMessageDrivenContext
, viene chiamato prima del metodo ejbCreate
, per inizializzare il Contesto.
package lucasantaniello.ejb.mdb;
import javax.ejb.EJBException;
import javax.ejb.MessageDrivenBean;
import javax.ejb.MessageDrivenContext;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
import org.jboss.logging.Logger;
public class HtmlMDB implements MessageDrivenBean, MessageListener{
private static final long serialVersionUID = 7585993155984264586L;
private static Logger log = Logger.getLogger(HtmlMDB.class);
public void ejbCreate() throws EJBException{
log.info("HtmlMDB ejbCreate");
...
}
public void ejbRemove() throws EJBException{
log.info("HtmlMDB ejbRemove");
...
}
public void setMessageDrivenContext(MessageDrivenContext mdc) throws EJBException{
log.info("HtmlMDB setMessageDrivenContext");
...
}
public void onMessage(Message msg){
log.info("HtmlMDB onMessage");
if (msg instanceof TextMessage){
TextMessage textMsg = (TextMessage) msg;
try{
log.info(textMsg.getText());
}catch (Exception exc){
throw new RuntimeException(exc.toString());
}
}
}
}
Come qualsiasi altro ejb, occorre creare anche due file di configurazione, il file ejb.jar e il file jboss.xml.
Il file ejb-jar.xml, contiene il nome dell'MDB, la classe che implementa le interfacce MessageListener e MessageDrivenBean, e il tipo di Destination (javax.jms.Topic).
<?xml version="1.0"?>
<!DOCTYPE ejb-jar PUBLIC
"-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN"
"http://java.sun.com/dtd/ejb-jar_2_0.dtd">
<ejb-jar>
<enterprise-beans>
<message-driven>
<ejb-name>HtmlMDB</ejb-name>
<ejb-class>lucasantaniello.ejb.mdb.HtmlMDB</ejb-class>
<transaction-type>Container</transaction-type>
<acknowledge-mode>AUTO_ACKNOWLEDGE</acknowledge-mode>
<message-driven-destination>
<destination-type>javax.jms.Topic</destination-type>
</message-driven-destination>
</message-driven>
</enterprise-beans>
</ejb-jar>
Il file jboss.xml, contiene il nome dell'MDB e il nome JNDI della destination sulla quale mettersi in ascolto.
<?xml version="1.0"?>
<jboss>
<enterprise-beans>
<message-driven>
<ejb-name>HtmlMDB</ejb-name>
<destination-jndi-name>topic/HtmlTopic</destination-jndi-name>
</message-driven>
</enterprise-beans>
</jboss>
Per fare il deploy dell'MDB su JBoss è necessario creare un file JAR che, oltre alla classe HtmlMDB, contiene una cartella META-INF, nella quale sono presenti i due file XML creati. Il file JAR va posizionato nella cartella deploy di JBoss. Quando il file viene elaborato, verrà stampato un messaggio sulla console.
[EjbModule] Deploying HtmlMDB
[EJBDeployer] Deployed: file:... /JBoss_4.2.2.GA/server/default/deploy/HtmlMDB.jar
Adesso creiamo un semplice Client che invia un messaggio sulla nostra Topic.
package lucasantaniello.ejb.client;
import java.util.Hashtable;
import javax.jms.TextMessage;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicPublisher;
import javax.jms.TopicSession;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class ClientMDB{
private static String JNDI_CONNECTION_FACTORY = "ConnectionFactory";
private static String JNDI_TOPIC = "topic/HtmlTopic";
public static void main(String[] args){
System.out.println("Start Publisher");
//STEP 1: Ottenere riferimento al Context del Server Jboss
InitialContext ctx = null;
try{
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
env.put(Context.PROVIDER_URL, "jnp://localhost:1099");
ctx = new InitialContext(env);
}catch (NamingException e){
System.out.println(e.getMessage());
}
try{
//STEP 2: Ottenere il riferimento alla Connection Factory mediante JNDI
TopicConnectionFactory topicConnectionFactory = (TopicConnectionFactory)ctx.lookup(JNDI_CONNECTION_FACTORY);
//STEP 3: Ottenere il riferimento alla Topic mediante JNDI
Topic topic = (Topic) ctx.lookup(JNDI_TOPIC);
//STEP 4: Utilizzare la connection Factory per creare una Connessione
TopicConnection topicConnection = topicConnectionFactory.createTopicConnection();
//STEP 5: Utilizzare la Connessione per creare una Sessione
TopicSession topicSession = topicConnection.createTopicSession(false, TopicSession.AUTO_ACKNOWLEDGE);
//STEP 6: Utilizzare la Sessione per creare il Messaggio da inviare
TextMessage textMsg = topicSession.createTextMessage();
textMsg.clearBody();
textMsg.setIntProperty("severity", 1);
textMsg.setText("Ciao, sono il producer e sto inviando un messaggio sulla Topic, vediamo se l'MDB intercetta il messaggio!!!");
//STEP 7: Utilizzare la Sessione per creare un Publisher
TopicPublisher publisher = topicSession.createPublisher(topic);
//STEP 8: Invio del messaggio
publisher.send(textMsg);
System.out.println("Messaggio inviato alla Topic");
}catch (Exception e){
System.out.println(e.getMessage());
System.exit(-2);
}
System.out.println("End Publisher");
}
}
Se lanciamo il nostro client, vedremo come sulla console di JBoss apparirà il seguente messaggio:
[HtmlMDB] HtmlMDB setMessageDrivenContext
[HtmlMDB] HtmlMDB ejbCreate
[HtmlMDB] HtmlMDB onMessage
[HtmlMDB] Ciao, sono il producer.
Nel momento in cui il container riceve il messaggio, invoca i metodi dell'MDB in ascolto sulla Topic. I metodi setMessageDrivenContext
ed ejbCreate
, vengono invocati soltanto al primo messaggio, mentre il metodo onMessage
verrà invocato tutte le volte che il container riceverà un messaggio. Qualora il servizio JBoss verrà terminato, verrà invocato il metodo ejbRemove dell'MDB.