Java Producer, Stompy Python Consumer, ActiveMQ - java

I have a java ActiveMQ producer which produces Integer messages into an ObjectMessage instance.
On the python side, I use stomp python for listening on the queue. However, I receive empty message body although all the headers are received right.
Moreover, if I change the message type to TextMessage on the java side, I get correct message on python-consumer side.
I have also tried with PyactiveMQ but with the same effect
Any suggestions will be appreciated!!!
EDIT: Here is a boilerplate java producer code and python subscriber code which i wrote to test stomp on python
public class App
{
Connection conn;
Session session;
MessageProducer producer;
public void registerPublisher(String queueName, String url) throws JMSException {
ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("system", "manager" ,url);
conn = cf.createConnection();
conn.start();
session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue(queueName);
producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
}
public void send(int c) {
for (int i=0; i<c; ++i) {
try {
TextMessage tm = session.createTextMessage(new Integer(i).toString());
// ObjectMessage tm = session.createObjectMessage();
producer.send(tm);
} catch (JMSException e) {
e.printStackTrace();
}
}
}
public static void main(String []arg) {
App app = new App();
try {
app.registerPublisher(arg[0], arg[1]);
System.out.println(app.session);
} catch (JMSException e) {
e.printStackTrace();
}
app.send(1000);
}
}
And Python Stomp listener
import time
import sys
import logging
import stomp
from stomp import ConnectionListener
queuename = sys.argv[1]
logging.basicConfig( level=logging.DEBUG)
class MyListener(ConnectionListener):
def on_error(self, headers, message):
print 'received an error %s' % message
def onMessage(self, headers, message):
print headers
print str(message)
print type(message)
print 'received a message ...%s...' % message
conn = stomp.Connection([('localhost', 61613)])
conn.set_listener('', MyListener())
conn.start()
conn.connect()
conn.subscribe(destination='/queue/'+queuename, ack='auto')
while 1:
time.sleep(2)

In order to send an receive ObjectMessage types over Stomp you need to use the message transformation feature of ActiveMQ to have the object payload delivered in a form a STOMP client can understand. ActiveMQ provides XML and JSON transformation support out of the box however you can add your own transformer to get whatever format you want on the content.

PROBLEM: Sending ObjectMessage from a java producer to ActiveMQ Broker. Stomp Python consumer client was getting empty message body
SOLUTION: Use transformation header while subscribing to the activemq broker in the python client,
for example:
connection.subscribe(destination='/queue/'+queuename, ack='auto', transformation="jms-json")
So that the broker knows in what form the message is to be sent to the stomp client

Related

Why does my JMS client not consume messages from the Topic?

I have ActiveMQ running on the localhost using the default port, 61616. I put some messages in a Topic called topic.STUDENTS. I have a client program that I am trying to use to read the messages in the Topic. Here is the main part of the program that does not work as expected. I was expecting to get some of the message back but instead I just receive null.
public void receiveMessages() throws URISyntaxException, JMSException, Exception {
try {
//Create a ConnectionFactory
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
//Create a Connection
Connection connection = connectionFactory.createConnection();
connection.start();
//Create a session
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//Create the destination (Topic or Queue)
Destination destination = session.createTopic("topic.STUDENTS");
//Create a MessageConsumer from the Session to the Topic or Queue
MessageConsumer consumer = session.createConsumer(destination);
//Wait for a message
Message message = consumer.receive(1000);
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
String text = textMessage.getText();
System.out.println("Received: " + text);
} else {
System.out.println("Received: " + message);
}
consumer.close();
session.close();
connection.close();
} catch(Exception e) {
System.out.println("Caught: " + e);
e.printStackTrace();
}
}
This code basically apes the code from ActiveMQ 'Hello World' example: http://activemq.apache.org/hello-world.html
Does anyone know why I do not receive any messages from the Topic? Here is one message that is in the Topic that I can see through the ./activemq browse topic.STUDENTS command:
JMS_BODY_FIELD:JMSText = Invention-my-dear-friends-is-93%-perspiration-6%-electricity
JMS_HEADER_FIELD:JMSExpiration = 0
JMS_HEADER_FIELD:JMSMessageID = ID:user-thinkpad-335i-59919-1457977678059-1:1:1:1:3
JMS_HEADER_FIELD:JMSPriority = 4
JMS_HEADER_FIELD:JMSDestination = topic.STUDENTS
JMS_HEADER_FIELD:JMSTimestamp = 1457977678409
JMS_HEADER_FIELD:JMSRedelivered = false
JMS_HEADER_FIELD:JMSDeliveryMode = persistent
Topics do not retain messages by default, so if you start the consumer after you've produced the messages then any message that was sent before the consumer arrived is gone. If you want to consume messages that were produced while your consumer was offline then you need to use a Queue or register a durable Topic subscriber on the Topic prior to producing the messages.

