JMS Get message/response from EJB - java

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.

Related

How can I set expire time of queue message using ActiveMQ by Java Programming?

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));
}
}

JMS how to get mulitple messages with JMSMessageListener

I m trying to sent to a consumer a message from client. Consumer expects many message types like Booking or Confirmation. So when i get the message i m trying to see if the message is instance of Booking or Confirmation. So far the instance of is not working, i cant see if the object is Booking or Confirmation. Besides my JMSMessageListener doesnt seem to be the best way of doing the scenario.
The scenario is :
Client sends a Booking to agent, agent forwards the message to different consumers, agent gets confirmation from consumers and sends a confirmation back.
Any ideas why instance of not working and for this scenario, is this a good way to implement a JMSMessageListener to an agent for multiple purposes ?
//JMS Message Listener
public class JMSAgentMessageListener implements MessageListener {
private ConnectionFactory factory = null;
private Connection connection = null;
private Session session = null;
private Destination BookingQueue = null;
private Destination consolidatorQueue1 = null;
private Destination consolidatorQueue2 = null;
private MessageConsumer consumer = null;
private Destination agentConfirmQueue = null;
private static MessageProducer producer = null;
final static Logger logger = Logger.getLogger(TravelAgent.class);
private Destination customerConfirmQueue = null;
#Override
public void onMessage(Message message) {
try {
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory( "tcp://localhost:61616");
// Create a Connection
Connection connection = connectionFactory.createConnection();
session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
if (message instanceof Booking) {
Booking booking = (Booking) message;
logger.info("# Received order for " + booking.getCustomer());
customerConfirmQueue = message.getJMSReplyTo();
logger.info("# The travel agent forwards booking orders to the airfare consolidators");
ObjectMessage messageToConsilator1 = session . createObjectMessage ( booking ) ;
agentConfirmQueue = session.createQueue("AgentConfirmQueue");
consolidatorQueue1 = session.createQueue("ConsolidatorQueue1");
messageToConsilator1.setJMSReplyTo(agentConfirmQueue);
messageToConsilator1.setJMSDestination(consolidatorQueue1);
producer = session.createProducer(consolidatorQueue1);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
producer.send(messageToConsilator1);
}else if(message instanceof Confirmation){
logger.info("# The travel agent recieved booking orders to the airfare consolidators");
Confirmation confirmation = (Confirmation) message;
logger.info(confirmation.getMessage()+"received");
logger.info("# The travel agent notfiying the customers");
ObjectMessage messageToClient = session . createObjectMessage ( confirmation ) ;
customerConfirmQueue = session.createQueue("customerConfirmQueue");
producer = session.createProducer(customerConfirmQueue);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
producer.send(messageToClient);
}
producer.close();
session.close();
connection.close();
} catch (JMSException e) {
logger.error("couldnt get the message");
}
}
}
Message isn't in the hierarchy of your class inheritance tree. JMS offers, different types of messages that can be disseminated, Text, Object, etc., all inheriting from Message. It is these types that you could call instance of on. Once Message is cast to an ObjectMessage, you can then call getObject() and then cast it/check instanceof for your types.
I'd recommend limiting types of messages that can be sent on a topic as it lends itself to some messier code. I try to avoid using instanceof if at all possible by refactoring the code in a way that makes it unnecessary. To reduce the need for instanceof, I'd create a topic per type of information being conveyed or develop your classes in such a way that they inherit from the same parent or implement the same interface.

Implementing ActiveMQ Message Listener in/using JSP

