- les bases de données sont désormais alimentées au fil de l'eau plutôt que par des batchs ou des travaux planifiés
- les utilisateurs s'attendent de plus en plus à ce qu'on leur pousse l'information alors qu'ils allaient la chercher autrefois.
- ils ont fait leur preuve, depuis plusieurs milliers d'années, alors qu'IBM dominait encore le monde de l'informatique
- ils réduisent les temps de latence ; les notifications des clients, même en nombre, deviennent quasi-instantanées
- ils nécessitent bien moins de ressources que de sonder systématiquement toutes les données depuis parfois des dizaines de programmes
- ils sont capables de monter facilement en charge, du fait de leur nature asynchrone
Cet article illustre ce type d'approche à l'aide d'une file d'attente Oracle Advanced Queuing (AQ) sur laquelle sont publiés des messages JMS qui déclenchent un EJB de type Message Driven Bean dans Weblogic. Il présente les différents aspects d'implémentation et de paramétrage de ces composants...
Résumé
Le schéma ci-dessous présente le fonctionnement de l'architecture publish/subscribe de l'article :La configuration consiste en :
- Une file d'attente AQ dans la base de données, capable d'échanger des messages JMS. Cette file d'attente est appelée Topic dans le contexte JMS, car elle peut avoir plusieurs subscribers (souscripteurs).
- Un module JMS dans Weblogic qui se connecte à la file d'attente AQ en tant que serveur JMS étranger. Celui-ci s'appuie sur une Datasource JDBC créée préalablement et passée en paramètre au connecteur
- Un EJB de type Message Driven Bean lié via des annotations et la configuration JNDI de Weblogic à la base de données et à la file d'attente.
File d'attente AQ et messages JMS
Côté paramètrage, commencez par créer un schéma, une table de type "multi consumers" qui pourra stocker le "Topic". La file associée permet d'échanger des messages JMS (ici javax.jms.TextMessage). Vous aurez besoin de démarrer la file d'attente pour terminer. Voici un exemple de script réalisant l'ensemble de ces opérations :connect / as sysdba
create user demo
identified by demo
default tablespace users;
grant connect, resource, aq_user_role to demo;
grant execute on dbms_aqadm to demo;
grant execute on dbms_aq to demo;
grant execute on dbms_aqin to demo;
grant execute on dbms_aqjms to demo;
connect demo/demo
begin
dbms_aqadm.create_queue_table(
queue_table =>'myQueueTable',
queue_payload_type =>'sys.aq$_jms_text_message',
multiple_consumers =>true);
end;
/
begin
dbms_aqadm.create_queue(
queue_name=>'myqueue',
queue_table=>'myqueuetable');
end;
/
begin
dbms_aqadm.start_queue(queue_name=>'myqueue');
end;
/
Créer le module et le serveur JMS
Une fois la base de données paramétrée, vous pouvez créer le module JMS et le foreign server JMS qui permet de se connecter au Topic JMS supporté par AQ ainsi que les identifiants JNDI correspondants.- Etape 1 : Créez une datasource JDBC
Name: AQJMSOracleDS JNDI Name: jdbc/AQJMSOracleDS Database : Oracle Database Driver: Oracle's Driver (Thin XA) for Service connections; (...) Database Name: Host Name: Port: Database User Name: demo Password: demo Confirm Password: demo Targets : AdminServer
- Etape 2 : Créez un module JMS
*Name: AQJMSModule Descriptor File Name: Location In Domain: Targets : AdminServer Would you like to add resources to this JMS system module? NO
- Etape 3 : Créez une resource JMS de type "Foreign Server"
Create a New JMS System Module Resource Foreign Server *Name: AQJMSForeignServer Targets : Servers |X| AdminServer
- Etape 4 : Modifiez la Context Factory Initiale
JNDI Initial Context Factory: oracle.jms.AQjmsInitialContextFactory JNDI Properties: datasource=jdbc/AQJMSOracleDS |X| Default Targeting Enabled
- Etape 5 : Ajoutez une Connection Factory
*Name: AQJMSForeignConnectionFactory Local JNDI Name: jms/aq/mycf Remote JNDI Name: TopicConnectionFactory
- Etape 6 : Ajoutez une Destination qui pointe vers le Topic
*Name: AQJMSForeignDestination Local JNDI Name: jms/aq/myqueue Remote JNDI Name: Topics/myqueue
- Etape 7 : Redémarrez Weblogic
Oracle® Fusion Middleware Configuring and Managing JMS for Oracle WebLogic ServerVous pouvez vérifier la configuration en affichant la structure JNDI locale du votre serveur ou cluster Weblogic ; dans ce cas, il s'agit de la configuration du serveur AdminServer; l'arbre présente la connection factory et la file d'attente comme ci-dessous :
12c Release 1 (12.1.1)
7 Interoperating with Oracle AQ JMS
Configuring WebLogic Server to Interoperate with AQ JMS
Créer et déployer un EJB MDB
Le développement de l'EJB Message Driven Bean est au-delà de cet article. Vous recollerez sans doute facilement les morceaux... Notez bien, en particulier, que les alias des Connection Factory et destinations JMS sont celles créées précédemment. Voici le fichier Java correspondant :package arkzoyd.demo;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
@MessageDriven(mappedName = "jms/aq/myqueue", activationConfig = {
@ActivationConfigProperty(propertyName = "connectionFactoryJndiName",
propertyValue = "jms/aq/mycf"),
@ActivationConfigProperty(propertyName = "acknowledgeMode",
propertyValue = "Auto-acknowledge"),
@ActivationConfigProperty(propertyName = "destinationType",
propertyValue = "javax.jms.Topic"),
@ActivationConfigProperty(propertyName = "subscriptionDurability",
propertyValue = "Durable"),
@ActivationConfigProperty(propertyName = "clientId",
propertyValue = "LogMessage"),
@ActivationConfigProperty(propertyName = "subscriptionName",
propertyValue = "LogMessage")
})
public class LogMessage implements MessageListener {
public LogMessage() {
}
@Override
public void onMessage (Message message) {
try {
BufferedWriter out = new BufferedWriter(
new FileWriter("/tmp/messages.out",
true));
SimpleDateFormat formatter = new SimpleDateFormat(
"dd/MM/yyyy HH:mm:ss");
out.write(formatter.format(new Date()) + "- Message (" +
((TextMessage) message).getText() + ")\n");
out.close();
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
}
Vous déployerez votre EJB; La console Weblogic permet notamment de superviser l'activité de cet EJB comme vous le voyez ci-dessous :Tester l'envoi d'un message JMS
Le script PL/SQL ci-dessous envoie un message JMS depuis la base de données :connect demo/demo
DECLARE
v_enqueue_options DBMS_AQ.ENQUEUE_OPTIONS_T;
v_message_properties DBMS_AQ.MESSAGE_PROPERTIES_T;
v_message SYS.AQ$_JMS_TEXT_MESSAGE;
v_message_id RAW(16);
BEGIN
v_message := SYS.AQ$_JMS_TEXT_MESSAGE.CONSTRUCT;
v_message.set_text('Message -- TEST --');
dbms_aq.enqueue (
queue_name => 'myqueue',
enqueue_options => v_enqueue_options,
message_properties => v_message_properties,
payload => v_message,
msgid => v_message_id
);
COMMIT;
END;
/
L'EJB en regardant le contenu du fichier
/tmp/message.out :$ tail -f /tmp/messages.out 09/06/2012 00:09:58- Message (date 09/06/2012 00:09:58) 09/06/2012 00:10:10- Message (date 09/06/2012 00:10:10)
Vous pouvez également supervision l'EJB dans la console Weblogic :




4 commentaires:
Bonjour
le problème arrive avec les Durables subscription. Car en l'état on perd les messages entre l'arret/relance du MDB
Avez vous testé ?
Avec AQ ? Ca marche très bien pour moi dans les cas où:
- Je suspends le MDB puis le réactive
- J'arrête l'application et la redémarre
Pour le test, j'ai modifié le script d'envoie des messages pour afficher l'heure d'envoi :
DECLARE
v_enqueue_options DBMS_AQ.ENQUEUE_OPTIONS_T;
v_message_properties DBMS_AQ.MESSAGE_PROPERTIES_T;
v_message SYS.AQ$_JMS_TEXT_MESSAGE;
v_message_id RAW(16);
BEGIN
v_message := SYS.AQ$_JMS_TEXT_MESSAGE.CONSTRUCT;
v_message.set_text('Sending; it is...'||to_char(sysdate,'DD/MM/YYYY HH24:MI:SS'));
dbms_aq.enqueue (
queue_name => 'myqueue',
enqueue_options => v_enqueue_options,
message_properties => v_message_properties,
payload => v_message,
msgid => v_message_id
);
COMMIT;
END;
/
A- Voici le résultat du MDB lorsque celui-ci est suspendu et que je le relance :
12/06/2012 19:14:09- Message (Sending; it is...12/06/2012 19:13:51)
B- Voici le résultat lorsque l'application est arrêtée :
12/06/2012 19:16:20- Message (Sending; it is...12/06/2012 19:16:14)
Par contre, si j'arrête Weblogic et le redémarre, en effet, je perds les messages envoyés dans l'intervalle. Je regarde pourquoi...
Oops... Je le refais !!!
J'avais modifié mon EJB MDB entre temps pour le mettre en non durable ! Bref, dans ma nouvelle configuration et celle de cet article, c'est à dire avec :
@ActivationConfigProperty(propertyName = "subscriptionDurability", propertyValue = "Durable"),
Les messages sont conservés, y compris:
- si on suspend l'EJB MDB et qu'on le redémarre
- si on arrête l'application et qu'on la redémarre
- si on arrête le serveur et qu'on le redémarre
- si on désinstalle l'application et qu'on la réinstalle
-Grégory
Merci gregory
j'ai la même config ( sauf que je travaille avec les fichier xml ejb-jar et weblogic-ejb-jar.xml à la place des annotations)
mais quand je redémarre mes MDB j'ai un message d'erreur :
oracle.jms.AQjmsException: JMS-230: Opération interdite sur un abonnement durable avec TopicSubscriber actif>
Le pire c'est que j'ai 2 MDB qui écoute chacun sur un topics dédié, et un seul me fait ce message d'erreur
Enregistrer un commentaire