MokaByte 74- Maggio 2003 
Setup di architetture J2EE
Configurare JMS con JBoss 2.4.x
di
Davide Brusamolino
Java Message Service è un servizio che mi permette fra le altre cose di gestire lo scambio di messaggi in maniera asincrona. Questo sta a significare che chi spedisce non ha una diretta connessione con chi riceve. La prima versione di specifiche è uscita nell'Agosto del 1998 e solo recentemente è stata integrata nella J2EE. Il messaging service di JBoss è compatibile con le specifiche JMS 1.0.2

JBossMQ

La configurazione del JMS Provider di JBoss avviene nel file jboss.jcml nella directory di configurazione (jboss\conf\default) identificata dal commento:

<!-- ======================================================= -->
<!-- JBossMQ -->
<!-- ======================================================= -->

Generalmente posso compiere 3 tipi operazioni per modificare la configurazione di base:
1) aggiunta di una nuova destinazione
2) gestione utente
3) gestione del connection factories


Aggiunta di una nuova destinazione
Ho 2 modi per aggiungere una nuova destinazione in Jboss:

  1. Nel file jboss.jcml: se per esempio voglio creare una nuova topic chiamata 'testTopic' devo inserire il seguente codice in formato xml:

    <mbean code="org.jboss.mq.server.TopicManager"
    name="JBossMQ:service=Topic,name=testTopic"/>

  2. Servendomi dell'interfaccia fornita da JBoss. Eseguire lo startup (comando run directory
    bin), aprire un browser e digitare http://localhost:8082, comparirà la lista di tutti i servizi
    attivi in JBoss.



Figura 1



Selezionado 'service=Server' si accede ad una seconda pagina che mi permette la
creazione della mia nuova destinazione


Figura 2

Alla fine dopo la conferma dell'avvenuta creazione tornando alla pagina iniziale vedrò una
nuova riga con la nuova destinazione.


Figura 3

Attenzione: questa operazione a differenza della numero 1) è momentanea nel senso
che facendo un reboot di JBoss verrà persa.

Quando farò la look up per utilizzare questa nuova risorsa dovrò specificare il nome con un prefisso ovvero nel nostro caso avendo creato una topic quando farò la look up il JNDI name sarà topic/testTopic.

 

Gestione Utente
Questa funzionalità è necessaria se voglio gestire una persistenza duratura dei miei messaggi. Nel file jbossmq-state.xml ( jboss\conf\default ) viene inserito il seguente codice:

<User>
  <Name>Davide</Name>
  <Password>Yarelys</Password>
  <Id>Naike</Id>
</User>

Il riferimento al file jbossmq-state.xml lo troviamo all'interno del solito jboss.jcml:

<mbean code="org.jboss.mq.server.StateManager"        name="JBossMQ:service=StateManager">
  <attribute name="StateFile">jbossmq-state.xml</attribute>
</mbean>


Gestione Connection Factories
JBoss definisce un differente numero di connection factories per topics e queues dipendente dal tipo di protocollo utilizzato. Tutti i tipi di factories e properties ad esse associate sono specificate nel file jboss.jcml:

<mbean code="org.jboss.mq.il.jvm.JVMServerILService"
       name="JBossMQ:service=InvocationLayer,type=JVM">
  <attribute name="ConnectionFactoryJNDIRef">
    java:/ConnectionFactory
  </attribute>
  <attribute name="XAConnectionFactoryJNDIRef">
    java:/XAConnectionFactory
  </attribute>
</mbean>

<mbean code="org.jboss.mq.il.rmi.RMIServerILService"
       name="JBossMQ:service=InvocationLayer,type=RMI">
  <attribute name="ConnectionFactoryJNDIRef">
     RMIConnectionFactory</attribute>
  <attribute
  name="XAConnectionFactoryJNDIRef">RMIXAConnectionFactory</attribute>
</mbean>

<mbean code="org.jboss.mq.il.oil.OILServerILService"
       name="JBossMQ:service=InvocationLayer,type=OIL">
  <attribute name="ConnectionFactoryJNDIRef">
    ConnectionFactory
  
</attribute>
  <attribute name="XAConnectionFactoryJNDIRef">
    XAConnectionFactory
  </attribute>
</mbean>

