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.
Selezionado 'service=Server' si accede ad una seconda pagina che mi permette la creazione della mia nuova destinazione.
Alla fine dopo la conferma dell'avvenuta creazione tornando alla pagina iniziale vedrò una nuova riga con la nuova destinazione.
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
