mardi 6 septembre 2011

L’ordonnancement des messages ou UnitOfOrder dans JMS sous Weblogic permet de respecter l’ordre des messages en arrivées par rapport à leur ordre de production.

Il se peut que lors du passage des messages dans une architecture multitiers, la propagation de certains messages soit ralentie par rapport à d’autres, ce qui peut aboutir à une arrivée désordonnée par rapport à l’ordre de leurs créations.

Une question peut se poser si lors de la propagation des messages des événements imprévus surviennent. Quand est-il de l’ordonnancement si des mécanismes d’erreur réémettent les messages, que se passe-t-il si des messages sont perdus, l’ordonnancement est-il arrêté, etc …

Ce post restitue un test que j’ai réalisé avec un prototype mettant en œuvre le JMS UnitOfOrder avec un certain nombre de simulations d’erreur et de perturbation afin d’évaluer le fonctionnement de cette fonctionnalité.

ARCHITECTURE



Le prototype simule l’envoi de message par un client JAVA multi thread qui va simuler l’envoi de message vers la plateforme JEE.

Message texte envoyé par le producteur de message.
Threads[No Thread]-No[No message]

Deux couches sont implémentées avec une file de messages (Queue) dans lequel est déposé le message puis lues par un MDB. Celui-ci fait appel à un EJB pour remettre le message dans une autre file JMS.

En final le message est déposé dans une file de messages de sortie lue par un client JAVA qui affiche la totalité des messages produits (avec l’ordre d’arrivée).

Les traitements effectués sur les flux sont :

ü  Une temporisation aléatoire (Wait) est introduite dans chaque composant afin de désynchroniser l’ordre d’arrivée final.
ü  Une exception et levé aléatoirement sur les MDB afin de simuler les erreurs techniques. Un mécanisme de rejeux JMS est mise en place sur les files de messages pour réinjecter les messages 1 fois. Au bout du 2eme échec, le message est mis dans une file d’erreurs.
ü  Un mécanisme de switch aléatoire est placé dans l’EJB de sortie afin de simuler les exceptions applicatives.


A chaque passage dans les composants JEE, le message est enrichi en y ajoutant le nom du composant, de l’instance de passage et du temps d’attente. L’affichage final du consommateur affichant en 1er l’ordre d’arrivée

PARAMETRAGE



L’architecture mise en place est un domaine Weblogic avec deux instances en cluster et un domaine mono-instance. Les files de messages de type Queue ont été paramétrées en mode Uniform Distributed Queue sur la plate-forme cluster avec les paramétrages suivants :
                                                                                                               
  • Déclaration d’un Path Service obligatoire pour l’utilisation du UnitOfOrder en cluster ciblé sur l’instance managed1 (service singleton à migrer en cas de problème) (un seul Path Service par cluster).

${DOMAIN_NAME}àServicesàPath Services

  • Paramétrage de la Connexion Factory pour déclarer le UnitOfOrder côté client.

${DOMAIN_NAME}àServicesàMessagingàJMS Modulesà${JMS_MODULE_NAME}à${CONNECTION_FACTORY}àConfigurationàDefault DeliveryàDefault Unit-Of-Order for Producer:System-generated.

  • Désactivation du Server Affinity pour le LoadBalancing afin qu’un même client répartisse la charge sur le cluster.

${DOMAIN_NAME}àServicesàMessagingàJMS Modulesà${JMS_MODULE_NAME}à${CONNECTION_FACTORY}àConfigurationàLoad BalancingàServer Affinity Enabled:OFF.

  • Déclaration du Path Service dans les Queues.

${DOMAIN_NAME}àServicesàMessagingàJMS Modulesà${JMS_MODULE_NAME}à${QUEUE}àConfigurationàGeneralàAdvancedàUnit-Of-Order Messge Routing:Path Service.

  • Définir la politique de retry en cas d’erreur avec un rejeux d’1 fois (pour l’exemple).

${DOMAIN_NAME}àServicesàMessagingàJMS Modulesà${JMS_MODULE_NAME}à${QUEUE}àConfigurationàGeneralàDelivery Failure
àRedelivery Delay Override=1
àRedelivery Limit=1
àExpiration Policy=Redirect
àError Destination=${QUEUE_ERROR}

  • Mise en place setRollBackOnly dans le code MDB pour mettre la transaction en échec sur une erreur applicative et déclencher le traitement d’erreur du MDB (rejeux ou mise en dead letter)

} catch (Exception e) {
     
      if( alreadyRedelivered ) System.out.println("MDB1 MESSAGE On ERROR -> REPUBLISH ONCE AGAIN : " + msgText);
      else System.out.println("MDB1 MESSAGE On ERROR -> REPUBLISH : " + msgText);
      getMessageDrivenContext().setRollbackOnly();  
     
}

  • Sur QueueOut, positionner le Forward Delay à 1 afin que le consommateur puisse récupérer les messages de la seconde instance (consommation non load-balancé)

