Je lance un projet Java EE qui doit être fortement évolutif. Jusqu'à présent, le concept était :
- plusieurs "Message Driven Beans", responsables de différentes parties de l'architecture
- un Session Bean est injecté dans chaque MDB pour gérer la logique métier.
- un couple d'Entity Beans, fournissant un accès à la couche de persistance
- communication entre les différentes parties de l'architecture via le concept de demande/réponse par le biais de messages JMS :
- La MDB reçoit un message contenant une demande d'activité
- utilise son bean de session pour exécuter la logique commerciale nécessaire.
- renvoie l'objet de la réponse dans le msg au demandeur original
L'idée était qu'en découplant les parties de l'architecture les unes des autres via le bus de messages, il n'y a aucune limite à l'évolutivité. Il suffit de lancer d'autres composants - tant qu'ils sont connectés au même bus, nous pouvons croître et croître encore.
Malheureusement, nous avons de gros problèmes avec le concept de demande-réponse. Transaction Mgmt semble être dans notre chemin beaucoup. Il semble que les beans de session ne sont pas censés consommer des messages ?!
Lecture http://blogs.oracle.com/fkieviet/entry/request_reply_from_an_ejb y http://forums.sun.com/message.jspa?messageID=10338789 j'ai l'impression que les gens recommandent contre le concept de demande/réponse pour les EJB.
Si c'est le cas, comment faire vous communiquez entre vos EJBs ? (N'oubliez pas que c'est l'évolutivité qui m'intéresse).
Détails de mon installation actuelle :
- MDB 1 'TestController', utilise (local) SLSB 1 'TestService' pour la logique d'entreprise.
- TestController.onMessage() fait en sorte que TestService envoie un message à la file d'attente XYZ et demande une réponse.
- TestService utilise les transactions gérées par Bean
- TestService établit une connexion et une session avec le broker JMS via une usine de connexion commune lors de l'initialisation (@PostConstruct).
- TestService commet la transaction après l'envoi, puis commence une autre transaction et attend la réponse pendant 10 secondes.
- Le message est transmis à la MDB 2 "LocationController", qui utilise le SLSB 2 "LocationService" (local) pour la logique commerciale.
- LocationController.onMessage() permet au LocationService d'envoyer un message. arrière à la file d'attente JMSReplyTo demandée
- Même concept BMT, même concept @PostConstruct
- utilisent tous la même fabrique de connexion pour accéder au courtier
Problème : Le premier message est envoyé (par SLSB 1) et reçu (par MDB 2) sans problème. L'envoi du message de retour (par SLSB 2) est également correct. Cependant, SLSB 1 ne reçoit jamais rien - ça s'arrête.
J'ai essayé sans le messageSelector, aucun changement, toujours pas de réception de message.
N'est-il pas possible de consommer un message par un bean de session ?
SLSB 1 - TestService.java
@Resource(name = "jms/mvs.MVSControllerFactory")
private javax.jms.ConnectionFactory connectionFactory;
@PostConstruct
public void initialize() {
try {
jmsConnection = connectionFactory.createConnection();
session = jmsConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
System.out.println("Connection to JMS Provider established");
} catch (Exception e) { }
}
public Serializable sendMessageWithResponse(Destination reqDest, Destination respDest, Serializable request) {
Serializable response = null;
try {
utx.begin();
Random rand = new Random();
String correlationId = rand.nextLong() + "-" + (new Date()).getTime();
// prepare the sending message object
ObjectMessage reqMsg = session.createObjectMessage();
reqMsg.setObject(request);
reqMsg.setJMSReplyTo(respDest);
reqMsg.setJMSCorrelationID(correlationId);
// prepare the publishers and subscribers
MessageProducer producer = session.createProducer(reqDest);
// send the message
producer.send(reqMsg);
System.out.println("Request Message has been sent!");
utx.commit();
// need to start second transaction, otherwise the first msg never gets sent
utx.begin();
MessageConsumer consumer = session.createConsumer(respDest, "JMSCorrelationID = '" + correlationId + "'");
jmsConnection.start();
ObjectMessage respMsg = (ObjectMessage) consumer.receive(10000L);
utx.commit();
if (respMsg != null) {
response = respMsg.getObject();
System.out.println("Response Message has been received!");
} else {
// timeout waiting for response
System.out.println("Timeout waiting for response!");
}
} catch (Exception e) { }
return response;
}
SLSB 2 - LocationService.Java (seulement la méthode de réponse, le reste est identique au précédent)
public boolean reply(Message origMsg, Serializable o) {
boolean rc = false;
try {
// check if we have necessary correlationID and replyTo destination
if (!origMsg.getJMSCorrelationID().equals("") && (origMsg.getJMSReplyTo() != null)) {
// prepare the payload
utx.begin();
ObjectMessage msg = session.createObjectMessage();
msg.setObject(o);
// make it a response
msg.setJMSCorrelationID(origMsg.getJMSCorrelationID());
Destination dest = origMsg.getJMSReplyTo();
// send it
MessageProducer producer = session.createProducer(dest);
producer.send(msg);
producer.close();
System.out.println("Reply Message has been sent");
utx.commit();
rc = true;
}
} catch (Exception e) {}
return rc;
}
sun-resources.xml
<admin-object-resource enabled="true" jndi-name="jms/mvs.LocationControllerRequest" res-type="javax.jms.Queue" res-adapter="jmsra">
<property name="Name" value="mvs.LocationControllerRequestQueue"/>
</admin-object-resource>
<admin-object-resource enabled="true" jndi-name="jms/mvs.LocationControllerResponse" res-type="javax.jms.Queue" res-adapter="jmsra">
<property name="Name" value="mvs.LocationControllerResponseQueue"/>
</admin-object-resource>
<connector-connection-pool name="jms/mvs.MVSControllerFactoryPool" connection-definition-name="javax.jms.QueueConnectionFactory" resource-adapter-name="jmsra"/>
<connector-resource enabled="true" jndi-name="jms/mvs.MVSControllerFactory" pool-name="jms/mvs.MVSControllerFactoryPool" />