<mbean code="org.jboss.mq.il.uil.UILServerILService"
       name="JBossMQ:service=InvocationLayer,type=UIL">
  <attribute name="ConnectionFactoryJNDIRef">
    UILConnectionFactory
  </attribute>
  <attribute name="XAConnectionFactoryJNDIRef">
    UILXAConnectionFactory
   </attribute>
</mbean>

Vediamo brevemente il significato:

OIL: è quella di default risulta molto veloce basata su socket
UIL: utilizzata per passare dal firewall e quando il client non conosce correttamente IP del
server
RMI: è il primo tipo scritto molto stabile ma lenta

Diamo un elenco di alcune connection factories presenti in JBoss con il loro tipo:

Es. di codice riassuntivo

private void maker(){
  Hashtable props = new Hashtable();
  props.put(Context.INITIAL_CONTEXT_FACTORY,
            "org.jnp.interfaces.NamingConnectionFactory");
  props.put(Context.PROVIDER_URL,"localhost:1099");
  props.put("java.naming.rmi.security","yes");
  props.put(Context.URL_PKG_PREFIXES,"org.jboss.naming");
  Context context = new InitialContext(props);
  TopicConnectionFactory
topicFactory;
    topicFactory =(TopicConnectionFactory)context.lookup(
                                        "TopicConnectionFactory");
  TopicConnection
topicConnection;
  topicConnection = TopicFactory.createTopicConnection();
  Topic topic = (Topic) context.lookup("topic/testTopic");
  ...

}

 

Persistenza dei Messaggi
Il Persistence Manager è il responsabile per memorizzare i messaggi in caso di fault del server, e permettere quindi il loro recupero in un secondo tempo.
Ci sono quattro tipi di persistenza:


La persistenza di default è di tipo rolliglogged:

<mbean code="org.jboss.mq.pm.rollinglogged.PersistenceManager"
name="JBossMQ:service=PersistenceManager">
<attribute name="DataDirectory">../../db/jbossmq/</attribute>
</mbean>

Mi permette di memorizzare diversi messaggi in file di log nella directory definita da 'DataDirectory'.
Se voglio cambiare il tipo di persistenza per File e Logged è sufficiente cambiare 'code' dell'mbean; in particolare per File è 'org.jboss.mq.pm.file.PersistenceManager' mentre per la Logged e 'org.jboss.mq.pm.logged.PersistenceManager'.
Discorso a parte è per la persistenza JDBC.

 

Persistenza JDBC
Per questo tipo di persistenza ho bisogno di un db di appoggio.
Devo creare :

  1. le seguenti tabelle:

    CREATE TABLE JMS_MESSAGES(
    MESSAGEID CHAR(17) NOT NULL,
    DESTINATION VARCHAR(30) NOT NULL,
    MESSAGEBLOB BLOB,
    PRIMARY KEY (MESSAGEID, DESTINATION));
    CREATE INDEX JMS_MESSAGES_DEST ON JMS_MESSAGES(DESTINATION);
    CREATE TABLE JMS_TRANSACTIONS(
    ID CHAR(17)
    );

  2. configurare una connessione JDBC nel file jcml.jboss ( vedi articolo Configurare una
    connessione a db con JBoss 2.4.x) es con il nome 'OracleDS'

  3. inserire nel file jboss.jcml il seguente codice (commentando quello precedente):

    <mbean code="org.jboss.mq.pm.jdbc.PersistenceManager"
    name="JBossMQ:service=PersistenceManager">
    <attribute name="JmsDBPoolName">java:/OracleDS
    </attribute>
    </mbean>

Es di codice per un subscriber:

private void method(String factoryJNDI, String topicJNDI
                    String user,String password){
  Hashtable props = new Hashtable();
  props.put(Context.INITIAL_CONTEXT_FACTORY,
            "org.jnp.interfaces.NamingConnectionFactory");
  props.put(Context.PROVIDER_URL,"localhost:1099");
  props.put("java.naming.rmi.security","yes");
  props.put(Context.URL_PKG_PREFIXES,"org.jboss.naming");
  Context context = new InitialContext(props);
  TopicConnectionFactory topicFactory =
                (TopicConnectionFactory)context.lookup(factoryJNDI);
  TopicConnection topicConnection =
  topicFactory.createTopicConnection(user,password);
  TopicSession topicSession = topicConnection.createTopicSession(
  false,Session.AUTO_ACKNOWLEDGE);
  Topic topic = (Topic)context.lookup(topicJNDI);
  TopicSubscriber topicSubscriber =
  topicSession.createDurableSubscriber(topic,user);
  …………………
  ……………
}


