Imho the following code should create a new message, which is immedeatelly fetched again. But the output is zero. Why?
public static void main(String[] args) throws JMSException, NamingException {
Properties props = new Properties();
props.setProperty(Context.INITIAL_CONTEXT_FACTORY,"org.apache.activemq.jndi.ActiveMQInitialContextFactory");
props.setProperty(Context.PROVIDER_URL,"tcp://localhost:61616");
props.setProperty("topic.MyTopic", "FOO.BAR");
// create a new intial context, which loads from jndi.properties file
Context ctx = new InitialContext(props);
// lookup the connection factory
TopicConnectionFactory factory = (TopicConnectionFactory) ctx.lookup("ConnectionFactory");
// create a new TopicConnection for pub/sub messaging
TopicConnection conn = factory.createTopicConnection();
// lookup an existing topic
Topic mytopic = (Topic) ctx.lookup("MyTopic");
// create a new TopicSession for the client
TopicSession session = conn.createTopicSession(false, TopicSession.AUTO_ACKNOWLEDGE);
// create a new publisher to produce messages
TopicPublisher publisher = session.createPublisher(mytopic);
// create a new subscriber to receive messages
TopicSubscriber subscriber = session.createSubscriber(mytopic);
subscriber.setMessageListener(new MessageListener() {
public void onMessage(Message msg) {
try {
TextMessage textMessage = (TextMessage) msg;
String txt = textMessage.getText();
System.out.println(txt);
} catch (JMSException e) {
e.printStackTrace();
}
}
});
TextMessage message = session.createTextMessage();
message.setText("Kebap: Pommes");
publisher.publish(message);
}
Okay, I found the problem. The example from the ActiveMQ website isn't that good ... but they also provide an answer for my problem.
http://activemq.apache.org/i-am-not-receiving-any-messages-what-is-wrong.html
Related
I'm trying to move away from Weblogic to JBoss, and as such I'm trying to implement the things I was able to implement on Weblogic on JBoss.
One of those things is our notification system where the client sends a request to an MDB and the MDB sends a reply back to the client.
This was a breeze in Weblogic, but on Jboss, nothing seems to work. I keep getting this error:
javax.jms.InvalidDestinationException: Not an ActiveMQ Artemis Destination:ActiveMQTemporaryQueue[da00b1a2-114d-4be9-930d-926fc20c2fce]
Is there something I need to configure on my Jboss?
EDIT
I realise that I probably didn't phrase the question very well.
What happens is this: I have a client and a server MDB (message driven bean). The client sends a message to a queue and waits for a response from the server. The server picks the message from the queue and sends a response to the client, which the client picks up and displays.
On Jboss, messages from the client go smoothly, and the server picks it up, but as soon as the server MDB tries to send a response to the client, that error is thrown.
My client code (excerpt):
int TIME_OUT = 60000;
//prepare factory
Properties prop = new Properties();
prop.setProperty("java.naming.factory.initial", "org.jboss.naming.remote.client.InitialContextFactory");
prop.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces");
prop.setProperty("java.naming.provider.url", "http-remoting://remotehost:8080");
prop.setProperty("java.naming.security.principal", "guest-user")
prop.setProperty("java.naming.security.credentials", "Password#1")
String queueConnectionFactory = "jms/RemoteConnectionFactory";
Context context = new InitialContext(prop);
QueueConnectionFactory qconFactory = (QueueConnectionFactory) context.lookup(queueConnectionFactory);
//prepare queue and sessions
QueueConnection qcon = qconFactory.createQueueConnection(prop.getProperty("java.naming.security.principal"), prop.getProperty("java.naming.security.credentials"));
QueueSession qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue = (Queue) context.lookup("jms/TestQueue2");
//create message
NotificationWrapper wrapper = //object initialised with something
ObjectMessage om = qsession.createObjectMessage(wrapper);//NotificationWrapper wrapper
//create producer
MessageProducer producer = qsession.createProducer(queue);
//create temporary queue
TemporaryQueue tempqueue = qsession.createTemporaryQueue();
om.setJMSReplyTo(tempqueue);
//start connection
qcon.start();
//send message and wait for response
producer.send(om);
MessageConsumer consumer = qsession.createConsumer(tempqueue);
Message callback = consumer.receive(TIME_OUT);
//print message from server
if (callback != null) {
System.out.println("Response received from server. Print here...");
//message from server
} else {
System.out.println("No Response received from server. Problems!!!");
}
//close all connections
if (consumer != null) {
consumer.close();
}
if (producer != null) {
producer.close();
}
if (qsession != null) {
qsession.close();
}
if (qcon != null) {
qcon.close();
}
My Server code (excerpt):
#MessageDriven(mappedName = "TestQueue2", activationConfig = {
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
#ActivationConfigProperty(propertyName = "destination", propertyValue = "jms/TestQueue2"),
#ActivationConfigProperty(propertyName = "maxSession", propertyValue = "10")
})
public class ServerSide implements MessageListener {
private static final QueueConfigProperties queueConfigProp = QueueConfigProperties.getInstance();
private Context context;
private QueueConnectionFactory qconFactory;
private QueueConnection qcon;
private QueueSession qsession;
private MessageProducer producer;
public ServerSide() {
try {
initialiseQueueFactory("jms/RemoteConnectionFactory");
//initialiseQueueFactory("jms/GreenpoleConnectionFactory");
prepareResponseQueue();
Properties prop = new Properties();
prop.setProperty("java.naming.factory.initial", "org.jboss.naming.remote.client.InitialContextFactory");
prop.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces");
prop.setProperty("java.naming.provider.url", "http-remoting://remotehost:8080");
prop.setProperty("java.naming.security.principal", "guest-user")
prop.setProperty("java.naming.security.credentials", "Password#1")
String queueConnectionFactory = "jms/RemoteConnectionFactory";
Context context = new InitialContext(prop);
QueueConnectionFactory qconFactory = (QueueConnectionFactory) context.lookup(queueConnectionFactory);
qcon = qconFactory.createQueueConnection(queueConfigProp.getProperty("java.naming.security.principal"), queueConfigProp.getProperty("java.naming.security.credentials"));
qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
} catch (NamingException | ConfigNotFoundException | IOException | JMSException ex) {
//error log
}
}
#Override
public void onMessage(Message message) {
try {
if (((ObjectMessage) message).getObject() instanceof NotificationWrapper) {
//send response
if (message.getJMSReplyTo() != null) {
logger.info("sending response");
respondToSenderPositive(message);
Response resp = new Response();
resp.setRetn(0);
resp.setDesc("Notification submitted to queue.");
producer = qsession.createProducer(message.getJMSReplyTo());
producer.send(qsession.createObjectMessage(resp));
producer.send(msg_to_send);
}
} else {
//some message printed here
}
} catch (JMSException ex) {
//error logs
} catch (Exception ex) {
//error logs
}
}
}
The issue was to do with the configuration of the destination queue which is a remote queue: the client and server are both running on different JVMs. Remote Queues on Jboss are named differently from those on Weblogic.
The name of a remote queue should be something like this: java:jboss/exported/jms/TestQueue2
Refer to the JBoss documentation for a more detailed explanation on queues: https://access.redhat.com/documentation/en-us/red_hat_jboss_enterprise_application_platform/7.0/html-single/configuring_messaging/index
Currently i am using Websphere MQ V8.
public static void main(String[] args) throws JMSException {
// TODO Auto-generated method stub
try{
MQEnvironment.disableTracing();
MQQueueConnectionFactory cf = new MQQueueConnectionFactory();
cf.setStringProperty(WMQConstants.WMQ_HOST_NAME, "localhost");
cf.setStringProperty(WMQConstants.WMQ_PORT, "1414");
cf.setStringProperty(WMQConstants.WMQ_CHANNEL, "TEST_SVR_CONN");
cf.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, "DEVTESTQUEUE");
//cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_DIRECT_HTTP);
//cf.setTransportType(WMQConstants.WMQ_CM_BINDINGS);
//set MQServer =
//HelloWorldConsumer.HelloWorldProducer();
MQQueueConnection connection = (MQQueueConnection) cf.createQueueConnection();
MQSession session = (MQSession) connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
MQQueue queue = (MQQueue) session.createQueue("REQUEST");
//queue.setMessageBodyStyle(WMQConstants.WMQ_MESSAGE_BODY_MQ);
queue.setTargetClient(WMQConstants.WMQ_TARGET_DEST_MQ);
queue.setProperty("PROPCTL", "ALL");
((com.ibm.mq.jms.MQQueue)queue).setIntProperty(WMQConstants.WMQ_TARGET_CLIENT, WMQConstants.WMQ_TARGET_DEST_MQ);
connection.start();
MessageConsumer consumer = session.createConsumer(queue);
consumer.setMessageListener(new HelloWorldConsumer());
session.close();
connection.close();
System.out.println("------END------");
}catch(JMSException je){
je.printStackTrace();
}catch(Exception e){
e.printStackTrace();
}
}
i have tried by setting TARGCLIENT property to WMQ_TARGET_DEST_MQ and PROPCTL as "NONE/FORCE". Still iam getting the header in the message as
RFH ? ????MQSTR ? 25504.txt ?UPLOAD|1||
I am facing an issue with JMS Connection stop() and start(). A simple java program illustrating the same is:
public class Test {
static Connection producerConn = null;
static BufferedWriter consumerLog = null;
static BufferedWriter producerLog = null;
public static final void main(String[] args) throws Exception {
ConnectionFactory cf = new ActiveMQConnectionFactory("failover:(tcp://localhost:61616)");
producerConn = cf.createConnection();
producerLog = new BufferedWriter(new FileWriter("produced.log"));
consumerLog = new BufferedWriter(new FileWriter("consumed.log"));
new Thread(new Runnable() {
public void run() {
try {
producerConn.start();
Session session = producerConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue("SampleQ1");
MessageProducer producer = session.createProducer(queue);
Random random = new Random();
byte[] messageBytes = new byte[1024];
for (int i = 0; i < 100; i++) {
random.nextBytes(messageBytes);
Message message = session.createObjectMessage(messageBytes);
producer.send(message);
Thread.currentThread().sleep(10);
producerLog.write(message.getJMSMessageID());
producerLog.newLine();
producerLog.flush();
}
System.out.println("Produced 100000 messages...");
producerLog.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
}).start();
System.out.println("Started producer...");
new Thread(new Runnable() {
public void run() {
int count = 0;
try {
producerConn.start();
Session session = producerConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue("SampleQ1");
MessageConsumer consumer = session.createConsumer(queue);
consumer.setMessageListener(new Test().new MyListener());
}
catch (Exception e) {
e.printStackTrace();
}
}
}).start();
System.out.println("Started consumer...");
}
private class MyListener implements MessageListener{
private int count = 0;
public void onMessage(Message message) {
try {
message.acknowledge();
System.out.println("count is " +count++);
if(count == 5){
producerConn.stop();
System.out.println("Sleeping Now for 5 seconds. . ." +System.currentTimeMillis());
Thread.currentThread().sleep(5000);
producerConn.start();
}
System.out.println("Waking up . . ." +System.currentTimeMillis());
consumerLog.write(message.getJMSMessageID());
consumerLog.newLine();
consumerLog.flush();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
}
My idea is to simulate the connection stop() and start(). Therefore, in the consumer thread after calling stop(), I have placed a sleep of 5 seconds. However, in the mean time the producer thread continues its job of sending message to the queue.
I expected the test to just consume only the message delivered before the consumer calls stop() and after it calls start() again after waking up from the sleep. But what's happening here is, when consumer wakes up it reads all the messages from the server even those that were sent to the queue when consumer's message reception was stopped.
Am I doing anything wrong here ?
There is nothing wrong there, it's the correct behavior. In asynchronous messaging producer and consumer are loosely decoupled. A producer does not care whether a consumer is consuming messages or not. It keeps putting messages to a queue while the consumer may be down, or stopped consuming messages or actively consuming messages.
The connection.stop() method has no effect on producer. It affects only consumer, stop() method pauses the delivery of messages from JMS provider to a consumer while start() method starts/resumes message delivery.
Hope this helped.
I need to be able to receive notification when a ActiveMQ client consumes a MQTT message.
activemq.xml
<destinationPolicy>
<policyMap>
<policyEntries>
<policyEntry topic=">" advisoryForConsumed="true" />
</policyEntries>
</policyMap>
</destinationPolicy>
In the below code, I get MQTT messages on myTopic fine. I do not get advisory messages in processAdvisoryMessage / processAdvisoryBytesMessage.
#Component
public class MqttMessageListener {
#JmsListener(destination = "mytopic")
public void processMessage(BytesMessage message) {
}
#JmsListener(destination = "ActiveMQ.Advisory.MessageConsumed.Topic.>")
public void processAdvisoryMessage(Message message) {
System.out.println("processAdvisoryMessage Got a message");
}
#JmsListener(destination = "ActiveMQ.Advisory.MessageConsumed.Topic.>")
public void processAdvisoryBytesMessage(BytesMessage message) {
System.out.println("processAdvisoryBytesMessageGot a message");
}
}
What am I doing wrong?
I have also attempted doing this with a ActiveMQ BrokerFilter:
public class AMQMessageBrokerFilter extends GenericBrokerFilter {
#Override
public void acknowledge(ConsumerBrokerExchange consumerExchange, MessageAck ack) throws Exception {
super.acknowledge(consumerExchange, ack);
}
#Override
public void postProcessDispatch(MessageDispatch messageDispatch) {
Message message = messageDispatch.getMessage();
}
#Override
public void messageDelivered(ConnectionContext context, MessageReference messageReference) {
log.debug("messageDelivered called.");
super.messageDelivered(context, messageReference);
}
#Override
public void messageConsumed(ConnectionContext context, MessageReference messageReference) {
log.debug("messageConsumed called.");
super.messageConsumed(context, messageReference);
}
In this second scenario I was unable to both have the message and a contect with which to send the consumed notification. acknowledge/messageDelivered/messageConsumed all have a connection context but only postProcessDispatch has the message which I need part of it (payload is JSON) in order to send my outgoing message. I could be eager and use send which has both but it is safer to wait until at least it was acknowledged.
I have tried:
#Override
public void postProcessDispatch(MessageDispatch messageDispatch) {
super.postProcessDispatch(messageDispatch);
String topic = messageDispatch.getDestination().getPhysicalName();
if( topic == null || topic.equals("delivered") )
return;
try {
ActiveMQTopic responseTopic = new ActiveMQTopic("delivered");
ActiveMQTextMessage responseMsg = new ActiveMQTextMessage();
responseMsg.setPersistent(false);
responseMsg.setResponseRequired(false);
responseMsg.setProducerId(new ProducerId());
responseMsg.setText("Delivered msg: "+msg);
responseMsg.setDestination(responseTopic);
String messageKey = ":"+rand.nextLong();
MessageId msgId = new MessageId(messageKey);
responseMsg.setMessageId(msgId);
ProducerBrokerExchange producerExchange=new ProducerBrokerExchange();
ConnectionContext context = getAdminConnectionContext();
producerExchange.setConnectionContext(context);
producerExchange.setMutable(true);
producerExchange.setProducerState(new ProducerState(new ProducerInfo()));
next.send(producerExchange, responseMsg);
}
catch (Exception e) {
log.debug("Exception: "+e);
}
However the above seems to lead to unstable server. I'm thinking this is related to using the getAdminConnectionContext which seems wrong.
My factory was setting setPubSubDomain to false by default. This disables connections for advisory messages for topics. I set it to true and things started working. Note that queues will not work with this set. To get around that I created two factories and named their beans.
#Bean(name="main")
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(ConnectionFactory connectionFactory) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
// factory.setDestinationResolver(destinationResolver);
// factory.setPubSubDomain(true);
factory.setConcurrency("3-10");
return factory;
}
I want to write generic code for sending message on any jms server. so for that i thought if i have jndi.properties file then we can place server configuration in this file and we can access this file through the code but i am able to do this only for 'ActiveMQ Server'. Now i am facing problems to send the message on any other server like glassfish server or jboss server. can somebody help me to do this task.
Here is my code :
public class Producer
{
public Producer() throws JMSException, NamingException,IOException
{
InputStream is = getClass().getResourceAsStream("my.jndi.properties");
Properties jndiParamaters = new Properties();
jndiParamaters.load(is);
Context jndi = new InitialContext(jndiParamaters);
ConnectionFactory conFactory = (ConnectionFactory) jndi.lookup("connectionFactory");
Connection connection;
connection = conFactory.createConnection();
try
{
connection.start();
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
Destination destination = (Destination) jndi.lookup("Myqueue");
MessageProducer producer = session.createProducer(destination);
TextMessage message = session.createTextMessage("Hello World!");
producer.send(message);
System.out.println("Sent message '" + message.getText() + "'");
}
finally
{
connection.close();
}
}
public static void main(String[] args) throws JMSException
{
try
{
BasicConfigurator.configure();
new Producer();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
thanks
Have you tried using the Spring JMS Template? http://static.springsource.org/spring/docs/2.0.x/reference/jms.html
It provides an abstraction layer to JMS and could probably help you when your implementation changes.