I have implemented Message Listener in core java using Active MQ/JMS. The purpose of this listener is to subscribe a topic on ActiveMQ and then listen to the messages received from the topic. My code is working fine as a console application. Now I need to extend my application into a web application so that the messages received could be used in the web page i.e JSP. I am confused about how the message listener will work in JSP, how I will receive and process messages from active MQ topic. So far I have following code but doesn't seem to help in current scenario:
<%!
public void handleReceivedMessages() {
String url = ActiveMQConnection.DEFAULT_BROKER_URL;
String subject = "XXXXX";
try {
ConnectionFactory connectionFactory
= new ActiveMQConnectionFactory(url);
Connection connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic(subject);
MessageConsumer consumer = session.createConsumer(topic);
MessageListener listner = new MessageListener() {
#Override
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);
}
}
};
consumer.setMessageListener(listner);
try {
System.in.read();
} catch (IOException e) {
}
connection.close();
} catch (JMSException ex) {
// Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, ex);
}
}//end method
%>
How I am supposed to use this code so that i can e.g print every message on my web page which is received by the topic?
JSP pages are used the moment the web page is loaded to render the HTML. After that, they have no function.
Typically, you need to create a Message Driven Bean(MDB) or something similar using Spring. The MDB will receive messages, process the data and store it somewhere (typically a database, but could be also be a global cache, local files or similar). Your JSP then simply uses the data stored by JMS messages.
If you really want the messages to interact with the user more dynamically - you can connect to ActiveMQ using JavaScript from the client browser. The ActiveMQ distribution have some examples regarding this. Look into examples/mqtt/websocket or examples/stomp/websocket to see some working code.

Not receiving reply on Websphere MQ temporary queue

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.

Jboss Messaging JMS

