How to initialize initial context in JMS - java

I would like to create a Message queue in a standalone application using JMS Queue. I am not using any kind of container like tomcat and JBoss. What should be the arguments passed to the initial context object.? It s completely a standalone application..
Note: If anybody wishes to give down vote for this question, please give the reason in the comment and give down vote. Thanks!
InitialContext ctx = new InitialContext(?????);
Queue queue = (Queue) ctx.lookup("queue/queue1");
QueueConnectionFactory connFactory = (QueueConnectionFactory) ctx.lookup("queue/connectionFactory");
QueueConnection queueConn = connFactory.createQueueConnection();
QueueSession queueSession = queueConn.createQueueSession(false,Session.AUTO_ACKNOWLEDGE);
QueueSender queueSender = queueSession.createSender(queue);
queueSender.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
TextMessage message = queueSession.createTextMessage("Hello");
queueSender.send(message);
System.out.println("sent: " + message.getText());
queueConn.close();

You can't resolve the connectionFactory via jndi as there are no container to provide it.
You will have to instantiate the connectionFactory yourself providing the necessary (transport) parameters.
As you don't retrieve it from a Java EE container this behavior is not covered by the related JSR and is so provider specific.
below an example using HornetQ :
// Transport parameters
final Map< String, Object > connectionParams = new HashMap< String, Object >();
connectionParams.put(TransportConstants.PORT_PROP_NAME, port);
connectionParams.put(TransportConstants.HOST_PROP_NAME, host);
final TransportConfiguration transportConfiguration = new TransportConfiguration(
NettyConnectorFactory.class.getName(), connectionParams);
// this should be created only once and reused for the whole app lifecycle
connectionFactory = (ConnectionFactory) org.hornetq.api.jms.HornetQJMSClient
.createConnectionFactoryWithoutHA(JMSFactoryType.QUEUE_CF, transportConfiguration);
final jmsQueue = HornetQJMSClient.createQueue(queueName)
try {
// connection is thread safe
Connection connection = null;
// session is not
Session session = null;
connection = connectionFactory.createConnection(user, password);
connection.start();
/* following objects must be propper to a thread (but should be reused if possible) */
// Create a non transacted Session (no XA support outside of Java EE container)
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
final MessageProducer producer = session.createProducer(jmsQueue);
final ObjectMessage objectMessage = session.createObjectMessage();
objectMessage.setObject(myMessageSerializableObject);
producer.send(objectMessage);
}
finally {
// Release resources
try {
if (session != null) {
session.close();
}
if (connection != null) {
connection.close();
}
}
catch (final JMSException e) {
LOG.warn("An error occurs while releasing JMS resources", e);
}
}
Note that connections, sessions and producers should be reused (not created and released for each use but not shared between threads) and ideally pooled.
See https://developer.jboss.org/wiki/ShouldICacheJMSConnectionsAndJMSSessions

Related

How does the MessageListener running in JMS? Can it load messages in the queue in real time?

I want to load the JMS messages in a queue in real time, if is a consumer.setMessageListener(myListener) viable and how it works?
I'm not sure how a listener working. I wrote a listener like below.
public class JmsMessageListenerExample {
public static void main(String[] args) throws URISyntaxException, Exception {
BrokerService broker = BrokerFactory.createBroker(new URI(
"broker:(tcp://localhost:61616)"));
broker.start();
Connection connection = null;
try {
// Producer
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
"tcp://localhost:61616");
connection = connectionFactory.createConnection();
Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue("customerQueue");
String payload = "Important Task";
Message msg = session.createTextMessage(payload);
MessageProducer producer = session.createProducer(queue);
System.out.println("Sending text '" + payload + "'");
producer.send(msg);
// Consumer
MessageConsumer consumer = session.createConsumer(queue);
consumer.setMessageListener(new ConsumerMessageListener("Consumer"));
connection.start();
} finally {
if (connection != null) {
connection.close();
}
broker.stop();
}
}
After I run the JmsMessageListenerExample, it completed quickly and I didn't received any messages. If a listener should keep on running until I stop it?
When you set a JMS message listener it will receive messages asynchronously in its own thread (invoked by the JMS implementation). In your case you need to prevent main from exiting and stopping your application because when that happens the MessageListener will be terminated.
Also, when you say "load the JMS messages in a queue in real time" I assume you mean "consume JMS messages from a queue as soon as possible when queue receives them." If that's the case then a JMS message listener is the right approach.

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 start ActiveMQ when tomcat starts?

