I am having a problem about JMS. The problem is, I have an application and it is trying to send a message through JMS , but after JMS server restart, it throws exception as when the server was down time. It is not reconnecting.
It is completely fine without a restart of JMS server and I am using weblogic 10.x.
Is it a problem about JMS configuration?
Thanks
Can you post your code how you are sending messages?
If you attempt to send a message when the JMS server is down, you will probably have an exception, and have to deal with that. When you attempt to send a message the next time, when the JMS server is restarted and running, you probably create a new connection from your connection factory. Reconnection will happend then:
// Let's say, you inject CF and Dest.
#Resource(lookup = "jms/ConnectionFactory")
private static ConnectionFactory cf;
#Resource(lookup = "jms/MyQueue")
private static Destination dest;
public void sendMessage(){ // called every time you need to send a message.
try{
Connection con = cf.createConnection(); // will reconnect, otherwise pooled.
Session sess = con.createSession(false,Session.AUTO_ACKNOWLEDGE);
MessageProducer prod = sess.createProducer(dest);
Message msg = sess.createTextMessage("Hello, World");
prod.send(msg);
sess.close();
con.close();
}catch(Exception e){
// handle errors
}
}
However, there are some built in failover/reconnecting features in Weblogic JMS, take a look at this page:
Oracle code listing and documentation about reconnecting JMS producers
Related
I'm so stuck about this.
I want to subscribe an ActiveMQ topic. ActiveMQ works on Centos machine, NOT LOCALHOST. I can consume messages with tcp, http protocols. Code;
public static void main(String[] args) throws JMSException {
PropertyUtils.loadPropertyFile();
Properties receiverProperties = PropertyUtils.getreceiverProperties();
// URL of the JMS server
String url = (String) receiverProperties.get("receiver.connection.url");
// Name of the queue we will receive messages from
String subject = (String) receiverProperties.get("receiver.topic.name");
// Getting JMS connection from the server
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(url);
Connection connection = connectionFactory.createConnection();
connection.start();
// Creating session for getting messages
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// Getting the topic
Destination destination = session.createTopic(subject);
// MessageConsumer is used for receiving (consuming) messages
MessageConsumer consumer = session.createConsumer(destination);
Message message = null;
// Here we receive the message.
while (true) {
message = consumer.receive();
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
System.out.println("Received message '" + textMessage.getText() + "'");
}
}
// We will be using TestMessage in our example. MessageProducer sent us a
// TextMessage
// so we must cast to it to get access to its .getText() method.
// connection.close();
}
I want to use wss protocol. This is a must for me. When I changed url with wss://host:port getting;
Could not create Transport. Reason: java.io.IOException: createTransport() method not implemented!
So I checked the alternatives. People figure this out with Stomp over WS. My first achievement is wss connection.
Any recommendation will be appreciated!
The exception you're seeing is expected because the OpenWire JMS client you're using doesn't support WebSocket connections, and it doesn't really need to. WebSocket connections are really only relevant for clients running in a limited environment like a web browser. Web browsers don't support running Java clients.
If you really want to use STOMP over WebSockets then you'll have to use a STOMP client implementation that supports WebSockets (most do).
Keep in mind that ActiveMQ is a broker. It does not supply clients for all the protocols it supports. It only provides a JMS client because it is required in order to implement JMS. STOMP, for example, is a standardized protocol and anyone can implement a client which will work with any broker implementing STOMP. There are lots of STOMP client implementations available written in many different languages for many different platforms. Any good search engine should help you find one to fit your needs.
The application I am working on needs to communicate to an IBM MQ server in a remote location. We currently have a working system using active MQ which uses a broker, and a bridge to connect to this remote IBM MQ server and is working fine.
Due to some new enhancement, we are now trying to achieve the same using IBM client jars instead of Active MQ.
The problem I am facing is that I can connect to the remote server's inboundQ and send messages.But I am always receiving null from the remote servers outbound Queue. But I have no way to check if the messages are received at the remote location. But the same message if sending through the old ActiveMQ system will get a response from remote MQ server.
Old Active MQ internally uses the bridge to connect to remote IBM MQ server which is configured exactly like the new code I am using.
I have tried multiple codes from internet and stack overflow itself and always I am able to connect but not getting any responses.
Also, I get no errors or exceptions while trying to send or receive from remote IBM MQ.
I will paste a sample code which I am trying to get to work. I have changed some configuration values in the code.
My doubts are the following.
All I am doing for this is copying IBM MQ client jars into the application and using the code to send messages to remote MQ. I have not installed any other application. Will such a system work or should there always be some intermediate program like active MQ?
The same code is able to send and receive from an IBM MQ server which I installed in our local network but fails to get a response from the remote server? This leads me to believe if I am missing anything in configuration ? should anything else be configured other than in code?
I see no errors or exceptions. Always message is sent but the response is null. I have not seen the usage of any username-password or public-private key authentication. Is there any authentication used normally to check the source. ?
I am using IBM MQ client 5.3 version which I know is old. But used that since they working active MQ setup uses the same and is working correctly. I have no way of knowing which version on IBM MQ server is present on the remote machine. Is there a problem if we use a different client MQ version than the version of server MQ version. ?
Sample code which works for me in local environment ie is able to send and receive from an IBM MQ server I have installed in another machine in the local network. The same code will fetch null response when I am trying to use it with remote IBM MQ server.
import javax.jms.*;
import javax.jms.JMSException;
import com.ibm.mq.jms.*;
import com.ibm.jms.JMSMessage;
import javax.jms.TextMessage;
public class SendReceive {
private MQQueueConnectionFactory connectionFactory;
private MQQueueConnection connection;
private void runTest() {
try {
connect();
connection.start();
MQQueueSession session = (MQQueueSession) connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
MQQueue queue = (MQQueue) session.createQueue("INBOUND_QUEUE"); /* values replaced with correct values in deployment server */
MQQueue queue2 = (MQQueue) session.createQueue("OUTBOUND_QUEUE"); /* values replaced with correct values in deployment server */
MQQueueSender sender = (MQQueueSender) session.createSender(queue);
MQQueueReceiver receiver = (MQQueueReceiver) session.createReceiver(queue2);
//TextMessage message = session.createTextMessage("yesyesyes");
String stt = "Test Message"; //
TextMessage message = session.createTextMessage(stt);
message.setJMSReplyTo(queue2);
sender.send(message);
System.out.println("Sent: " + message);
Message msg1 = receiver.receive(5000);
if(msg1!=null){
String responseMsg = ((TextMessage) msg1).getText();
System.out.println("Received: " + responseMsg);
}else{
System.out.println("Message received is null");
}
}catch(Exception e){
System.out.println("Exception caught in program : " + e);
e.printStackTrace();
}
}
public boolean connect() {
boolean connected = false;
try {
/* values below are replaced with correct values in deployment server */
connectionFactory = new MQQueueConnectionFactory();
connectionFactory.setPort(1515);
connectionFactory.setHostName("192.168.1.23"); //
connectionFactory.setQueueManager("QCCMGR");
connectionFactory.setChannel("QCHANNEL");
connectionFactory.setTransportType(JMSC.MQJMS_TP_CLIENT_MQ_TCPIP);
connection = (MQQueueConnection) connectionFactory.createQueueConnection();
connected = true;
} catch (Exception e) {
connected = false;
}
return connected;
}
public static void main(String[] args) {
new SendReceive().runTest();
}
}
MQ v5.3 was released November 29th 2002 and has been out of support since September 28th 2007 (almost 9 years). The version may not have anything to do with your issue but I would strongly suggest that you move to a supported version of the MQ client. Newer MQ client versions can connect to older MQ queue managers. You can download a java only install of MQ 8.0 or MQ 9.0 jar files at the links below:
IBM MQ v8.0 Client
IBM MQ v9.0 Client
I read on some old threads that having the sender and receiver on the same session caused problems when a timeout was specified. Try adding another session for the receiver.
private void runTest() {
try {
connect();
connection.start();
MQQueueSession session = (MQQueueSession) connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
MQQueueSession session2 = (MQQueueSession) connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
MQQueue queue = (MQQueue) session.createQueue("INBOUND_QUEUE"); /* values replaced with correct values in deployment server */
MQQueue queue2 = (MQQueue) session2.createQueue("OUTBOUND_QUEUE"); /* values replaced with correct values in deployment server */
MQQueueSender sender = (MQQueueSender) session.createSender(queue);
MQQueueReceiver receiver = (MQQueueReceiver) session2.createReceiver(queue2);
//TextMessage message = session.createTextMessage("yesyesyes");
String stt = "Test Message"; //
TextMessage message = session.createTextMessage(stt);
message.setJMSReplyTo(queue2);
sender.send(message);
System.out.println("Sent: " + message);
Message msg1 = receiver.receive(5000);
if(msg1!=null){
String responseMsg = ((TextMessage) msg1).getText();
System.out.println("Received: " + responseMsg);
}else{
System.out.println("Message received is null");
}
}catch(Exception e){
System.out.println("Exception caught in program : " + e);
e.printStackTrace();
}
}
Try taking a JMS trace by adding the following to the execution of the java app:
-DMQJMS_TRACE_LEVEL=base
-DMQJMS_TRACE_DIR=/tracedirectory
ex: java -DMQJMS_TRACE_LEVEL=base -DMQJMS_TRACE_DIR=/tracedirectory JavaApp
This should produce a file that I believe ends in .trc in the directory you specify.
You can review this for errors that might help point you in the right direction.
Suggestions:
Try changing your program to force it to send a blank username:
connection = (MQQueueConnection) connectionFactory.createQueueConnection("", "");
Try closing the sender after sender.send is called
sender.close();
With out further information it is difficult to determine the cause. The more information you can gather the better.
It could be some network related configuration issue or maybe Windows Messaging not configured well. You may consider giving WebSphere MQ - Message Test Utility by IBM to ensure that there are no such system or network configuration issues are present.
Currently i'm working on a standalone Java apps that connects to a Websphere MQ to send and receive messages.
The flow is in asynchronous mode, which we implemented using MessageListener class to retrieve the messages from the queue when they are ready. The code to initialize the consumer with the listener is as follow:
if(connection == null)
connection = getJmsConnection();
try {
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
if (isTopic) {
destination = session.createTopic(destinationName);
} else {
destination = session.createQueue(destinationName);
}
consumer = session.createConsumer(destination);
consumer.setMessageListener(listener);
} catch (JMSException e) {
e.printStackTrace();
}
The getJmsConnection() method will return a connection from a pool, implemented using Apache Commons Pool library.
My question is, will the connection assign to the listener from the pool be active and tied to that listener as long as the program is running? Or the connection is used intermittently and can be reuse by other processes? Our idea is to have the sending and receiving process to reuse the connection from the pool, but i'm not sure how the MessageListener deal with the connection they are assigned with.
Thank you.
The key object here is the session rather than the connection; the session is on the one that will be doing the primary work here with the message consumption (async or otherwise).
It is advisable to try and share out the connection as widely as possible. Temporary destinations are scoped on the connection level. So the use of pooling is a good idea; it will be perfectly possible to share that connection around.
However I would also say that it might be worth considering pooling the sessions. With the code here a new session will be created, each time through that code, that will mean a new connection to the WebSphere MQ queue manager will be created. It's not clear what the scope of that will be, but if that is closed quickly it could become a bottleneck.
I have a client that receives messages from a Queue. I currently have a MessageListener that implements onMessage().
Once the message is received, it is processed further then saved to a Database on the onMessage() method; the client then acknowledges the message receipt.
As long as the database is up there is no problem. But if the DB is down, the client will not acknowledge.
To cater for this, I want the client to be sending scheduled requests to the queue for any unacknowledged messages at scheduled intervals.
As it is, the only way I have of doing this is to restart the client which is not Ideal. Is there a way to trigger the queue to resend an unacknowledged message without a restart?
What i have in onMessage():
//code to connect to queue
try {
if (DB is available){
//process message
//save required details to DB
msg.acknowledge();
}
else{
//schedule to request same message later from queue
}
} catch (Exception e) {}
I think the standard behavior is already doing what you want: if the message broker is using the same database and the database is not available, it will not accept the messages and thus the client will spool them until the message broker is ready again.
If they do not share the same database and the message broker is on, it will spool the message and retry if onMessage throws an exception.
The message broker will try to resend according to its configurable policy.
After some more research, I have stumbled on the session.recover() which I can use to trigger redelivery. I have seen there is the RedeliveryPolicy class which I can use to set message resend options. Now my code looks like:
ConnectionFactory factory = new ActiveMQConnectionFactory(url);
RedeliveryPolicy policy = new RedeliveryPolicy();
policy.setBackOffMultiplier((short) 2);
policy.setRedeliveryDelay(30000);
policy.setInitialRedeliveryDelay(60000);
policy.setUseExponentialBackOff(true);
((ActiveMQConnectionFactory)factory).setRedeliveryPolicy(policy);
final Session session = connection.createSession(false,
Session.CLIENT_ACKNOWLEDGE);
...
...
...
..
//inside onMessage()
try {
if (DB is available){
//process message
//save required details to DB
msg.acknowledge();
}
else{
session.recover();
}
} catch (Exception e) {}
I haven't touched any J2EE stuff in years and I need to whip up a quick JMS client for a demo.
I'm using Eclipse, on OS X and I can't even get started because I can't seem to figure out how to get the required libraries.
This is supposed to be a simple stand alone application (not running in a container) that pulls messages from a topic.
Every JMS implementation has its own set of libraries that specify how you get the initial connection factory. If you have an existing server from which to pull messages, you need to examine the documentation of that server to determine where to find the libraries to put in your classpath and how to create your initial connection factory. If you want to create a server for the purposes of the demonstration, I recommend using an embedded Active MQ broker.
Once you have your connection factory, polling for messages from a topic is pretty straightforward. Here is some example code which can be called to drain a topic of its current messages.
// Implementation specific code
public void drainTopic(TopicConnectionFactory factory, String topicName, String subscriberId)
// set factory properties like the server ID
Connection conn = factory.createConnection();
conn.start();
Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic(topicName);
MessageConsumer consumer = session.createDurableSubscriber(topic, subscriberId);
Message message;
while (null != (message = consumer.receive(1000))) {
// do work on the message
}
conn.close();
}
Note the use of a durable subscriber. This means that I don't have to try to maintain a single connection all the time and handle the errors if it times out somehow. But because the subscription is durable, the server knows to retain any messages the topic receives while I'm not connected and provide them on my next connection. This code would be the same regardless of the host OS. The only tricky part is the creation of the provider specific connection factory.