I successfully managed to send the message to queue name ReceiverQueue on my localhost Jboss server, how can I retrieve message I sent to it or how do I check if there is any messages in the queue if any retrieve them. or can I get an explanation of some sort what is the best way to do this. Thank you
A working send/receive tutorial would be accept as well. Anything that will get me to just send to the queue and receive message from that queue will get accepted answer.
I'm using Spring.
I want a solution that does it using application context with bean injection ..
Standard JMS API steps:
1. Create a javax.naming.Context with the access details of the server
context = new InitialContext(environment)
2. Look up javax.jms.QueueConnectionFactory in the context. Factory name is specific to the JMS server
factory = (QueueConnectionFactory)context.lookup(factoryName)
3. Create a javax.jms.QueueConnection
connection = factory.createQueueConnection(...)
4. Create a javax.jms.QueueSession
session = connection.createQueueSession(...)
5. Look up your javax.jms.Queue in the context
queue = (Queue) context.lookup(qJndiName)
Till now it is the same as sending....
6. Create a javax.jms.QueueReceiver with the session
receiver = session.createReceiver(queue)
7. JMS API provides 2 ways to retrieve a message:
7.a Wait for a message with one of the receiver.receive() methods
7.b Implement javax.jms.MessageListener in your class and register it as the listener
receiver.setMessageListener(this)
JMS API will call your onMessage() method whenever a new message arrives
8. Don't forget to start the listener:
connection.start()
9. Close the context (very important, when you access multiple JMS servers from the same program):
context.close()
The above is a typical solution from a stand-alone application. In EJB environment you should use message driven beans. You can find ino on them on http://java.sun.com/javaee/6/docs/tutorial/doc/gipko.html and a tutorial on http://schuchert.wikispaces.com/EJB3+Tutorial+5+-+Message+Driven+Beans
Here is the working example you've asked for:
import java.util.Hashtable;
import javax.naming.*;
import javax.jms.*;
public class JMSJNDISample implements MessageListener {
public static final String JNDI_URL = "jnp://localhost:1099";
public static final String JNDI_CONTEXT_FACTORY = "org.jnp.interfaces.NamingContextFactory";
public static final String JMS_USER = null;
public static final String JMS_PASSWORD = null;
public static final String JMS_CONNECTION_FACTORY = "MyConnectionFactory";
public static final String QUEUE_JNDI_NAME = "ReceiverQueue";
QueueConnection qConn = null;
QueueSession qSession = null;
QueueSender qSender = null;
QueueReceiver qReceiver = null;
public JMSJNDISample () {
}
public void init() throws JMSException, NamingException {
// Set up JNDI Context
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_CONTEXT_FACTORY);
env.put(Context.PROVIDER_URL, JNDI_URL);
if (JMS_USER != null)
env.put(Context.SECURITY_PRINCIPAL, JMS_USER);
if (JMS_PASSWORD != null)
env.put(Context.SECURITY_CREDENTIALS, JMS_PASSWORD);
Context jndiContext = new InitialContext(env);
// Lookup queue connection factory
QueueConnectionFactory cFactory = (QueueConnectionFactory)jndiContext.lookup(JMS_CONNECTION_FACTORY);
// Create Connection
if (JMS_USER == null || JMS_PASSWORD == null)
qConn = cFactory.createQueueConnection();
else {
qConn = cFactory.createQueueConnection(JMS_USER, JMS_PASSWORD);
}
// Create Session
qSession = qConn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
// Lookup Queue
Queue queue = (Queue) jndiContext.lookup(QUEUE_JNDI_NAME);
// Create Queue Sender
qSender = qSession.createSender(queue);
// Create Queue Receiver
qReceiver = qSession.createReceiver(queue);
qReceiver.setMessageListener(this);
// Start receiving messages
qConn.start();
// Close JNDI context
jndiContext.close();
}
public void sendMessage (String str) throws JMSException {
TextMessage msg = qSession.createTextMessage(str);
qSender.send(msg);
}
public void onMessage (Message message) {
try {
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage)message;
System.out.println("Text Message Received: "+textMessage.getText());
} else {
System.out.println(message.getJMSType()+" Message Received");
}
} catch (JMSException je) {
je.printStackTrace();
}
}
public void destroy() throws JMSException {
if (qSender != null) qSender.close();
if (qReceiver != null) qReceiver.close();
if (qSession != null) qSession.close();
if (qConn != null) qConn.close();
}
public static void main(String args[]) {
try {
JMSJNDISample sample = new JMSJNDISample();
// Initialize connetion
sample.init();
// Send Message
sample.sendMessage("Hello World");
// Wait 2 sec for answer
Thread.sleep(2000);
// Disconnect
sample.destroy();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Other than having a MessageDrivenBean listening to that queue?
EDIT:
You are using spring just to create the payload, right? JMS is a JavaEE spec. You don't need to use Spring for actually sending/receiving messages. You don't have to manually check whether there are messages in the queue etc., either. All you need to do is have an MDB(MessageDrivenBean) set up like this,
#MessageDriven(activationConfig = {
#ActivationConfigProperty(
propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
#ActivationConfigProperty(
propertyName = "destination", propertyValue = "queue/myqueue")
})
public class MyMessageDrivenBean implements MessageListener {
public void onMessage(Message message) {
ObjectMessage objMsg = (ObjectMessage) message;
Payload payload = (Payload)objMsg.getObject();
//do stuff
}
}
And then send some JMS messages.
#Stateless
public class QueuerBean implements QueuerLocal {
#Resource(mappedName = "java:/JmsXA")
private ConnectionFactory jmsConnectionFactory;
#Resource(mappedName = "queue/myqueue")
private Queue queue;
private void queue(MyPayload payload) {
try {
Connection connect = jmsConnectionFactory.createConnection();
Session session = connect.createSession(false,
Session.DUPS_OK_ACKNOWLEDGE);
MessageProducer producer = session.createProducer(queue);
// create a JMS message and send it
ObjectMessage objMsg = session.createObjectMessage(payload);
producer.send(objMsg);
producer.close();
session.close();
connect.close();
} catch (JMSException e) {
log.error("Bad thing happened", e);
}
}
}
The queue is configured by the annotation. When a message is sent, JBoss will automatically trigger the MDB.
Here's an example showing how to set up a message-driven POJO in Spring. I'd recommend following this idiom if you're already using Spring.
As for the part about seeing how many messages are on the queue, I'd say you should be using the admin console for JBOSS, not your code.
I would recommend also using a tool like HermesJMS (http://www.hermesjms.com/confluence/display/HJMS/Home) to inspect the queue manager and queues. It's a great debugging tool.

Categories

Resources