How do I configure my J2EE application so that I can invoke ActiveMQ service along with tomcat server? I am aware about embedded broker, here asking how to start the ActiveMQ whenever I start tomcat
Current Code (works fine) :
Now I want to remove main() method and use the code to run when tomcat runs.
public class JMSService {
public void produceJMS() throws NamingException, JMSException {
ConnectionFactory connFactory = new ActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_BROKER_URL);
Connection conn = connFactory.createConnection();
conn.start();
Session session = conn.createSession(false,Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue("testQueue");
MessageProducer producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
TextMessage message = session.createTextMessage("Test Message ");
// send the message
producer.send(message);
System.out.println("sent: " + message);
}}
Here is my consumer :
public class JMSReceiver implements MessageListener,ExceptionListener {
public static void main(String args[]) throws Exception {
JMSReceiver re = new JMSReceiver();
re.receiveJMS();
}
public void receiveJMS() throws NamingException, JMSException {
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_BROKER_URL);
Connection connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
// Getting the queue 'testQueue'
Destination destination = session.createQueue("testQueue");
MessageConsumer consumer = session.createConsumer(destination);
// set an asynchronous message listener
JMSReceiver asyncReceiver = new JMSReceiver();
consumer.setMessageListener(asyncReceiver);
connection.setExceptionListener(asyncReceiver);
}
#Override
public void onMessage(Message message) {
System.out.println("Received message : " +message);
}
}
What #Tim Bish said is correct. You either need to have a timer say for example receiver should listen for 1 hour- or make it available until program terminate. Either case you need to start your consumer program once:
Change your receiveJMS method as follows:
public void receiveJMS() throws NamingException, JMSException {
try{
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_BROKER_URL);
Connection connection = connectionFactory.createConnection();
connection.start(); // it's the start point
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
// Getting the queue 'testQueue'
Destination destination = session.createQueue("testQueue");
MessageConsumer consumer = session.createConsumer(destination);
// set an asynchronous message listener
// JMSReceiver asyncReceiver = new JMSReceiver();
//no need to create another object
consumer.setMessageListener(this);
connection.setExceptionListener(this);
// connection.close(); once this is closed consumer no longer active
Thread.sleep(60 *60 * 1000); // receive messages for 1 hour
}finally{
connection.close();// after 1 hour close it
}
}
The above program will listen upto 1 hour. If you want it as long as the program run, remove the finally block. But the recommended way is to close it somehow. since your application seems to be standalone ,you can check the java runtime shutdown hook, where you can specify how to release such resources while program terminates.
If your consumer is a web application you can close it in a ServletContextlistner.
You aren't giving the consumer application any time to actually receive a message, you create it, then you close it. You either need to use a timed receive call to do an sync receive of the message from the Queue or you need to add some sort of wait in the main method such as a CountDownLatch etc to allow the async onMessage call to trigger shutdown once processing of the message is complete.

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.

Java WeakReferences = Understandingproblem (with HornetQ JMS Implementation)?