JMS Topic Publish/Subscriber

Currently I have started to work on JMS Topic with ActiveMQ. I have created Publisher and Durable Subscribers through JAVA code (mentioned below) and I received the messages in subscribers side also.
Publisher.Java
public static void createConnectionAndSendMessage(String ipAddress)
{
try
{
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://"+ipAddress+":61617");
Connection connection = factory.createConnection();
connection.start();
Session topicSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = topicSession.createTopic("Test-Topic");
MessageProducer producer = topicSession.createProducer(topic);
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
ObjectMessage message = topicSession.createObjectMessage();
TopicTO topicTO = new TopicTO();
topicTO.setId(i);
topicTO.setName("Sample");
message.setStringProperty("s_id", "Sample");
message.setObject((Serializable) topicTO);
producer.send(message);
System.out.println("message sent successfully");
}
}
catch(JMSException e)
{
System.out.println("error :" + e);
}
}
Subscriber.java
public void createConnectionAndReceiveMessage(String clientId, String ipAddress)
{
try
{
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://"+ipAddress+":61617");
Connection connection = connectionFactory.createConnection();
connection.setClientID(clientId);
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic("Test-Topic");
String selector = "s_id = 'Sample'";
System.out.println("selector : '"+selector+"'....");
TopicSubscriber consumer = session.createDurableSubscriber(topic, "Sub1", selector, true);
consumer.setMessageListener(new TopicMessageListener());
}
catch(Exception e)
{
System.out.println("error :" + e);
}
}
I have some doubts in Topic those are follows,
How may I check that how many subscribers actively looking for a message in Topic using Java JMS?
How can I get those active durable subscribers list from Topic?
Do we have any option to delete a posted message in Topic?
Help me in these contexts.
Thanks in advance.
In Publish/Subscribe messaging pattern, a publisher will be unaware of any subscribers. Publisher will publish messages to a topic hosted on a broker and the broker will in-turn distribute those messages to any subscribers registered for that topic. If there are no subscribers for a topic, then the message will be simply discarded.
JMS specification does not define any API that can get the details you are looking for. Such APIs will be JMS provider specific, Active MQ in your case. This link might be useful:http://activemq.apache.org/advisory-message.html

Unable to receive message sent to acivemq by C# in Java