${DOMAIN_NAME}àServicesàMessagingàJMS Modulesà${JMS_MODULE_NAME}à${QUEUE}àConfigurationàGeneralàForward Delay:1.
                                                        
TESTS



Dans le domaine mono-instance, le Path Service n’est pas obligatoire pour respecter l’ordre. Par contre sans le paramétrage UnitOfOrder ou du Path Service en cluster, les messages arrivent dans le désordre.

${DOMAIN_NAME}àServicesàMessagingàJMS Modulesà${JMS_MODULE_NAME}à${CONNECTION_FACTORY}àConfigurationàDefault DeliveryàDefault Unit-Of-Order for Producer:None.

Affichage du consommateur avec l’ordre d’arriver sur un consommateur mono thread de 20 messages. Nous pouvons voir que l’ordonnancement des messages n’est pas assuré. Les messages manquants ont été mis dans les dead letter queue suite à la génération d’exception aléatoire.

1 : Threads[0]-No[4] : ->MDB1[AdminServer][50]->EJB1[AdminServer][30]->MDB2[AdminServer][30]->EJB2[AdminServer][30]
2 : Threads[0]-No[9] : ->MDB1[AdminServer][50]->EJB1[AdminServer][50]->MDB2[AdminServer][50]->EJB2[AdminServer][50]
3 : Threads[0]-No[14] : ->MDB1[AdminServer][50]->EJB1[AdminServer][30]->MDB2[AdminServer][40]->EJB2[AdminServer][50]
4 : Threads[0]-No[8] : ->MDB1[AdminServer][40]->EJB1[AdminServer][50]->MDB2[AdminServer][40]->EJB2[AdminServer][30]
5 : Threads[0]-No[13] : ->MDB1[AdminServer][30]->EJB1[AdminServer][50]->MDB2[AdminServer][30]->EJB2[AdminServer][40]
6 : Threads[0]-No[7] : ->MDB1[AdminServer][30]->EJB1[AdminServer][30]->MDB2[AdminServer][50]->EJB2[AdminServer][40]
7 : Threads[0]-No[3] : ->MDB1[AdminServer][30]->EJB1[AdminServer][30]->MDB2[AdminServer][50]->EJB2[AdminServer][40]
8 : Threads[0]-No[5] : ->MDB1[AdminServer][50]->EJB1[AdminServer][40]->MDB2[AdminServer][40]->EJB2[AdminServer][30]
9 : Threads[0]-No[15] : ->MDB1[AdminServer][50]->EJB1[AdminServer][30]->MDB2[AdminServer][50]->EJB2[AdminServer][50]
10 : Threads[0]-No[2] : ->MDB1[AdminServer][30]->EJB1[AdminServer][50]->MDB2[AdminServer][30]->EJB2[AdminServer][30]
11 : Threads[0]-No[10] : ->MDB1[AdminServer][30]->EJB1[AdminServer][30]->MDB2[AdminServer][50]->EJB2[AdminServer][30]
12 : Threads[0]-No[0] : ->MDB1[AdminServer][40]->EJB1[AdminServer][40]->MDB2[AdminServer][30]->EJB2[AdminServer][40]
13 : Threads[0]-No[1] : ->MDB1[AdminServer][30]->EJB1[AdminServer][40]->MDB2[AdminServer][50]->EJB2[AdminServer][40]
14 : Threads[0]-No[19] : ->MDB1[AdminServer][40]->EJB1[AdminServer][30]->MDB2[AdminServer][40]->EJB2[AdminServer][40]

Si l’on remet le UnitOfOrder actif, nous constatons sur le résultat l’ordonnancement des messages malgré les messages écartés par des exceptions système ou applicative.

1 : Threads[0]-No[1] : ->MDB1[AdminServer][50]->EJB1[AdminServer][30]->MDB2[AdminServer][30]->EJB2[AdminServer][30]
2 : Threads[0]-No[4] : ->MDB1[AdminServer][40]->EJB1[AdminServer][50]->MDB2[AdminServer][40]->EJB2[AdminServer][30]
3 : Threads[0]-No[12] : ->MDB1[AdminServer][50]->EJB1[AdminServer][30]->MDB2[AdminServer][50]->EJB2[AdminServer][40]
4 : Threads[0]-No[16] : ->MDB1[AdminServer][30]->EJB1[AdminServer][30]->MDB2[AdminServer][30]->EJB2[AdminServer][40]
5 : Threads[0]-No[18] : ->MDB1[AdminServer][30]->EJB1[AdminServer][50]->MDB2[AdminServer][40]->EJB2[AdminServer][30]
<!--[if !supportLists]-->1     <!--[endif]-->: Threads[0]-No[19] : ->MDB1[AdminServer][50]->EJB1[AdminServer][30]->MDB2[AdminServer][30]->EJB2[AdminServer][40]