File jboss.xml

Se voglio attenermi alle specifiche J2EE devo rimappare le risorse utilizzando i file messi a disposizione da JBoss.
Dopo il deploy avrò il riferimento alle mie risorse all'interno del file ejb-jar.xml es. per un session bean

<session>
<ejb-name>nomeBean</ejb-name>
...
<resource-env-ref>
<resource-env-ref-name>jms/testTopic
</resource-env-ref-name>
<resource-env-ref-type>javax.jms.Topic
</resource-env-ref-type>
</resource-env-ref>
</session>


la corrispondente porzione di codice nel file jboss.xml:

<session>
<ejb-name>nomeBean</ejb-name>
<resource-env-ref>
<resource-env-ref-name>jms/testTopic
</resource-env-ref-name>
<jndi-name>topic/testTopic</jndi-name>
</resource-env-ref>
</session>

così facendo nella look up potrò scrivere

InitialContext iniCtx = new InitialContext();
Topic topic = (Topic)iniCtx.lookup("java:comp/env/jms/testTopic");

Nel caso utilizzi un MDB utilizzando una scrittura persistente dei messaggi distinguo 2 casi di persistenza 1) BPM, 2) CMP

1) Tralasciando il codice i file di configurazione saranno:

file ejb-jar.xml:

…..
<message-driven>
<ejb-name>nome</ejb-name>
<ejb-class>nome classe<ejb-class>
<transaction-type>Bean</transaction-type>
<acknowledge-mode>Auto-acknowledge</acknowledge-mode>
<message-driven-destination>
<destination-type>javax.jms.Topic</destination-type>
</message-driven-destination>
</message-driven>

file jboss.xml:

<message-driven>
<ejb-name>nome</ejb-name>
<resource-env-ref>
<resource-env-ref-name>jms/testTopic
</resource-env-ref-name>
<jndi-name>topic/testTopic</jndi-name>
</resource-env-ref>
</message-driven>


in questo caso tutta la logica di 'gestione' della topic è fatta da codice.

2) CMP:

file ejb-jar.xml:

...
<message-driven>
<ejb-name>nome</ejb-name>
<ejb-class>nome classe<ejb-class>
<transaction-type>Container</transaction-type>
<acknowledge-mode>Auto-acknowledge</acknowledge-mode>
<message-driven-destination>
<destination-type>javax.jms.Topic</destination-type>
<subscription-durability>Durable
</subscription-durability >
</message-driven-destination>
</message-driven>

file jboss.xml: (Vedi Gestione Utente file jbossmq-state.xml)

<message-driven>
<ejb-name>nome</ejb-name>
<resource-env-ref>
<resource-env-ref-name>jms/testTopic
</resource-env-ref-name>
<jndi-name>topic/testTopic</jndi-name>
</resource-env-ref>
<mdb-user>Davide</mdb-user>
<mdb-passwd>Yarelys</mdb-passwd>
<mdb-subscriber-id>Naike</mdb-subscriber-id>
</message-driven>

Come ci si può immaginare il codice con la CMP sarà molto più snello poiché tutte le operazioni di 'autenticazione', settaggio ID etc. verranno fatte dal Container.

 

Conclusioni
Come già citato il comportamento di JBoss è all'altezza di altri, anche se purtroppo più si cerca di approfondire e più la documentazione è centellinata. Il più grosso lavoro a volte consiste nel leggere lunghissime mailing list (www.jboss.org) per risolvere problemi di qualche riga di codice.
E' vero anche, questo è un mio personale pensiero, che se non si 'soffre' non ci si diverte.

 

Bibliografia
[1] * "Manual - online HTML version"- www.jboss.org
[2] * SCOTT STARK, MARC FLEURY "JBoss Administration and Development "- JBoss Group

MokaByte® è un marchio registrato da MokaByte s.r.l. 
Java®, Jini® e tutti i nomi derivati sono marchi registrati da Sun Microsystems.
Tutti i diritti riservati. E' vietata la riproduzione anche parziale.
Per comunicazioni inviare una mail a info@mokabyte.it