What I want to do is to send messages via Apache Activemq between C# app and Java app.
C#:
using (IConnection connection = factory.CreateConnection())
using (ISession session = connection.CreateSession())
{
IDestination destination = SessionUtil.GetDestination(session, "queue://ISI");
// Create a consumer and producer
using (IMessageProducer producer = session.CreateProducer(destination))
{
// Start the connection so that messages will be processed.
connection.Start();
ITextMessage request = session.CreateTextMessage(JsonConvert.SerializeObject(obj));
/*request.NMSCorrelationID = "abc";
request.Properties["NMSXGroupID"] = "cheese";
request.Properties["myHeader"] = "Cheddar";*/
producer.Send(request);
return request;
}
}
Java:
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(isiProperties.getMqUrl());
connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue("ISI");
MessageConsumer consumer = session.createConsumer(destination);
Message message = consumer.receive();
if(message instanceof TextMessage) {
try {
String text = ((TextMessage) message).getText();
ObjectMapper mapper = new ObjectMapper();
StatusChangeMessage obj = mapper.readValue(text, StatusChangeMessage.class);
if (obj instanceof StatusChangeMessage) {
StatusChangeMessage received = (StatusChangeMessage) obj;
Order order = orderRepository.findOne(received.getOrderId());
order.setStatus(received.getStatus());
orderRepository.saveAndFlush(order);
}
} catch(JMSException e) {
} catch(IOException e) {
}
}
The C# app correctly sends messages (it is visible in activemq admin interface) but there are no active subscribers (Java app should do that). Do you see anything wrong here?
Basically, breakpoint on if(message instanceof TextMessage) { does not get executed.
I have finally found a solutioin. It was two-steps problem. Firstly, Windows firewall influenced activemq. Secondly, client library probably didn't fully match to the server. Problem finally gone after downgrading server to 5.8.0.

How to kill consumers in activemq

I am trying to get rid of all of the "Number of Consumers" in a certain queue. Whenever I purge/delete the queue, the number of consumers still remain if I ever create that queue with the same name again. Even with 0 pending messages, there are still 6 consumers.
My problem may have stemmed in my java code while not closing the session or connection.
I have tried both restarting and reinstalling the server.
Here is my producer code:
private static String url = ActiveMQConnection.DEFAULT_BROKER_URL;
public static String addElementToQueue(String queueName,String param1, String param2) throws JMSException, NamingException {
// Getting JMS connection from the server and starting it
ConnectionFactory connectionFactory =
new ActiveMQConnectionFactory(url);
Connection connection = connectionFactory.createConnection();
// JMS messages are sent and received using a Session. We will
// create here a non-transactional session object. If you want
// to use transactions you should set the first parameter to 'true'
Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
// Destination represents here our queue on the
// JMS server. You don't have to do anything special on the
// server to create it, it will be created automatically.
Destination destination = session.createQueue(queueName);
// MessageProducer is used for sending messages (as opposed
// to MessageConsumer which is used for receiving them)
MessageProducer producer = session.createProducer(destination);
String queueMessage = param1+ "-" + param2;
TextMessage message = session.createTextMessage(queueMessage);
// Here we are sending the message!
producer.send(message);
connection.close();
session.close(); // added after problem came up
producer.close(); // added after problem came up
return commandID;
}
Here is my consumer code:
// URL of the JMS server
private static String url = ActiveMQConnection.DEFAULT_BROKER_URL;
public static Pair consumeNextElement(String queueName) throws JMSException {
// Getting JMS connection from the server
ConnectionFactory connectionFactory
= new ActiveMQConnectionFactory(url);
Connection connection = connectionFactory.createConnection();
connection.start();
// Creating session for seding messages
Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
// Getting the queue
Destination destination = session.createQueue(queueName);
// MessageConsumer is used for receiving (consuming) messages
MessageConsumer consumer = session.createConsumer(destination);
// Here we receive the message.
// By default this call is blocking, which means it will wait
// for a message to arrive on the queue.
Message message = consumer.receive();
// There are many types of Message and TextMessage
// is just one of them. Producer sent us a TextMessage
// so we must cast to it to get access to its .getText()
// method.
String[] parts = ((TextMessage)message).getText().split("-");
Pair retVal = new Pair(parts[0], parts[1]);
connection.close();
session.close(); // added after problem came up
consumer.close(); // added after problem came up
return retVal;
}
Any thoughts?
Thanks.
The number of consumers is the number of listeners on the queue. Purging the queue should only remove the enqueued messages - those consumers listening will be unaffected.
The ability of the consumer to maintain/re-establish a connection may depend on the transport used to connect, and settings for the transport may allow for some tweaking of connection properties.
I frankly don't have much experience with these, but you might investigate Advisory Messages as a means to help debug your connections. The JMX interface or web console don't appear to be helpful beyond reporting consumer counts.

ACTIVEMQ- publisher subscriber hello world example

There are two programs: subscriber and publisher...
Subscriber is able to put the message onto the topic and the message is sent successfully.
When I check the activemq server on my browser it shows 1 msg enqueued . But when I run the consumer code, it is not receiving the message
Here is the producer code:
import javax.jms.*;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
public class producer {
private static String url = ActiveMQConnection.DEFAULT_BROKER_URL;
public static void main(String[] args) throws JMSException {
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
Connection connection = connectionFactory.createConnection();
connection.start();
// JMS messages are sent and received using a Session. We will
// create here a non-transactional session object. If you want
// to use transactions you should set the first parameter to 'true'
Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic("testt");
MessageProducer producer = session.createProducer(topic);
// We will send a small text message saying 'Hello'
TextMessage message = session.createTextMessage();
message.setText("HELLO JMS WORLD");
// Here we are sending the message!
producer.send(message);
System.out.println("Sent message '" + message.getText() + "'");
connection.close();
}
}
After I run this code the output at the console is:
26 Jan, 2012 2:30:04 PM org.apache.activemq.transport.failover.FailoverTransport doReconnect
INFO: Successfully connected to tcp://localhost:61616
Sent message 'HELLO JMS WORLD'
And here is the consumer code:
import javax.jms.*;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
public class consumer {
// URL of the JMS server
private static String url = ActiveMQConnection.DEFAULT_BROKER_URL;
// Name of the topic from which we will receive messages from = " testt"
public static void main(String[] args) throws JMSException {
// Getting JMS connection from the server
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
Connection connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic("testt");
MessageConsumer consumer = session.createConsumer(topic);
MessageListener listner = new MessageListener() {
public void onMessage(Message message) {
try {
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
System.out.println("Received message"
+ textMessage.getText() + "'");
}
} catch (JMSException e) {
System.out.println("Caught:" + e);
e.printStackTrace();
}
}
};
consumer.setMessageListener(listner);
connection.close();
}
}
After I run this code it doesnt show anything.
Can someone help to me to overcome this problem?
Your issue is that your consumer is running and then shutting down immediately.
Try adding this into your consumer:
consumer.setMessageListener(listner);
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
connection.close();
This will wait until you hit a key before stopping.
Other things to consider:
Use a finally block for the close
Java naming conventions encourage using uppercase for the first letter of a class
The main problem (besides the app closing down to quickly) is that you are sending to a Topic. Topics don't retain messages so if you run your application that produces and then run the consumer, the consumer won't receive anything because it was not subscribed to the topic at the time the message was sent. If you fix the shutdown issue and then run the consumer in one terminal and then run the producer you should then see the message received by your consumer. If you want message retention then you need to use a Queue which will hold onto the message until someone consumes it.
Your producer class is correct. It runs smoothly.
But, your consumer is incorrect & you have to modify it.
First, add setClientID("any_string_value") after creating connection object;
eg: Connection connection = connectionFactory.createConnection();
// need to setClientID value, any string value you wish
connection.setClientID("12345");
secondly, use createDurableSubscriber() method instead of createConsumer() for transmitting message via topic.
MessageConsumer consumer = session.createDurableSubscriber(topic,"SUB1234");
Here is the modified comsumer class:
package mq.test;
import javax.jms.*;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
public class consumer {
// URL of the JMS server
private static String url = ActiveMQConnection.DEFAULT_BROKER_URL;
// Name of the topic from which we will receive messages from = " testt"
public static void main(String[] args) throws JMSException {
// Getting JMS connection from the server
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
Connection connection = connectionFactory.createConnection();
// need to setClientID value, any string value you wish
connection.setClientID("12345");
try{
connection.start();
}catch(Exception e){
System.err.println("NOT CONNECTED!!!");
}
Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic("test_data");
//need to use createDurableSubscriber() method instead of createConsumer() for topic
// MessageConsumer consumer = session.createConsumer(topic);
MessageConsumer consumer = session.createDurableSubscriber(topic,
"SUB1234");
MessageListener listner = new MessageListener() {
public void onMessage(Message message) {
try {
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
System.out.println("Received message"
+ textMessage.getText() + "'");
}
} catch (JMSException e) {
System.out.println("Caught:" + e);
e.printStackTrace();
}
}
};
consumer.setMessageListener(listner);
//connection.close();
}
}
Now, your code will run successfully.
just some:
work with a queue not a topic. messages in topics will be discarded when no consumer is available, they are NOT persistend.
add connection.start() after setting the message listener. you should start a connection when all consumers/producers are properly set up.
wait some time before before closing the connection again.
the topic will probably be your most important source of failure.

Categories