I have a consumer Java app which connects to an Apache ActiveMQ server. It's working. However, if I stop the Apache ActiveMQ server the consumer app has an exception:
java.net.SocketException: Connection reset
How can I handle this Exception, for example I'd like to send an alert e-mail to support. How can I detect offline ActiveMQ server.
Here is the exception details
// Getting JMS connection from the server
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(this.activeMqClient.getUsername(), this.activeMqClient.getPassword(), this.activeMqClient.getProducerUri());
activeMQConnectionFactory.setUseAsyncSend(false);
activeMQConnectionFactory.setMaxThreadPoolSize(1);
this.activeMqClient.setClientId(activeMqClient.getClientType() + "_" + Thread.currentThread().getName());
if (this.activeMqClient.getClientId() != null) {
activeMQConnectionFactory.setClientID(this.activeMqClient.getClientId());
}
Connection connection = activeMQConnectionFactory.createConnection();
if (this.activeMqClient.getClientId() != null) {
connection.setClientID(this.activeMqClient.getClientId());
}
connection.start();
connection.setExceptionListener(this);
// Creating session for receiving messages
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
// Getting the queue
Destination destination = session.createQueue(this.activeMqClient.getDestinationQueueName() + "?consumer.exclusive=true");
// MessageConsumer is used for receiving (consuming) messages
MessageConsumer consumer = session.createConsumer(destination);
//Setting message listener
consumer.setMessageListener(this);
You can catch it like any other exception:
try {
//... client code ...//
}
catch(SocketException e) {
//... send email ...//
}
Related
I am using below code for connecting to JMS.I cannot create a connection factory because in PROD env, I am just a consumer and not aware which server it is installed. I have the broker URL,Username and Password.
public class HelloWorldProducer implements Runnable {
public void run() {
try {
// Create a ConnectionFactory
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("id972483","octitt123","tcp://ozoi6000:2506");
// 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.createQueue("gw.oct.request.letterbusinesscommunication.v1.in.q");
// Create a MessageProducer from the Session to the Topic or Queue
MessageProducer producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
// Create a messages
//String text = "Hello world! From: " + Thread.currentThread().getName() + " : " + this.hashCode();
TextMessage message = session.createTextMessage(getXMLdata());
message.setJMSCorrelationID("Sample_JMS_Test");
// Tell the producer to send the message
System.out.println("Sent message: "+ message.hashCode() + " : " + Thread.currentThread().getName());
producer.send(message);
// Clean up
session.close();
connection.close();
}
catch (Exception e) {
System.out.println("Caught: " + e);
e.printStackTrace();
}
}
I am getting the error like below:
Caught: javax.jms.JMSException: Disposed due to prior exception
javax.jms.JMSException: Disposed due to prior exception
at org.apache.activemq.util.JMSExceptionSupport.create(JMSExceptionSupport.java:72)
at org.apache.activemq.ActiveMQConnection.syncSendPacket(ActiveMQConnection.java:1413)
at org.apache.activemq.ActiveMQConnection.ensureConnectionInfoSent(ActiveMQConnection.java:1478)
at org.apache.activemq.ActiveMQConnection.start(ActiveMQConnection.java:527)
at HelloWorldProducer.run(HelloWorldProducer.java:25)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.activemq.transport.TransportDisposedIOException: Disposed due to prior exception
at org.apache.activemq.transport.ResponseCorrelator.onException(ResponseCorrelator.java:125)
at org.apache.activemq.transport.TransportFilter.onException(TransportFilter.java:114)
at org.apache.activemq.transport.TransportFilter.onException(TransportFilter.java:114)
at org.apache.activemq.transport.WireFormatNegotiator.onException(WireFormatNegotiator.java:173)
at org.apache.activemq.transport.AbstractInactivityMonitor.onException(AbstractInactivityMonitor.java:344)
at org.apache.activemq.transport.TransportSupport.onException(TransportSupport.java:96)
at org.apache.activemq.transport.tcp.TcpTransport.run(TcpTransport.java:219)
... 1 more
Caused by: java.io.IOException: Unknown data type: -1
at org.apache.activemq.openwire.OpenWireFormat.doUnmarshal(OpenWireFormat.java:359)
at org.apache.activemq.openwire.OpenWireFormat.unmarshal(OpenWireFormat.java:278)
at org.apache.activemq.transport.tcp.TcpTransport.readCommand(TcpTransport.java:240)
at org.apache.activemq.transport.tcp.TcpTransport.doRun(TcpTransport.java:232)
at org.apache.activemq.transport.tcp.TcpTransport.run(TcpTransport.java:215)
... 1 more
What is configured on the port you are trying to connect to? You see these sorts of error when trying to connect the JMS client to a port that servicing a protocol other than the OpenWire protocol that the ActiveMQ JMS client speaks.
When getting errors like this it is usually a good idea to ask what the broker is actually configured to do
I am using an embedded ActiveMQ broker.
My goal is to find a way to detect when an external producer on a Queue lost it's connection.
I am starting the broker like this:
BrokerService broker = new BrokerService();
broker.addConnector("tcp://" + LISTEN_DEVICE_IP + ":" + port);
setLastMessagesPersistent(broker);
broker.start();
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("vm://localhost");
connection = factory.createConnection();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
connection.start();
And after that I tried to add a TransportListener:
((ActiveMQConnection) connection).addTransportListener(new TransportListener() {
public void transportResumed() {
System.out.println("resumed");
}
public void transportInterupted() {
System.out.println("interrupted");
}
public void onException(IOException arg0) {
System.out.println("ioexception: " + arg0);
}
public void onCommand(Object arg0) {
System.out.println("command: " + arg0);
}
});
I also register a consumer and ProducerListener like this:
Destination dest = session.createQueue(queuename);
MessageConsumer consumer = session.createConsumer(dest);
ProducerEventSource source = new ProducerEventSource(connection, dest);
System.out.println("Setting Producer Listener");
source.setProducerListener(prodevent -> {
System.out.println("producer status: " + prodevent.isStarted());
});
// Gets called from inside the broker's Thread and somehow causes deadlocks if I don't invoke this from the outside
new Thread(() -> {
try {
consumer.setMessageListener(new NetworkEventPlayerAdapter(objectMapper, event, gameEventManager, playerID));
} catch (Exception e) {
e.printStackTrace();
}
}).start();
Unfortunately neither the TransportListener, nor the ProducerListener give me any output when I forcefully quit another application that previously was added as a producer (Alt+F4). The broker surely notices though:
WARN | Transport Connection to: tcp://127.0.0.1:58988 failed: java.net.SocketException: Connection reset
WARN | Transport Connection to: tcp://127.0.0.1:58986 failed: java.net.SocketException: Connection reset
But I don't find a way to get a callback on those events in Java.
I also tried setting a custom IOExceptionHandler in the broker and adding an ExceptionListener to the connection. They also get never called.
You can use The Advisory Topics ActiveMQ.Advisory.Connection or even the ActiveMQ.Advisory.Producer.Queue ActiveMQ.Advisory.Producer.Topic , these provide the stats on connections of number of producers , check this link http://activemq.apache.org/advisory-message.html
a possible way is to parse the log-output for Connection reset
WARN | Transport Connection to: tcp://127.0.0.1:58988 failed:
java.net.SocketException: Connection reset
WARN | Transport
Connection to: tcp://127.0.0.1:58986 failed: java.net.SocketException:
Connection reset
Because the socket is implemented in activemq you would have to add the ExceptionListener there to write your own exception handling routine ...
I'm using jbossall-client jar for JMS and I'm new to messaging. Whenever I try to browse the queue to which I send a message (its an object message), always I'm getting 'false' on my qBrowser.getEnumeration().hasMoreElements();
This is how I create the connection:
public void initialize() throws Exception {
try {
InitialContext initialContext = new InitialContext(contextProperties);
connectionFactory = (QueueConnectionFactory) initialContext.lookup(connectionFactoryName);
queue = (Queue) initialContext.lookup("queue/" + queueName);
initialContext.close();
} catch (NamingException e) {
throw new Exception("Error initializing enqueuer for " + queueName, e);
}
}
public MyQueueConnection openQueueConnection() throws JMSException {
QueueConnection connection = null;
try {
connection = connectionFactory.createQueueConnection();
connection.start();
QueueSession session = connection.createQueueSession(true, QueueSession.DUPS_OK_ACKNOWLEDGE);
QueueSender sender = session.createSender(queue);
sender.setDeliveryMode(DeliveryMode.PERSISTENT);
return new MyQueueConnection(connection, session, sender);
} catch (JMSException e) {
throw e;
}
}
Do I need to configure anything with QueueConnection/QueueSession/QueueSender or something else to browse the messages in a queue? Is it something I need to configure in jboss properties? (I do this in a singleton-MDB; this project is a spring framework project)
Please advise; thanks in advance.
Just a suggestion for another one.
I used hornetQ
Please check you created QueueReceiver createReceiver() after getEnumeration() is called.
Make sure you start connection connection.start()
Check the link for bug
Check the custom size
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.
EDIT: Rephrased the question:
I want to use ActiveMQ as a messenger service between my server and client applications.
I am trying to set up an embedded broker (i.e. not a separate process) within the server to handle the produced messages for my clients to consume. This queue is persisted.
The broker initialisation as follows:
BrokerService broker = new BrokerService();
KahaPersistenceAdapter adaptor = new KahaPersistenceAdapter();
adaptor.setDirectory(new File("activemq"));
broker.setPersistenceAdapter(adaptor);
broker.setUseJmx(true);
broker.addConnector("tcp://localhost:61616");
broker.start();
After tinkering, I ended up with the server part being:
public static class HelloWorldProducer implements Runnable {
public void run() {
try {
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost"); // apparently the vm part is all i need
Connection connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue("TEST.FOO");
MessageProducer producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
String text = "Hello world! From: " + Thread.currentThread().getName() + " : " + this.hashCode();
TextMessage message = session.createTextMessage(text);
System.out.println("Sent message: "+ message.hashCode() + " : " + Thread.currentThread().getName());
producer.send(message);
session.close();
connection.close();
}
catch (Exception e) {
System.out.println("Caught: " + e);
e.printStackTrace();
}
}
}
The client is very similar and looks like this:
public static class HelloWorldConsumer implements Runnable, ExceptionListener {
public void run() {
try {
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost");
Connection connection = connectionFactory.createConnection(); // exception happens here...
connection.start();
connection.setExceptionListener(this);
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue("TEST.FOO");
MessageConsumer consumer = session.createConsumer(destination);
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 obj: " + message);
}
consumer.close();
session.close();
connection.close();
} catch (Exception e) {
System.out.println("Caught: " + e);
e.printStackTrace();
}
}
The main method simply starts each of these in a thread to start producing/receiving messages.
...but I am running into the following with the start of each thread:
2013-01-24 07:54:31,271 INFO [org.apache.activemq.broker.BrokerService] Using Persistence Adapter: AMQPersistenceAdapter(activemq-data/localhost)
2013-01-24 07:54:31,281 INFO [org.apache.activemq.store.amq.AMQPersistenceAdapter] AMQStore starting using directory: activemq-data/localhost
2013-01-24 07:54:31,302 INFO [org.apache.activemq.kaha.impl.KahaStore] Kaha Store using data directory activemq-data/localhost/kr-store/state
2013-01-24 07:54:31,339 INFO [org.apache.activemq.store.amq.AMQPersistenceAdapter] Active data files: []
2013-01-24 07:54:31,445 DEBUG [org.apache.activemq.broker.jmx.ManagementContext] Probably not using JRE 1.4: mx4j.tools.naming.NamingService
2013-01-24 07:54:31,450 DEBUG [org.apache.activemq.broker.jmx.ManagementContext] Failed to create local registry
java.rmi.server.ExportException: internal error: ObjID already in use
at sun.rmi.transport.ObjectTable.putTarget(ObjectTable.java:186)
at sun.rmi.transport.Transport.exportObject(Transport.java:92)
at sun.rmi.transport.tcp.TCPTransport.exportObject(TCPTransport.java:247)
at sun.rmi.transport.tcp.TCPEndpoint.exportObject(TCPEndpoint.java:411)
at sun.rmi.transport.LiveRef.exportObject(LiveRef.java:147)
<snip....>
It seems like the messages are produced and consumed successfully (the other issues I previously posted about was resolved), but the above exception is worrying me.
EDIT: During broker shutdown, I am now also greeted by the following:
2013-01-25 08:40:17,486 DEBUG [org.apache.activemq.transport.failover.FailoverTransport] Transport failed with the following exception:
java.io.EOFException
at java.io.DataInputStream.readInt(DataInputStream.java:392)
at org.apache.activemq.openwire.OpenWireFormat.unmarshal(OpenWireFormat.java:269)
at org.apache.activemq.transport.tcp.TcpTransport.readCommand(TcpTransport.java:210)
at org.apache.activemq.transport.tcp.TcpTransport.doRun(TcpTransport.java:202)
at org.apache.activemq.transport.tcp.TcpTransport.run(TcpTransport.java:185)
at java.lang.Thread.run(Thread.java:722)
You can embed a broker into your code in a number of ways, much of which is documented here. You may want to try upgrading you version since what you are using appears to be quite old as it defaulting to the now deprecated AMQ Store instead of the newer KahaDB store. You might be having issues because of a race between the client threads as they use the different connection factories which could race to create in VM brokers. If you set the create=false option on the producer and ensure the consumer thread starts after that could address the issue, or you could create the VM broker ahead of time and the add create=false to both thread's and that might do the trick.
BrokerService broker = new BrokerService();
// configure the broker
broker.setBrokerName("localhost");
broker.setUseJmx(false);
broker.start();
And then in the client code just attach via this connection factory configuration.
ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("vm://localhost?create=false");
When I run your code, I got the below exception:
javax.jms.JMSException: Could not connect to broker URL: tcp://localhost.
Reason java.lang.IllegalArgumentException: port out of range:-1
Your broker is running and listening to port 61616, so any client which tries to connect to broker need to have the port in its URL.
The client code tries to connect to localhost but doesn't mention the port to which it has to connect.
Both the producer and consumer code needs to be fixed.
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost");
To
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
After fixing the port, I was able to run your code.