Par contre quand on rejoue les messages des dead letter queue (via une procédure manuelle d’administration de mouvement de Queue), l’ordonnancement est perdu.

1 : Threads[0]-No[1] : ->MDB1[AdminServer][50]->EJB1[AdminServer][30]->MDB2[AdminServer][30]->EJB2[AdminServer][30]
2 : Threads[0]-No[4] : ->MDB1[AdminServer][40]->EJB1[AdminServer][50]->MDB2[AdminServer][40]->EJB2[AdminServer][30]
3 : Threads[0]-No[12] : ->MDB1[AdminServer][50]->EJB1[AdminServer][30]->MDB2[AdminServer][50]->EJB2[AdminServer][40]
4 : Threads[0]-No[16] : ->MDB1[AdminServer][30]->EJB1[AdminServer][30]->MDB2[AdminServer][30]->EJB2[AdminServer][40]
5 : Threads[0]-No[18] : ->MDB1[AdminServer][30]->EJB1[AdminServer][50]->MDB2[AdminServer][40]->EJB2[AdminServer][30]
6 : Threads[0]-No[19] : ->MDB1[AdminServer][50]->EJB1[AdminServer][30]->MDB2[AdminServer][30]->EJB2[AdminServer][40]
7 : Threads[0]-No[0] : ->MDB1[AdminServer][40]->EJB1[AdminServer][50]->MDB2[AdminServer][50]->EJB2[AdminServer][40]
8 : Threads[0]-No[6] : ->MDB1[AdminServer][50]->EJB1[AdminServer][50]->MDB2[AdminServer][50]->EJB2[AdminServer][50]
9 : Threads[0]-No[8] : ->MDB1[AdminServer][40]->EJB1[AdminServer][30]->MDB2[AdminServer][40]->EJB2[AdminServer][30]
10 : Threads[0]-No[2] : ->MDB1[AdminServer][30]->EJB1[AdminServer][40]->MDB2[AdminServer][50]->EJB2[AdminServer][40]
11 : Threads[0]-No[3] : ->MDB1[AdminServer][40]->EJB1[AdminServer][40]->MDB2[AdminServer][50]->EJB2[AdminServer][50]
12 : Threads[0]-No[7] : ->MDB1[AdminServer][40]->EJB1[AdminServer][50]->MDB2[AdminServer][50]->EJB2[AdminServer][30]
13 : Threads[0]-No[9] : ->MDB1[AdminServer][30]->EJB1[AdminServer][40]->MDB2[AdminServer][40]->EJB2[AdminServer][30]
14 : Threads[0]-No[10] : ->MDB1[AdminServer][50]->EJB1[AdminServer][30]->MDB2[AdminServer][40]->EJB2[AdminServer][50]
15 : Threads[0]-No[15] : ->MDB1[AdminServer][40]->EJB1[AdminServer][40]->MDB2[AdminServer][40]->EJB2[AdminServer][50]
16 : Threads[0]-No[17] : ->MDB1[AdminServer][40]->EJB1[AdminServer][50]->MDB2[AdminServer][50]->EJB2[AdminServer][50]
17 : Threads[0]-No[13] : ->MDB1[AdminServer][30]->EJB1[AdminServer][50]->MDB2[AdminServer][30]->EJB2[AdminServer][30]
18 : Threads[0]-No[11] : ->MDB1[AdminServer][30]->EJB1[AdminServer][50]->MDB2[AdminServer][40]->EJB2[AdminServer][40]
19 : Threads[0]-No[5] : ->MDB1[AdminServer][30]->EJB1[AdminServer][50]->MDB2[AdminServer][50]->EJB2[AdminServer][50]
20 : Threads[0]-No[14] : ->MDB1[AdminServer][50]->EJB1[AdminServer][40]->MDB2[AdminServer][40]->EJB2[AdminServer][50]

L’ordonnancement est donc conservé tant qu’il n’y a pas rupture de transaction ou mise à l’écart du flux. Le rejeux administratif n’utilise pas le UnitOfOrder, ce qui explique le non-respect de l’ordonnancement (rejeux successif, car génération d’erreur lors de la réinjection des messages)

