Using liberty 18.0.0.1 and a MDB like this :
#MessageDriven(
activationConfig = {
#ActivationConfigProperty(propertyName = "destination", propertyValue = "distributedACLCache"),
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
#ActivationConfigProperty(propertyName = "subscriptionDurability", propertyValue = "Durable"),
#ActivationConfigProperty(propertyName = "subscriptionName", propertyValue = "distributedACLCache"),
#ActivationConfigProperty(propertyName = "clientId", propertyValue = "cli-id-01")
In this scenario the clientId is staic, but if I want to deploy this MDB in several instances with different clientId's it seems to not be possible ?
Is there a way to inject a clientId from a environment variable or properties from the current runtime ?
/bwa
You can configure all those values using xml (ejb-jar.xml), this way you can change configuration per deployment. I think you can also mix annotation and xml configuration of MDBs.
See https://docs.oracle.com/cd/E24329_01/web.1211/e24977/annotations.htm#WLMDB10006
Related
I have an application in springboot which is using jms to receive messages from ibm mq synchronously i.e., using .receive() method which is running fine, Now, I am implementing another process to run in background to receive async messages which is older than 2 minutes, from same queue which uses #Async and Message driven beans(onMessage()) .
My method implementation for mdb is as below:
#Service
#Slf4j
#MessageDriven(mappedName = "REPL.AI", activationConfig = {
#ActivationConfigProperty(propertyName = "connectionFactoryLookup", propertyValue = "jms/queueConnectionFactory"),
#ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
#ActivationConfigProperty(propertyName = "port", propertyValue = "1414")})
public class MessageBean implements MessageListener {
#Autowired
private AsyncMessageReceiver asyncMessageReceiver;
#Override
#Async("AsyncExecutor")
public void onMessage(Message message) {
log.info("ONMESSAGE-START");
TextMessage msg = null;
try {
if (message instanceof TextMessage) {
msg = (TextMessage) message;
log.info("received an async message");
asyncMessageReceiver.processIntoText(msg); //calling other method for further processing
}
} catch (Exception e) {
log.error("Exception occurs in onMessage(): " + e);
}
log.info("ONMESSAGE-END");
}
}
Also I have created a listener port '1414' in WAS server console to bind the mdb to port.
All configuration is already provided.
problem is, mdb is not receiving any messages from the queue , nor it is throwing any error.
I can see in logs
MDB Listener 1414 started successfully for JMSDestination jms/ReplQueue.
after this I dont see any exception and not any incoming messages too,messages have been sent through sender.
any pointers for this?
I am trying to understand concepts related to MDB, MQ, JMS. I did research on SO before asking this question.
Is this possible scenario:
MDB deployed on Application Server, say on JBOSS (on physical Server-A).
MQ (say ApacheMQ) on a difference physical server-B.
So can the MDB deployed in physical server-A get messages from physical server-B?
If this is possible, then does MDB use JMS API's?
I have heard Jboss has MQ, which i presume MQ withing Jboss application server; however i want MDB in a different server and MQ server on a different physical server.
Appreciate your help in understanding this.
There are 4 real parts to this.
1) Your application. An MDB is an application which implements the J2EE Message Driven Bean API, which in its simplest form means it has an onMessage() function which will be invoked by the application server when messages arrive.
2) The J2EE application server, JBOSS is an example. This receives messages from the MQ client, and forwards them to the MDB.
3) The MQ client. This is the code written by the MQ provider (IBM/Apache/etc) which implements the JCA RA and JMS parts of J2EE. Applications can interact with this client via JMS to put and get messages, though when you're interacting as an MDB you'll be driven via your onMessage() method. This client hands messages to the application server, which drives the applications.
4) The MQ server. IBM MQ calls this a 'queue manager', and this can exist anywhere. The client from #3 will connect to the queue manager over the network.
#1, #2, and #3 need to be on the same physical machine (and run in the same JVM). #4 can be anywhere as its accessed over the network.
To address your points:
So can the MDB deployed in physical server-A get messages from physical server-B?
Yes
If this is possible, then does MDB use JMS API's?
The MDB is driven by the application server using the J2EE API, JMS is just a part of this.
By the way, 'MQ' is the name of product rather than a concept. The generic name is 'Messaging Provider'. IBM MQ and ApacheMQ are both messaging providers.
An example of an MDB that is activated by a remote MQ instance:
/**
* WebSphereMQ.java
*
* Created on Sep 21, 2012, 9:11:29 AM
*
* To the extent possible under law, Red Hat, Inc. has dedicated all copyright to this
* software to the public domain worldwide, pursuant to the CC0 Public Domain Dedication. This
* software is distributed without any warranty.
*
* See <http://creativecommons.org/publicdomain/zero/1.0/>.
*
*/
package org.jboss.sample.mq;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.ejb.MessageDriven;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.jboss.ejb3.annotation.Pool;
import org.jboss.ejb3.annotation.ResourceAdapter;
import org.jboss.logging.Logger;
/**
*
*/
#MessageDriven(name = "WebSphereMQ", activationConfig = {
#ActivationConfigProperty(propertyName = "maxPoolDepth", propertyValue="100"),
#ActivationConfigProperty(propertyName = "maxMessages", propertyValue="1"),
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
#ActivationConfigProperty(propertyName = "hostName", propertyValue = "10.0.0.150"),
#ActivationConfigProperty(propertyName = "port", propertyValue = "1414"),
#ActivationConfigProperty(propertyName = "userName", propertyValue = "redhat"),
#ActivationConfigProperty(propertyName = "password", propertyValue = "redhat"),
#ActivationConfigProperty(propertyName = "channel", propertyValue = "SYSTEM.DEF.SVRCONN"),
#ActivationConfigProperty(propertyName = "queueManager", propertyValue = "REDHAT.QUEUE.MANAGER"),
#ActivationConfigProperty(propertyName = "useJNDI", propertyValue = "true"),
#ActivationConfigProperty(propertyName = "destination", propertyValue = "jms/queue/gssQueue"),
#ActivationConfigProperty(propertyName = "transportType", propertyValue = "CLIENT") })
#Pool(value="MQpool")
#ResourceAdapter(value="wmq.jmsra.7.5.0.4.rar")
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public class WebSphereMQ implements MessageListener {
private static final Logger logger = Logger.getLogger(WebSphereMQ.class);
/*
* (non-Javadoc)
*
* #see javax.jms.MessageListener#onMessage(javax.jms.Message)
*/
public void onMessage(Message message) {
try {
logger.info("Received message: " + message.getJMSMessageID() + " : " + ((TextMessage)message).getText());
try {
Thread.sleep(10000);
} catch(Exception e) {
logger.info("interrupted");
}
}
}
For people are using Glassfish4/Payara-Server, this is the equivalent for #Doug Grove #ResourceAdapter :
#MessageDriven(
name = "foo",
activationConfig = {
#ActivationConfigProperty(propertyName = "resourceAdapter", propertyValue = "activemq-rar-x-x-x"),
:
:
when activemq-rar-x-x-x is the ActiveMQ resource adapter deployed at AS.
Regards.
I have MQ as an external JMS server on my Weblogic server. The thing is that I need to rollback the message and retry until backout threshold is reached. Then I need to move the message to backout queue.
The MessageDrivenContext.setRollbackOnly() method takes care of that just fine. The problem, however, is with the message on the backout queue - it is uncommited.
Moreover, the messages are being taken from backout queue and processed again as soon as new message appears on the main queue.
This suggest me that there is something teribly wrong with my approach. I cannot, however, change the fact, that I have to retry the onMessage() with the same message a couple of times and send it to backout queue is backout threshold was reached.
#MessageDriven( name="MQListener", mappedName = "jms.mq.SOME.QUEUE.NAME",
activationConfig =
{
#ActivationConfigProperty(propertyName = "destinationType",propertyValue = "javax.jms.Queue"),
#ActivationConfigProperty(propertyName = "destination", propertyValue = "jms.mq.SOME.QUEUE.NAME"),
#ActivationConfigProperty(propertyName = "connectionFactoryJndiName", propertyValue = "jms.mq.MQ"),
#ActivationConfigProperty(propertyName = "useJNDI", propertyValue = "true")
})
public class MQListener implements MessageListener {
#Resource
private MessageDrivenContext context;
#Override
public void onMessage(Message message) {
String messageContent="";
try {
messageId = message.getJMSMessageID();
if (message != null) {
messageContent = ((TextMessage)message).getText();
if(!doSomething(messageContent)){
// doSomething fails, I need to rollback the message and try again:
context.setRollbackOnly();
}
}
} catch (Exception e) {
throw new RuntimeException();
}
}
private boolean doSomething(String messageContent){
// ...
}
}
I am a tyro in EJB. But from what I can see in your code snippet, I think you are missing initialization of MessageDrivenContext. I think you will have to do either
context = getMessageDrivenContext();
context.setRollbackOnly();
or
getMessageDrivenContext().setRollbackOnly();
Assume Active MQ is the broker and there are 6 servers where JMS listeners are attached.
When a Topic is send then all the six servers will consume the messages.
Now i want a particular server only consume the message instead of all six using selector and it should be filtered before sending the JMS.
How to define a selector in JMS so that the topic will be consumed by a particular server instead of all.
You need JMS message selectors. There is no need to filter before sending, but upon receiving. An example where only server with id "serv_5" receives the message:
Producer:
...
Message message = session.createMessage();
message.setObjectProperty("server_id", "serv_5");
producer.send(message);
Consumer (MDB):
#MessageDriven(mappedName="jms/YourQueue", activationConfig = {
#ActivationConfigProperty(propertyName = "acknowledgeMode",
propertyValue = "Auto-acknowledge"),
#ActivationConfigProperty(propertyName = "destinationType",
propertyValue = "javax.jms.Queue"),
#ActivationConfigProperty(
propertyName="messageSelector",
propertyValue="server_id = 'serv_5'")
})
public class YourMessageBean implements MessageListener { ..
As I am using WAS7.0 for Message Driven Bean and i have configured the MDB through annotation. I am not configuring any thing in ibm-ejb-jar-bnd.xml and ejb-jar.xml xml and I am giving all configuration in #MessageDriven configuration but My MDB is not listening the message from Queue Please advise while using #MessageDrive annotation do i need to configured MDB in XML also. I am using below annotation.
#MessageDriven(activationConfig = {
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
#ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
#ActivationConfigProperty(propertyName = "useJNDI", propertyValue = "true"),
#ActivationConfigProperty(propertyName = "connectionFactoryJndiName",propertyValue = "jms/TestChangeSubscriptionConnectionFactory"),
#ActivationConfigProperty(propertyName = "destinationJndiName",propertyValue = "jms/ETestChangeSubscriptionQueue")
}, mappedName = "jms/TestChangeSubscriptionQueue")
#TransactionManagement(TransactionManagementType.BEAN)