The code below does NOT work:
Cause:
I assume I tracked down the cause to:
http://community.jboss.org/thread/150988
=> This article says that HornetQ uses Weak References.
My Question:
Why does the code not run? (I have this code running with a slight different implementation, but the code blow fails repeatedly). My only guess is, that the
following references:
private Connection connection = null;
private Session session = null;
private MessageProducer producer = null;
are not regarded as strong references? (And this leads to the fact that the garbage collector removes the objects... But way arent they strong references?
Or is there another problem with the code (as said the code runs fine if I copy everything into one single method. But if I use the Singleton approach below the code does not work...) Another assumption was that it might have to do with ThreadLocal stuff, but I am using only a single thread...
The Code not working (stripped down):
public class JMSMessageSenderTest {
private static final Logger logger = Logger.getLogger(JMSMessageSenderTest.class);
private static JMSMessageSenderTest instance;
private Connection connection = null;
private Session session = null;
private MessageProducer producer = null;
private JMSMessageSenderTest() {
super();
}
public static JMSMessageSenderTest getInstance() throws JMSException {
if (instance==null) {
synchronized(JMSMessageSenderTest.class) {
if (instance==null) {
JMSMessageSenderTest instanceTmp = new JMSMessageSenderTest();
instanceTmp.initializeJMSConnectionFactory();
instance = instanceTmp;
}
} }
return instance;
}
private void createConnectionSessionQueueProducer() throws Exception {
try {
Queue queue = HornetQJMSClient.createQueue("testQueue");
connection = initializeJMSConnectionFactory();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
producer = session.createProducer(queue);
connection.start();
} catch (Exception e) {
cleanupAfterError();
throw e;
}
}
private void cleanupAfterError() {
if (connection != null){
try{
connection.close();
}catch(JMSException jmse) {
logger.error("Closing JMS Connection Failed",jmse);
}
}
session = null;
producer = null;
}
public synchronized void sendRequest(String url) throws Exception {
if (connection==null) {
createConnectionSessionQueueProducer();
}
try {
//HERE THE EXCEPTION IS THROWN, at least when debugging
TextMessage textMessage = session.createTextMessage(url);
producer.send(textMessage);
} catch (Exception e) {
cleanupAfterError();
throw e;
}
}
private Connection initializeJMSConnectionFactory() throws JMSException{
Configuration configuration = ConfigurationFactory.getConfiguration(null, null);
Map<String, Object> connectionParams = new HashMap<String, Object>();
connectionParams.put(org.hornetq.core.remoting.impl.netty.TransportConstants.PORT_PROP_NAME, 5445);
connectionParams.put(org.hornetq.core.remoting.impl.netty.TransportConstants.HOST_PROP_NAME, "localhost");
TransportConfiguration transportConfiguration = new TransportConfiguration(NettyConnectorFactory.class.getName(), connectionParams);
ConnectionFactory connectionFactory = (ConnectionFactory) HornetQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, transportConfiguration);
// return connectionFactory.createConnection(login, password);
return connectionFactory.createConnection();
}
/**
* Orderly shutdown of all resources.
*/
public void shutdown() {
cleanupAfterError();
}
}
TestCode to run the code above
JMSMessageSenderTest jmsMessageSender = JMSMessageSenderTest.getInstance();
jmsMessageSender.sendRequest("www.example.com)");
jmsMessageSender.shutdown();
Gives the following error:
I'm closing a JMS connection you left open. Please make sure you close all JMS connections explicitly before letting them go out of scope!
The JMS connection you didn't close was created here:
java.lang.Exception
at org.hornetq.jms.client.HornetQConnection.<init>(HornetQConnection.java:152)
at org.hornetq.jms.client.HornetQConnectionFactory.createConnectionInternal(HornetQConnectionFactory.java:662)
at org.hornetq.jms.client.HornetQConnectionFactory.createConnection(HornetQConnectionFactory.java:121)
Solution:
1.) You also have to Keep a reference to the ConnectionFactory (see the answer from Clebert below)
private ConnectionFactory factory = null;
2.) AND this code contains a severe hidden bug (that is not so easy to spot):
I initialized the Connection in the Constructor as well as in the createConnectionSessionQueueProducer() method. It will therefore override the old value and (as it is a Ressource that needs to be closed) will lead to a stale connection that HornetQ then will close and will then throw the error.
Thanks very very much! Markus
HornetQ will close the connection factory when the connection factory is released.
You need to hold a reference for the connection factory.
I also have similar issues. But it is not supposed to crash . Your implementation looks good. But only thing is that you are not closing the JMS connection , which in turn is getting closed by the hornetQ gc.
One thing probably wrong with the code is that you are calling cleanupAfterError() only after an exception. You should call the same method also after you have posted a message and a JMS connection is lying idle . Since you are just opening a connection to post a message and then not closing that connection unless an exception happens , Hornetq GC is finding that object and removing it while throwing this error.
Let me know if I missed something

Categories