Même constat en cluster.
 1 : Threads[0]-No[0] : ->MDB1[managed1][30]->EJB1[managed1][30]->MDB2[managed2][30]->EJB2[managed2][40]
2 : Threads[0]-No[1] : ->MDB1[managed1][50]->EJB1[managed1][50]->MDB2[managed1][50]->EJB2[managed1][30]
3 : Threads[0]-No[2] : ->MDB1[managed1][50]->EJB1[managed1][30]->MDB2[managed2][50]->EJB2[managed2][40]
4 : Threads[0]-No[3] : ->MDB1[managed1][50]->EJB1[managed1][30]->MDB2[managed1][30]->EJB2[managed1][30]
5 : Threads[0]-No[4] : ->MDB1[managed1][50]->EJB1[managed1][30]->MDB2[managed2][50]->EJB2[managed2][30]
6 : Threads[0]-No[6] : ->MDB1[managed1][30]->EJB1[managed1][40]->MDB2[managed2][30]->EJB2[managed2][30]
7 : Threads[0]-No[7] : ->MDB1[managed1][30]->EJB1[managed1][30]->MDB2[managed1][40]->EJB2[managed1][30]
8 : Threads[0]-No[9] : ->MDB1[managed1][40]->EJB1[managed1][50]->MDB2[managed1][30]->EJB2[managed1][40]
9 : Threads[0]-No[11] : ->MDB1[managed1][30]->EJB1[managed1][30]->MDB2[managed2][50]->EJB2[managed2][30]
10 : Threads[0]-No[13] : ->MDB1[managed1][40]->EJB1[managed1][30]->MDB2[managed2][40]->EJB2[managed2][40]
11 : Threads[0]-No[15] : ->MDB1[managed1][30]->EJB1[managed1][40]->MDB2[managed2][30]->EJB2[managed2][30]
12 : Threads[0]-No[17] : ->MDB1[managed1][40]->EJB1[managed1][50]->MDB2[managed2][40]->EJB2[managed2][40]
13 : Threads[0]-No[18] : ->MDB1[managed1][40]->EJB1[managed1][30]->MDB2[managed1][50]->EJB2[managed1][30]
14 : Threads[0]-No[19] : ->MDB1[managed1][40]->EJB1[managed1][40]->MDB2[managed2][50]->EJB2[managed2][30]
15 : Threads[0]-No[10] : ->MDB1[managed1][30]->EJB1[managed1][30]->MDB2[managed1][50]->EJB2[managed1][50]
16 : Threads[0]-No[8] : ->MDB1[managed1][30]->EJB1[managed1][30]->MDB2[managed2][30]->EJB2[managed2][40]
17 : Threads[0]-No[14] : ->MDB1[managed1][40]->EJB1[managed1][40]->MDB2[managed1][50]->EJB2[managed1][40]
18 : Threads[0]-No[16] : ->MDB1[managed1][40]->EJB1[managed1][50]->MDB2[managed1][50]->EJB2[managed1][40]
19 : Threads[0]-No[5] : ->MDB1[managed1][40]->EJB1[managed1][50]->MDB2[managed1][30]->EJB2[managed1][30]
20 : Threads[0]-No[12] : ->MDB1[managed1][50]->EJB1[managed1][50]->MDB2[managed1][50]->EJB2[managed1][30]

CONCLUSION



La fonctionnalité UnitOfOrder permet d’ordonnancer les messages JMS par producteur avec la contrainte d’avoir une ressource Singleton en cluster (prévoir migration).

Lors d’erreur technique et applicative, les messages mis à l’écart ne sont plus garantis pour l’ordonnancement (retiré de la liste ordonnée reçue par le consommateur). Lors de leurs réinjections, ils sont reçus désynchronisés (après les messages ordonnés), ce qui peut poser un problème si l’ordre initial doit être respecté.

Aucun mécanisme ne peut garantir l’ordonnancement des messages en erreurs, car nécessitant le blocage complet des flux le temps de la réinjection. Il faudra donc prévoir un scénario de rejeux applicatif afin de rollbacker l’ensemble des messages associés au flux et les rejouer.

La fonctionnalité UnitOfOrder permet par contre de garantir les flux hors événement d’erreur et de s’assurer du bon traitement ordonné sur un ensemble de messages d’un client. 

Oracle Advanced Queuing (AQ) est un provider de message implémenté en base. Il offre une interface d’accès JMS (en 11G) permettant à des applications externes d’envoyer et recevoir des messages. Cette intégration dans Weblogic peut se faire via un Bridge (ancien mode) ou plus nativement avec un Foreign Server (11G).

