I recently work with Topic in jms and I have a problem. My TopicSubscriber didn't receive message from publisher and I don't understand why.
Here is my TopicPublisher:
public class Publisher
{
private static final String CONNECTION_URL = "tcp://localhost:61616";
public static void main(String[] args) throws Exception
{
BrokerService service = BrokerFactory.createBroker(new URI("broker:(" + CONNECTION_URL + ")"));
service.start();
TopicConnectionFactory connectionFactory = new ActiveMQConnectionFactory(CONNECTION_URL);
// create a topic connection
TopicConnection topicConn = connectionFactory.createTopicConnection();
// create a topic session
TopicSession topicSession = topicConn.createTopicSession(false,
Session.AUTO_ACKNOWLEDGE);
// lookup the topic object
Topic topic = topicSession.createTopic("test");
// create a topic publisher
TopicPublisher topicPublisher = topicSession.createPublisher(topic);
topicPublisher.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
// create the "Hello World" message
TextMessage message = topicSession.createTextMessage();
message.setText("Hello World");
// publish the messages
topicPublisher.publish(message);
// print what we did
System.out.println("Message published: " + message.getText());
// close the topic connection
topicConn.close();
}
}
My TopicSubscriber:
public class Subscriber
{
private static final String CONNECTION_URL = "tcp://localhost:61616";
public static void main(String[] args) throws Exception
{
TopicConnectionFactory connectionFactory = new ActiveMQConnectionFactory(CONNECTION_URL);
// create a topic connection
TopicConnection topicConn = connectionFactory.createTopicConnection();
// create a topic session
TopicSession topicSession = topicConn.createTopicSession(false,
Session.AUTO_ACKNOWLEDGE);
Topic topic = topicSession.createTopic("test");
// create a topic subscriber
TopicSubscriber topicSubscriber = topicSession.createSubscriber(topic);
// start the connection
topicConn.start();
// receive the message
TextMessage message = (TextMessage) topicSubscriber.receiveNoWait();
// print the message
System.out.println("Message received: " + message.getText());
// close the topic connection
topicConn.close();
}
}
In my subscriber I've got a NullPointer on message.getText()
What is that problem? What am I doing wrong and how it can be fixed?
It appears that you're sending the message before you create the subscription. JMS topics use publish-subscribe semantics where any message published goes to all subscriptions. If there are no subscriptions then the message is discarded.
Also, since you're using receiveNoWait() you're severely reducing the chance that your client will ever get a message. In order for your client to actually receive a message the message would have to be sent in between the time you call createSubscriber(topic) and the time you call receiveNoWait(). Since those 2 calls happen very close together the window of time is very small.
If you really want your subscriber to get a message then run Subscriber first and use receive() rather than receiveNoWait() and then run Publisher. This will ensure the subscription exists when the message is sent and that the client waits to receive the message before exiting.
Related
In this code, I am using setJMSExpiration(1000) for expire message of one second in queue from publisher side. But From Consumer Side, It is returning properly message after 1 second instead of null.
public class RegistrationPublisher extends Thread{
public void run() {
publisherQueue("Registration.Main.*");
}
public void publisherQueue(String server){
try {
String url="tcp://192.168.20.49:61616";
// Create a ConnectionFactory
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
Connection connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue(server);
MessageProducer producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
String text = "Test";
TextMessage message = session.createTextMessage(text);
message.setJMSExpiration(1000);// For Expire message in one second
producer.send(message);
producer.close();
session.close();
connection.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String args[]) throws IOException{
RegistrationPublisher registrationPublisher=new RegistrationPublisher();
registrationPublisher.start();
}
}
You do this by configuring the JMS MessageProducer to do it for you via the send method that accepts a TTL or by calling setTimeToLive on the producer which adds the same TTL to all sent messages. The JMS APIs for the message version are clear that calling the setters on the message have no effect.
void setJMSExpiration(long expiration) throws JMSException
Sets the message's expiration value.
This method is for use by JMS providers only to set this field when a message is sent. This message cannot be used by clients to configure the expiration time of the message. This method is public to allow a JMS provider to set this field when sending a message whose implementation is not its own.
I first also thought that is was possible to set expiration directly on the message in the post-processor, but as Tim Bish said above, this is not the intended way to do it, and the value will get reset to 0 afterward. I couldn't access to the producer directly neither to set a time to live, because this object was in library org.springframework.jms (I was following this documentation).
One thing I could do was to set to time to live on the jmsTemplate:
import org.springframework.jms.core.JmsTemplate;
#Service
public class MyJmsServiceImpl implements MyJmsService {
#Inject
private JmsTemplate jmsTemplate;
private void convertAndSendToResponseQueue(String targetQueueName, String correlationid, Object message) {
// Set time to live
jmsTemplate.setExplicitQosEnabled(true);
jmsTemplate.setTimeToLive(5000);
jmsTemplate.convertAndSend(targetQueueName, message, new JmsResponsePostProcessor(correlationid));
}
}
So I'm trying to consume messages from a Tibco EMS broker via JMS with a message Id selector. If messages are NON_PERSISTENT, I can select them by their JMSMessageID's, and all works fine.
If the messages are PERSISTENT, the selector doesn't retrieve anything. I've tried the same code on Apache ActiveMQ, and it works in both cases. I've been through the EMS samples and cant see anything obvious. Wondering if there's some EMS settings that might affect this...
If I omit the selector, then messages are properly consumed regardless of DeliveryMode.
Here's what I'm using to reproduce it.
Any help would be much appreciated :)
package com;
import javax.jms.*;
import com.tibco.tibjms.TibjmsConnectionFactory;
public class JMSTest {
String msgIdPersistent = "";
String msgIdNon_Persistent = "";
String serverUrl = "tcp://localhost:7222";
String queueName = "test";
public static void main(String[] args) {
JMSTest test = new JMSTest();
try {
test.publish();
test.deleteBySelector();
}catch(Exception ex) {
ex.printStackTrace();
}
}
public void deleteBySelector() throws Exception {
// Create connection and session
ConnectionFactory factory = new TibjmsConnectionFactory(serverUrl);
Connection connection = factory.createConnection();
connection.start();
Session session = connection.createSession();
// Delete non-persistent
//
String selectorNonPersist = "JMSMessageID='" + msgIdNon_Persistent + "'";
MessageConsumer nonPersistReceiver = session.createConsumer(session.createQueue(queueName), selectorNonPersist);
Message nonPersistMsg = null;
nonPersistMsg = nonPersistReceiver.receive(1000);
System.out.println("NON PERSISTENT SELECTOR: " + ((nonPersistMsg!=null) ? "SUCCESS" : "FAIL"));
// Delete Persistent - **** THIS DOESN'T WORK *****
//
String selectorPersist = "JMSMessageID='" + msgIdPersistent + "'";
MessageConsumer persistReceiver = session.createConsumer(session.createQueue(queueName), selectorPersist);
Message persistMsg = null;
persistMsg = persistReceiver.receive(1000);
System.out.println("PERSISTENT SELECTOR: " + ((persistMsg!=null) ? "SUCCESS" : "FAIL"));
}
public void publish() throws Exception {
ConnectionFactory factory = new com.tibco.tibjms.TibjmsConnectionFactory(serverUrl);
Connection connection = factory.createConnection();
connection.start();
Session session = connection.createSession(javax.jms.Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue("test");
// Send persistent message
//
System.out.println("Persistent publish");
MessageProducer producerPersistent = session.createProducer(null);
producerPersistent.setDeliveryMode(DeliveryMode.PERSISTENT);
TextMessage messagePersistent = session.createTextMessage("PERSISTENT");
producerPersistent.send(destination, messagePersistent);
msgIdPersistent = messagePersistent.getJMSMessageID();
System.out.println("\tMsgId=" + msgIdPersistent);
// Send Non Persistent message
//
System.out.println("NON Persistent publish");
MessageProducer producernonPersistent = session.createProducer(destination);
producernonPersistent.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
TextMessage messageNonPersistent = session.createTextMessage("NON_PERSISTENT");
producernonPersistent.send(messageNonPersistent);
msgIdNon_Persistent = messageNonPersistent.getJMSMessageID();
System.out.println("\tMsgId=" + msgIdNon_Persistent);
// Clean up
session.close();
connection.close();
System.out.println("Done publish\n");
}
}
The output I'm getting from this is:
Persistent publish
MsgId=ID:EMS-SERVER.3D856ECE827932:1
NON Persistent publish
MsgId=ID:EMS-SERVER.3D856ECE827932:2
Done publish
NON PERSISTENT SELECTOR: SUCCESS
PERSISTENT SELECTOR: FAIL
I've confirmed its a bug in 8.2.x. I upgraded to 8.3.x and it is working fine.
This is my sender class:
private void sendJMSMessage(Object data) throws JMSException {
Connection con = null;
Session s = null;
try {
con = context.createConnection();
s = con.createSession(false, Session.CLIENT_ACKNOWLEDGE);
MessageProducer producer = s.createProducer(glassFishQueue);
ObjectMessage msg = s.createObjectMessage();
ArrayList list = new ArrayList();
list.add("name");
msg.setObject(p);
producer.send(msg);
}
And my Message-driven Bean:
public void onMessage(Message message) {
try {
ObjectMessage om = (ObjectMessage) message;
ArrayList al = (ArrayList) om.getObject();
System.out.println("Msg: " + al.get(0));
} catch (JMSException jex) {
System.out.println("Exception: " + jex);
}
I got the message sent from sender class but I need a message back from EJB to the sender.
Im doing a web client with a table but I need to fill it getting the info from a database remotely, I really doesnt know what i should to use to do this, so if im doing right let me know or tell me any suggestion
Thank u
JMS is asynchronous, so it won't work in request-response style out of the box.
If you want to send a reply, one way is to use a separate queue. Your MDB can write the response to this second queue and your client can listen to this queue by creating a QueueReceiver.
Another way is to use QueueRequestor. From javadocs:
It creates a TemporaryQueue for the responses and provides a request
method that sends the request message and waits for its reply.
Look here and here for QueueRequestor examples.
I am working with a send/receive mechanism to a Websphere MQ system.
The xml that I send in text format should receive a reply, however I receive no reply.
I know that the xml is being "sent" ok, since "things are happening" in the target system - it is just that I am not receiving a reply. The reply is important to me, since it could include an error message if something should fail.
So, the reason I am not receiving a reply - I am not sure if there is a problem with my code or with the Websphere MQ configuration.
Any pointers on my code or what I should ask the Websphere MQ administrators to look at are greatly appreciated!!
A small self contained example to demonstrate the receive is not happening looks like this:
public class CustomQueueConnection {
private MQQueueConnectionFactory connectionFactory;
private MQQueueConnection connection;
private void runTest() throws JMSException {
connect();
MQQueueSession session = (MQQueueSession) connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
MQQueue queue = (MQQueue) session.createQueue("queue:///REQ_SNAPSHOT.HT");
MQQueueSender sender = (MQQueueSender) session.createSender(queue);
TemporaryQueue temporaryQueue = session.createTemporaryQueue();
MQQueueReceiver receiver = (MQQueueReceiver) session.createReceiver(temporaryQueue);
TextMessage message = session.createTextMessage(
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n" +
// my well constructed xml goes here...
);
message.setJMSReplyTo(temporaryQueue);
sender.send(message);
System.out.println("Sent: " + message);
JMSMessage receivedMessage = (JMSMessage) receiver.receive(10000);
System.out.println("Received: " + receivedMessage);
}
public boolean connect() {
boolean connected = false;
try {
connectionFactory = new MQQueueConnectionFactory();
connectionFactory.setCCSID(819);
connectionFactory.setPort(1417);
connectionFactory.setHostName("1.2.3.4");
connectionFactory.setQueueManager("GATE1");
connectionFactory.setChannel("CLIENTS.CHANNEL");
connectionFactory.setTemporaryModel("GATEWAY_MODEL_QUEUE");
connectionFactory.setTempQPrefix("MACHINE.USER_NAME.*");
connectionFactory.setTransportType(JMSC.MQJMS_TP_CLIENT_MQ_TCPIP);
connection = (MQQueueConnection) connectionFactory.createQueueConnection();
connected = true;
} catch (JMSException e) {
connected = false;
}
return connected;
}
public static void main(String[] args) throws JMSException {
new CustomQueueConnection().runTest();
}
}
And here is the output:
Sent:
JMS Message class: jms_text
JMSType: null
JMSDeliveryMode: 2
JMSExpiration: 0
JMSPriority: 4
JMSMessageID: ID:414d512050314f47415445312020202053599032201b4d05
JMSTimestamp: 1398680728618
JMSCorrelationID:null
JMSDestination: queue:///REQ_SNAPSHOT.HT
JMSReplyTo: queue://GATE1/MACHINE.USER_NAME.53599032201B4E04?persistence=1
JMSRedelivered: false
JMS_IBM_PutDate:20140428
JMSXAppID:WebSphere MQ Client for Java
JMS_IBM_PutApplType:28
JMSXUserID:aomis
JMS_IBM_PutTime:10252859
JMSXDeliveryCount:0
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<esb:esbMessage xmlns:esb="http://ESBServices
Another 557 character(s) omitted
Received: null
(NB: Received: null)
edit: Websphere MQ version is 6.0.25
Your code looks OK to me, message send is successful. I would like you to check:
1) Is there an application running to receive message from REQ_SNAPSHOT.HT queue?
2) Assuming there is an application running and receiving messages, has that application processed the incoming XML message successfully? is it throwing any exceptions?
3) If the incoming message is processed successfully, has it put a reply to the correct reply queue "MACHINE.USER_NAME.53599032201B4E04"? check if it faced any problems while putting the reply message.
The solution was twofold.
First, the connection needed to be started right after it was created.
connect();
connection.start();
Secondly, the message needed to be sent with DeliveryMode.NON_PERSISTENT.
I wrote a simple ActiveMQ client program for produce a message as following:
public static void main(String[] args) throws Throwable
{
final ActiveMQConnectionFactory conFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
final QueueConnection connection = conFactory.createQueueConnection();
final Session session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
final Destination destination = new ActiveMQQueue("MJ_SAF");
final MessageProducer producer = session.createProducer(destination);
Message message = session.createTextMessage("test");
message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, 20);
message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_PERIOD, 1);
message.setIntProperty(ScheduledMessage.AMQ_SCHEDULED_REPEAT, 1);
producer.send(message);
}
when this program executed I expect a message stored in scheduled part of ActiveMQ and after 20 second send for MJ_SAF queue but when I connect to web consol saw following result:
stored two messages at MJ_SAF and it's not correct but when I normally send message (without scheduling), I see a message in web console.
public static void main(String[] args) throws Throwable
{
final ActiveMQConnectionFactory conFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
final QueueConnection connection = conFactory.createQueueConnection();
final Session session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
final Destination destination = new ActiveMQQueue("MJ_SAF");
final MessageProducer producer = session.createProducer(destination);
Message message = session.createTextMessage("test");
producer.send(message);
}
by above code all things is nice:
I don't understand this behavior. Does anyone know reasons of this?
You have the property ScheduledMessage.AMQ_SCHEDULED_REPEAT set to 1, so it will repeat 1 time giving you a total of 2 messages.
See here for the descriptions of the properties. As I understand it, your current set up will wait 20 milliseconds, publish 1 message, wait 1 millisecond, and publish a second message, then end.