Avant la 11G, Oracle fournissait un accès AQ via des interfaces non standardisées tel qu’Oracle Internet Directory (OID) ou l’ancien Provider JNDI d’OC4J.

L’accès se fait par un DataSource XA ou non, et les ressources JMS sont déclarées dans la DataBase et non plus dans le serveur d’applications. Tous les aspects d’administration et de monitoring sont donc décalés côté DataBase.

Le principal avantage, mais qui fait sa faiblesse et la centralisation du point d’accès (la base). Lorsqu’une instance Weblogic tombe, les autres peuvent continuer de travailler sans impacte pour le flux des messages et sans procédure administrative. Par contre, si la base n’est plus accessible, des erreurs sont produites et il faut rejouer les messages.

 CINEMATIQUE




1 – Le client récupère l’objet Factory d’accès à la base distante via le nom JNDI local. Cette factory permet de récupérer une référence sur le Foreign Server ou l’on a déclaré la DataSource.     
2 – Le client récupère la Destination via la référence locale donnée dans le Foreign Server et la DataSource associé d’accès à la base ou se trouve la destination.
3 – Le producteur pousse le message dans la destination distante (en base).

PARAMETRAGE DATABASE



Chaque queue ou topique JMS AQ est attaché à une table. Ce sont des références logiques associées à la table AQ. Les tables AQ sont créées sur des schémas utilisateur spécifiques qu’il faut déclarer et sur lequel il faut attribuer des droits spécifiques.

User : jmsuser
Password : jmsuser

sqlplus SYS/manager1@ORCL AS SYSDBA @AQ_GRANT.sql

AQ_GRANT.sql
sqlplus SYS/manager1@ORCL AS SYSDBA
grant connect,resource,aq_administrator_role to jmsuser identified by jmsuser;
grant select on sys.DBA_PENDING_TRANSACTIONS to jmsuser;
grant execute on sys.dbms_aqadm to jmsuser;
grant execute on sys.dbms_aq to jmsuser;      
grant execute on sys.dbms_aqin to jmsuser;    
grant execute on sys.dbms_aqjms to jmsuser; 
exec dbms_aqadm.grant_system_privilege(’ENQUEUE_ANY’,’jmsuser’);
exec dbms_aqadm.grant_system_privilege(’DEQUEUE_ANY’,’jmsuser’);    

Pour créer une table AQ, il faut préciser les paramètres suivant :

ü  queue_table                           Le nom de la table AQ (24 caractères).
ü  queue_payload_type         Le type de payload utilisé (utilisé sys.aq$_jms_message pour accepter tout type d’interface de message).
ü  multiple_consumers         Un flag indiquant si la table AQ et de type topic ou non (permet d’accepter plusieurs consommateurs).

Queue Table : myQueueTable
                                                                                                                   
sqlplus jmsuser/jmsuser AS SYSDBA @AQ_CREATE_TABLE_QUEUE.sql
                           
AQ_CREATE_TABLE_QUEUE.sql
execute dbms_aqadm.create_queue_table(queue_table=>'myQueueTable',queue_payload_type=>'sys.aq$_jms_message',multiple_consumers=>false);

Une fois la table AQ crée, on peut créer une ressource AQ JMS queue associée.           Cette ressource est utilisée à la fois pour les queues et topic. Les paramètres à préciser pour créer une queue AQ sont :

ü  queu_name            Le nom de la queue.
ü  queue_table          Le nom de la table AQ créé précédemment

Queue : userQueue

sqlplus jmsuser/jmsuser AS SYSDBA @AQ_CREATE_QUEUE.sql

AQ_CREATE_QUEUE.sql
execute dbms_aqadm.create_queue(queue_name=>'userQueue',queue_table=>'myQueueTable');

PARAMETRAGE WEBLOGIC



DATASOURCE

Il faut ensuite déclarer une DATASOURCE côté Weblogic (utiliser l’utilisateur DATASOURCE déclaré lors de la création de la table AQ) pour accéder à la queue AQ (Les driver JDBC OCI ne sont pas acceptés). Sélectionner le type de driver XA ou non selon le que l’on souhaite utiliser queue XA ou non.

ü Non-XA driver         Transaction locale (via la factory) (ne pas déclarer le paramètre Supports Global Transaction car pas de support d’option LLR, JTS et Emulate Tow-Phase Commit. Dans le cas où l’option est coché, un warning appartait dans les logs de l’instance : Global transactions are supported with XA-based JDBC drivers).
ü XA driver                  Transaction globale ou local

L’option Identity-based connection pools n’est pas supportée.

Data Source : AQ_DataSource

Consoleà${domaine}àServicesàDataSourcesàNewà’AQ_DataSource’

FOREIGN SERVER

Créer un module JMS pour y déclarer un foreign JMS Server (accès à la queue AQ JDBC distante).

Consoleà${domaine}àServicesàJMS ModulesàNewàSystemModule_AQ’

Déclarer dans se module un Foreign Server :

Consoleà${domaine}àServicesàJMS ModulesàNewà SystemModule_AQàNewàForeign ServeràForeignServer-AQ’

Préciser la factory de connexion de type AQ (oracle.jms.AQjmsInitialContextFactory), ainsi que la datasource associé créé précédemment.

Consoleà${domaine}àServicesàJMS ModulesàNewà SystemModule_AQà ForeignServer-AQàConfigurationàGeneral

Ø  JNDI Initial Context Factory=’ oracle.jms.AQjmsInitialContextFactory’
Ø  JNDI Properties=’datasource=AQ_DataSource’

Créer une connexion factory pour  y spécifier le nom JNDI d’accès à la queue AQ dans Weblogic (Local JNDI Name), ainsi que le type de queue créer côté DATABASE (Remote JNDI Name) :

Consoleà${domaine}àServicesàJMS ModulesàNewà SystemModule_AQà ForeignServer-AQàConfigurationàConnection FactoriesàNew

Ø  Name=’ XA_AQ_ForeignConnectionFactory’
Ø  Local JNDI Name=XA_AQ_ForeignConnectionFactory’
Ø  Remote JNDI Name=XAQueueConnectionFactory’

Remote JNDI Name
Remote JNDI Name
JMS Interface
QueueConnectionFactory
javax.jms.QueueConnectionFactory
TopicConnectionFactory
javax.jms.TopicConnectionFactory
ConnectionFactory
javax.jms.ConnectionFactory
XAQueueConnectionFactory
javax.jms.XAQueueConnectionFactory
XATopicConnectionFactory
javax.jms.XATopicConnectionFactory
XAConnectionFactory
javax.jms.XAConnectionFactory

Déclarer l’accès à la queue distante AQ en créant une Destination :

Consoleà${domaine}àServicesàJMS ModulesàNewà SystemModule_AQà ForeignServer-AQàConfigurationàDestinationsàNew

Ø  Name=’ForeignDestination_AQ’
Ø  Local JNDI Name=’ForeignDestination_AQ’
Ø  Remote JNDI Name=’ 'Queues/userQueue'

La partie remote JNDI name spécifie la queue AQ déclaré côté database avec la convention suivante :

Remote JNDI Name
AQ JMS Prefix Value
JMS Interface
Queues/
Javax.jms.Queue
Topics/
javax.jms.Topic

TRANSACTION



CLUSTER



MONITORING



ROBUSTESSE



DEBUGING



Placer le properties JAVA dans la ligne de commande de l’instance qui va supporter le lien à la file AQ. Avec un range de valeur croissant en sévérité de 1 à 6 (6 étant le mode le plus verbeux).

-Doracle.jms.traceLevel=
                                                                                                         
Vous devriez avoir en sortie standard les infos suivantes.

[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] AQjmsConnection:createQueueSession:  Created session
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] AQjmsSession.createQueue IN:  queuename: userQueue
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] AQjmsSession.getQueue IN:   owner: JMSUSER, name: userQueue
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] AQjmsSession.getQueue:  created AQOracleSession
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] AQjmsSession.getQueue:  finish AQOracleSession.getQueue()
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] AQjmsSession.getQueue EXIT:
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] AQjmsSession.createQueue EXIT :
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] [[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default(self-tuning)'] close (OJMS.Session.JFRANCOI-FR.-5b079042:130d13b6e18:-7fff.6) :  ENTRY:waiting for sync
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] AQjmsSession.preClose:  ENTRY
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] AQjmsSession.inGlobalTransRechecked:  entry
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] AQjmsSession.inGlobalTransRechecked:  oracle.jms.useEmulatedXA is on
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] EmulatedXAHandler.inGlobalTrans:  entry, reCheck=true
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] EmulatedXAHandler.checkForGlobalTxn:  entry
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] EmulatedXAHandler.checkForGlobalTxn:  container TM answers NOT IN global txn
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] EmulatedXAHandler.inGlobalTrans:  exit
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] AQjmsSession.inGlobalTransRechecked:  exit
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] AQjmsSession.preClose:  abort txn
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] AQjmsSession.preClose:  EXIT
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] [[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default(self-tuning)'] close (OJMS.Session.JFRANCOI-FR.-5b079042:130d13b6e18:-7fff.6) :  b4 closeWait
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] [[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default(self-tuning)'] close (OJMS.Session.JFRANCOI-FR.-5b079042:130d13b6e18:-7fff.6) :  after closeWait
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] AQjmsSession.closeSessionResources:  entry ...
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] AQjmsSession.closeSessionResources:  Closing general Connection
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] AQjmsGeneralDBConnection.close:  close DB connection
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] [[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default(self-tuning)'] close (OJMS.Session.JFRANCOI-FR.-5b079042:130d13b6e18:-7fff.6) :  EXIT
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] [[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default(self-tuning)'] close (OJMS.Connection.JFRANCOI-FR.-5b079042:130d13b6e18:-7fff.5) :  ENTRY:waiting for sync
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] [[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default(self-tuning)'] close (OJMS.Connection.JFRANCOI-FR.-5b079042:130d13b6e18:-7fff.5) :  b4 markClosed of OJMS.Session.JFRANCOI-FR.-5b079042:130d13b6e18:-7fff.6
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] [[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default(self-tuning)'] close (OJMS.Connection.JFRANCOI-FR.-5b079042:130d13b6e18:-7fff.5) :  after markClosed of OJMS.Session.JFRANCOI-FR.-5b079042:130d13b6e18:-7fff.6
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] AQjmsConnection.preClose:  ENTRY
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] AQjmsConnection.preClose:  EXIT
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] [[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default(self-tuning)'] close (OJMS.Connection.JFRANCOI-FR.-5b079042:130d13b6e18:-7fff.5) :  b4 closeWait
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] [[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default(self-tuning)'] closeWait (OJMS.Connection.JFRANCOI-FR.-5b079042:130d13b6e18:-7fff.5) :  b4 close of OJMS.Session.JFRANCOI-FR.-5b079042:130d13b6e18:-7fff.6
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] [[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default(self-tuning)'] close (OJMS.Session.JFRANCOI-FR.-5b079042:130d13b6e18:-7fff.6) :  ENTRY:waiting for sync
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] [[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default(self-tuning)'] close (OJMS.Session.JFRANCOI-FR.-5b079042:130d13b6e18:-7fff.6) :  ALREADY CLOSED
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] [[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default(self-tuning)'] closeWait (OJMS.Connection.JFRANCOI-FR.-5b079042:130d13b6e18:-7fff.5) :  after close of OJMS.Session.JFRANCOI-FR.-5b079042:130d13b6e18:-7fff.6
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] [[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default(self-tuning)'] close (OJMS.Connection.JFRANCOI-FR.-5b079042:130d13b6e18:-7fff.5) :  after closeWait
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] AQjmsConnection.localClose:  ENTRY
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] AQjmsConnection.closeConnectionResources:  Connection closed
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] [[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default(self-tuning)'] close (OJMS.Connection.JFRANCOI-FR.-5b079042:130d13b6e18:-7fff.5) :  EXIT
[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' [Mon Jun 27 15:14:55 CEST 2011] AQjmsContext.lookup:  lookup return:JMSUSER.userQueue


ADMINISTRATION



ORDERED MESSAGE

CREATE TYPE orders_message_type AS OBJECT (
order_id NUMBER(15),
Product_code VARCHAR2(10),
Customer_id VARCHAR2(10),
order_details VARCHAR2(4000),
price NUMBER(4,2),
region_code VARCHAR2(100));

DBMS_AQADM.CREATE_QUEUE_TABLE (
queue_table => 'aq_admin.orders_qt',
queue_payload_type =>
'aq_admin.orders_message_type'); DBMS_AQADM.CREATE_QUEUE (
queue_name => 'orders_msg_queue',
queue_table => 'aq_admin.orders_msg_qt',
queue_type => DBMS_AQADM.NORMAL_QUEUE,
max_retries => 0,
retry_delay => 0,
retention_time => 1209600,
dependency_tracking => FALSE,
comment => 'Test Object Type Queue',
auto_commit => FALSE);

DBMS_AQADM.START_QUEUE('orders_msg_queue');

SUBSCRIBER

-- need administrator privileges to add
-- subscriber
DBMS_AQADM.ADD_SUBSCRIBER(
Queue_name => ‘aq_admin.orders_msg_queue’,
Subscriber => ‘US_ORDERS’,
Rule => ‘tab.user_data.region_code = ‘`USA’’’);
DBMS_AQADM.ADD_SUBSCRIBER(
Queue_name => ‘aq_admin.orders_msg_queue’,
Subscriber => ‘EUROPE_ORDERS’,
Rule => ‘tab.user_data.region_code =
‘`EUROPE’’’, Transformation =>
‘aq_admin.Dollar_to_Euro’);

MESSAGE TRANSFORMATION 

CREATE FUNCTION
Fn_Dollars_to_Euro(src aq_admin.orders_msg_type
)Returns aq_admin.orders_msg_type AS
Target aq_admin.orders_msg_type;
BEGIN
Target :=
aqadmin.orders_msg_type(src.order_id,
src.product_code, src.customer_id,
src.order_details, src.price*.5,
src.region_code);
END;

DBMS_TRANSFORM.CREATE_TRANSFORMATION(
schema => 'AQ_ADMIN',
name => 'DOLLAR_TO_EURO’,
from_schema => 'AQ_ADMIN',
from_type => 'ORDERS_MSG_TYPE',
to_schema => 'AQ_ADMIN',
to_type => 'ORDERS_MSG_TYPE',
transformation =>
'AQ_ADMIN.Fn_Dollars_to_Euro(source.user_data)');

EXPORT

IMPORT

MOVE

PRODUCE

declare
  -- Local variables here
  queue_options DBMS_AQ.ENQUEUE_OPTIONS_T;
  message_properties DBMS_AQ.MESSAGE_PROPERTIES_T;
  message_id RAW(16);
  agent SYS.AQ$_AGENT := SYS.AQ$_AGENT(' ', null, 0);
  my_message SYS.AQ$_JMS_TEXT_MESSAGE;
begin
  my_message := SYS.AQ$_JMS_TEXT_MESSAGE.construct;
  my_message.set_text('my test message');

  -- Test statements here
  DBMS_AQ.ENQUEUE(
    queue_name => 'my_queue',
    enqueue_options => queue_options,
    message_properties => message_properties,
    payload => my_message,
    msgid => message_id);
  commit;
end; 

CONSUME

declare
  queue_options DBMS_AQ.DEQUEUE_OPTIONS_T;
  message_properties DBMS_AQ.MESSAGE_PROPERTIES_T;
  message_id RAW(2000);
  my_message SYS.AQ$_JMS_TEXT_MESSAGE;
  msg_text varchar2(32767);
begin
  DBMS_AQ.DEQUEUE(
    queue_name => 'my_queue',
    dequeue_options => queue_options,
    message_properties => message_properties,
    payload => my_message,
    msgid => message_id);
    commit;
    my_message.get_text(msg_text);
    DBMS_OUTPUT.put_line('JMS message: '||msg_text);
end;


START

 connect jmsuser / jmsuserpwd;
execute dbms_aqadm.start_queue(queue_name=>'userQueue');

STOP

connect jmsuser / jmsuserpwd
execute dbms_aqadm.stop_queue(queue_name=>'userQueue');

SUSPEND

PURGE

WLST





 startEdit()  
 cd('/')  
 cmo.createJMSSystemResource('SystemModule-0')  
 cd('/SystemResources/SystemModule-0')  
 set('Targets',jarray.array(, ObjectName))  
 cd('/JMSSystemResources/SystemModule-0/JMSResource/SystemModule-0')  
 cmo.createForeignServer('ForeignServer-0')  
 cd('/JMSSystemResources/SystemModule-0/JMSResource/SystemModule-0/ForeignServers/ForeignServer-0')  
 cmo.setDefaultTargetingEnabled(true)  
 cmo.setConnectionURL('some.url')  
 cmo.setInitialContextFactory('SomeInitialContextFactory')  
 cmo.createForeignDestination('ForeignDestination-0')  
 cd('/JMSSystemResources/SystemModule-0/JMSResource/SystemModule-0/ForeignServers/ForeignServer-0/ForeignDestinations/ForeignDestination-0')  
 cmo.setLocalJNDIName('localQ')  
 cmo.setRemoteJNDIName('remoteQ')  
 activate()  

STANDALONE CLIENT



Ajouter l’option dans le scripte de démarrage de l’instance Weblogic afin de pouvoir se connecter sur l’arbre JNDI de Weblogic sans mot de passé à partir de l’extérieure.

-Dweblogic.jdbc.remoteEnabled=true

Lorsqu’un client requête la ressource du Foreign server, il faut lui préciser toutes les informations d’accès à la Database en plus de la DataSource (peut être un problème). Si on précise également la DataSource, c’est celle-ci qui sera utilisée.



AUTEUR

Ma photo
Carrières Sur Sein, Yvelines, France
Consultant Oracle (Ancien consultant BEA depuis 2001), je m’occupe des expertises sur les produits Oracle : SOCLE (Weblogic, Coherence, JRockit) SOA (Service Bus, SOA Suite, BPM)
MON CV

LABEL 3D

Blogumulus by Roy Tanck and Amanda Fazani

LABEL CLOUD

MAP

Locations of visitors to this page

AUTRES BLOG

LIVRES

MEMBRES