In the jboss admin-console page I can view the current number of items in my queue.
However I'm getting empty enumeration from queueBrowser.getEnumeration().
Below is my code to browse the queue:
public class JMSQueueBrowser {
private final Log log = LogFactory.getLog(getClass());
private QueueConnectionFactory connectionFactory;
private Queue queue;
private QueueBrowser qBrowser;
private QueueSession qSession;
private QueueConnection qConn;
public JMSQueueBrowser() {
initialize();
}
private void initialize() {
try {
InitialContext initialContext = new InitialContext();
connectionFactory = (QueueConnectionFactory)initialContext.lookup("java:comp/env/jms/MyQCF");
queue = (Queue)initialContext.lookup("queue/sampleQueue");
qConn = (QueueConnection) connectionFactory.createConnection();
qConn.start();
qSession = qConn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
qBrowser = qSession.createBrowser(queue);
initialContext.close();
} catch (NamingException e) {
log.error(e.getMessage());
} catch (JMSException e) {
log.error(e.getMessage());
}
}
public void browseQueue() {
try {
log.info("---------Queue Name: "+queue.getQueueName()+"-----------");
log.info("---------Queue Has Elements: "+qBrowser.getEnumeration().hasMoreElements()+"-----------");
} catch (JMSException e) {
log.error(e.getMessage());
}
}}
The log is always being the same as following:
INFO JMSQueueBrowser - ---------Queue Name: sampleQueue-----------
INFO JMSQueueBrowser - ---------Queue Has Elements: false----------
The library used for JMS Queue is jbossall-client.jar.
Any answer will be appreciated. Thanks in advance.
Related
I have an application that queues and deques messages from Oracle AQ using the JMS interface. When the application is running items get queued and dequeued and I can see queued items in the queue table. However, one the application shuts down the queue table is cleared and the application cannot access the previously queued items. Any idea what might cause that behavior?
The Oracle AQ is created using this code:
BEGIN
dbms_aqadm.create_queue_table(
queue_table => 'schema.my_queuetable',
sort_list =>'priority,enq_time',
comment => 'Queue table to hold my data',
multiple_consumers => FALSE, -- THis is necessary so that a message is only processed by a single consumer
queue_payload_type => 'SYS.AQ$_JMS_OBJECT_MESSAGE',
compatible => '10.0.0',
storage_clause => 'TABLESPACE LGQUEUE_IRM01');
END;
/
BEGIN
dbms_aqadm.create_queue (
queue_name => 'schema.my_queue',
queue_table => 'schema.my_queuetable');
END;
/
BEGIN
dbms_aqadm.start_queue(queue_name=>'schema.my_queue');
END;
/
I also have a Java class for connecting to the queue, queueing items and processing dequeued items like this:
public class MyOperationsQueueImpl implements MyOperationsQueue {
private static final Log LOGGER = LogFactory.getLog(MyOperationsQueueImpl.class);
private final QueueConnection queueConnection;
private final QueueSession producerQueueSession;
private final QueueSession consumerQueueSession;
private final String queueName;
private final QueueSender queueSender;
private final QueueReceiver queueReceiver;
private MyOperationsQueue.MyOperationEventReceiver eventReceiver;
public MyOperationsQueueImpl(DBUtils dbUtils, String queueName) throws MyException {
this.eventReceiver = null;
this.queueName = queueName;
try {
DataSource ds = dbUtils.getDataSource();
QueueConnectionFactory connectionFactory = AQjmsFactory.getQueueConnectionFactory(ds);
this.queueConnection = connectionFactory.createQueueConnection();
// We create separate producer and consumer sessions because that is what is recommended by the docs
// See: https://docs.oracle.com/javaee/6/api/javax/jms/Session.html
this.producerQueueSession = this.queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
this.consumerQueueSession = this.queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
this.queueSender = this.producerQueueSession.createSender(this.producerQueueSession.createQueue(this.queueName));
this.queueReceiver = this.consumerQueueSession.createReceiver(this.consumerQueueSession.createQueue(this.queueName));
this.queueConnection.start();
} catch (JMSException| NamingException exception) {
throw new MyOperationException("Failed to create MyOperationsQueue", exception);
}
}
#Override
protected void finalize() throws Throwable {
this.queueReceiver.close();
this.queueSender.close();
this.consumerQueueSession.close();
this.producerQueueSession.close();
this.queueConnection.close();
super.finalize();
}
#Override
public void submitMyOperation(MyOperationParameters myParameters) throws MyOperationException {
try {
ObjectMessage message = this.producerQueueSession.createObjectMessage(myParameters);
this.queueSender.send(message);
synchronized (this) {
if(this.eventReceiver != null) {
this.eventReceiver.onOperationSubmitted(message.getJMSMessageID(), myParameters);
}
}
} catch (JMSException exc) {
throw new MyOperationException("Failed to submit my operation", exc);
}
}
#Override
public void setMyOperationEventReceiver(MyOperationEventReceiver operationReceiver) throws MyOperationException {
LOGGER.debug("Setting my operation event receiver");
synchronized (this) {
if(this.eventReceiver != null) {
throw new IllegalStateException("Cannot set an operation event receiver if it is already set");
}
this.eventReceiver = operationReceiver;
try {
this.queueReceiver.setMessageListener(message -> {
LOGGER.debug("New message received from queue receiver");
try {
ObjectMessage objectMessage = (ObjectMessage) message;
eventReceiver.onOperationReady(message.getJMSMessageID(), (MyOperationParameters) objectMessage.getObject());
} catch (Exception exception) {
try {
eventReceiver.onOperationRetrievalFailed(message.getJMSMessageID(), exception);
} catch (JMSException innerException) {
LOGGER.error("Failed to get message ID for JMS Message: "+message, innerException);
}
}
});
} catch (JMSException exc) {
throw new MyOperationException("Failed to set My message listener", exc);
}
}
}
}
I have a Java service which is getting messages from an Oracle Advanced Queue. I can create the connection and listen and get messages OK. I can see that you can stop and start listening for messages, so I have implemented controls for that. However, I would like to be able to report on the current status of the listener. I can see if it's there, but how can I tell if it's stopped or started?
I have a container class along the lines of (Listener is my own class (implementing both MessageListener and ExceptionListener) which actually does something with the message)
public class QueueContainer {
private static final String QUEUE_NAME = "foo";
private final Connection dbConnection;
private final QueueConnection queueConnection;
private final QueueSession queueSession;
private final Queue queue;
private final MessageConsumer consumer;
private final Listener listener;
public QueueContainer(final Connection dbConnection ) {
try {
this.dbConnection = dbConnection;
queueConnection = AQjmsQueueConnectionFactory.createQueueConnection(dbConnection);
queueSession = queueConnection.createQueueSession(false, Session.CLIENT_ACKNOWLEDGE);
queue = ((AQjmsSession) queueSession).getQueue(context.getEnvironment(), QUEUE_NAME);
consumer = queueSession.createConsumer(queue);
listener = new Listener(QUEUE_NAME);
consumer.setMessageListener(listener);
queueConnection.setExceptionListener(listener);
} catch (JMSException | SQLException e) {
throw new RunTimeException("Queue Exception", e);
}
}
public void startListening() {
try {
queueConnection.start();
} catch (JMSException e) {
throw new RunTimeException("Failed to start listening to queue", e);
}
}
public void stopListening() {
try {
queueConnection.stop();
} catch (JMSException e) {
throw new RunTimeException("Failed to stop listening to queue", e);
}
}
public void close() {
if (queueConnection != null) {
try {
queueConnection.close();
} catch (JMSException e) {
throw new RunTimeException("Failed to stop listening to queue", e);
}
}
}
public boolean isRunning() {
try {
// This doesn't work - I can't distinguish between started and stopped
return queueConnection.getClientID() != null;
} catch (JMSException e) {
LOGGER.warn("Failed to get queue client ID", e);
return false;
}
}
I can't see what to put in isRunning that could distinguish between a stopped and started listener
The JMS API assumes you know yourself what you did. So why not add a boolean flag and keep track of this ?
private volatile boolean isListening = false;
...
public void startListening() {
try {
queueConnection.start();
isListening = true;
} catch (JMSException e) {
throw new RunTimeException("Failed to start listening to queue", e);
}
}
public void stopListening() {
try {
queueConnection.stop();
isListening = false;
} catch (JMSException e) {
throw new RunTimeException("Failed to stop listening to queue", e);
}
}
public void close() {
if (queueConnection != null) {
try {
queueConnection.close();
isListening = false;
} catch (JMSException e) {
throw new RunTimeException("Failed to stop listening to queue", e);
}
}
}
public boolean isRunning() {
return isListening;
}
There is no JMS API call to determine whether or not a javax.jms.Connection is started.
To be clear, the queue itself is not the entity that is started or stopped. The connection is started or stopped.
You may be able to get this information from the Oracle Advanced Queue implementation object, but I'm not familiar with that implementation so I can't say. Obviously any solution using an implementation object rather than the standard API will not be portable.
I am trying to use Apache Qpid through Spring Boot application using Jms Qpid client. I am able to configure it but when I am trying to receive message from the queue, the logger is printing:
Dispatcher(918480905)Received a message(878303980)[1] from queue 1 )without a handler - rejecting(requeue)...
Here is my code:
JmsConfiguration.java
#Configuration
public class JmsConfiguration {
#Primary
#Bean
public Context createContext()
{
Properties properties=new Properties();
System.setProperty("IMMEDIATE_PREFETCH", "true");
Context context=null;
try {
properties.load(this.getClass().getResourceAsStream("application.properties"));
context = new InitialContext(properties);
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return context;
}
#Primary
#Bean
public ConnectionFactory createConnectionFactory(Context context)
{
ConnectionFactory connectionFactory=null;
try {
connectionFactory = (ConnectionFactory) context.lookup("qpidConnectionFactory");
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return connectionFactory;
}
#Primary
#Bean
public Connection jmsConnection(ConnectionFactory connectionFactory) throws Exception
{
Connection connection = connectionFactory.createConnection();
connection.start();
return connection;
}
#Primary
#Bean
public Queue jmsQueue(Context context) throws Exception
{
Queue queue = (Queue) context.lookup("myqueue");
return queue;
}
}
application.properties
java.naming.factory.initial = org.apache.qpid.jndi.PropertiesFileInitialContextFactory
connectionfactory.qpidConnectionFactory = amqp://guest:guest#clientid/?brokerlist='tcp://localhost:5672?maxprefetch='0''
queue.myqueue = queue1
ScheduledTask.java It just run send and receive messages in intervals.
#Component
public class ScheduledTasks
{
Connection connection;
Queue queue;
#Autowired
public ScheduledTasks(Connection connection, Queue queue) {
this.connection=connection;
this.queue=queue;
}
MessageListener messageListener = new MessageListener() {
#Override
public void onMessage(Message message) {
System.out.println("Received id is------>");
System.out.println(message);
}
};
#Scheduled(fixedDelay = 2000)
public void sendMessage() throws Exception
{
Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
Message message=session.createTextMessage();
MessageProducer messageProducer=session.createProducer(queue);
message.setStringProperty("value", "BOOM");
messageProducer.send(message);
session.commit();
messageProducer.close();
//connection.close();
System.out.println("---------------Message Sent");
}
//#JmsListener(destination="queue1")
#Scheduled(initialDelay=5000, fixedDelay = 5000)
public void receiveMessage() throws Exception
{
Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
MessageConsumer messageConsumer = session.createConsumer(queue);
// if(messageConsumer.getMessageListener()==null)
// messageConsumer.setMessageListener(messageListener);
Message message = messageConsumer.receive(3000);
if(message!=null)
System.out.println("----------------->"+message.getStringProperty("value"));
session.commit();
messageConsumer.close();
//connection.close();
System.out.println("--------------->Got Message");
}
}
You create an instance implementing MessageListener but you don't do anything with it.
In Spring you should use DefaultMessageListenerContainer or SimpleMessageListenerContainer from spring-jms and create it as a Spring Bean in the JmsConfiguration class. After setting connection details (ConnectionFactory, Queue, sessionTransacted etc.) you also need to set the JMS MessageListener implementing class.
My application needs to monitor multiple JMS queue's.
How should this be done?
Start 2 threads?
Can 2 queues be monitored at the same time?
Sample code for one queue:
...
queue1 = session.createQueue("queue-1");
consumer = session.createConsumer(queue1);
connection.start();
while (true) {
Message m = consumer.receive(10000);
if (m == null) {
...nothing...
} else {
...do something with the message...
}
}
...
How should I watch queue-1 and queue-2?
You could use quartz scheduler Quartz Scheduler for this. Implement one (or more) quartz job(s) like this:
public class MessageReaderJob1 implements Job {
private QueueReader1 qr;
#Override
public synchronized void execute(JobExecutionContext arg0) throws JobExecutionException {
qr = QueueReader1.getInstance();
try {
Message message = qr.getConsumer().receiveNoWait();
....
}
}
Then you will need a scheduler that you will run from your application (main method or servlet), note that you can implement a different trigger for the second queue also:
public class TestCasesSchedule {
private Scheduler scheduler;
public void createSchedule() {
JobDetail job1 = JobBuilder.newJob(MessageReaderJob1.class)
.withIdentity("jobname", Scheduler.DEFAULT_GROUP)
.build();
JobDetail job2 = JobBuilder.newJob(MessageReaderJob2.class)
.withIdentity("jobname", Scheduler.DEFAULT_GROUP)
.build();
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("minutestrigger", "triggergroup")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInMinutes(5)
.repeatForever())
.build();
try {
SchedulerFactory sf = new StdSchedulerFactory();
scheduler = sf.getScheduler();
scheduler.start();
scheduler.scheduleJob(job1, trigger);
scheduler.scheduleJob(job2, trigger);
} catch (SchedulerException se) {
System.err.println(se.getMessage())
}
}
QueueReader for one of your queue's would look like this:
public class QueueReader1 {
private MessageConsumer consumer = null;
private Context jndiContext = null;
private QueueConnectionFactory queueConnectionFactory = null;
private QueueConnection queueConnection = null;
private QueueSession queueSession = null;
private Queue queue = null;
private static final QueueReader instance = new QueueReader();
public synchronized static QueueReader getInstance() {
return instance;
}
private QueueReader() {
/*
* Create a JNDI API InitialContext object if none exists
* yet.
*/
try {
jndiContext = new InitialContext();
} catch (NamingException e) {
System.err.println(e.getMessage())
System.exit(1);
}
/*
* Look up connection factory and queue. If either does
* not exist, exit.
*/
try {
queueConnectionFactory = (QueueConnectionFactory) jndiContext.lookup("connection_factory_name");
queue = (Queue) jndiContext.lookup("queue_name");
queueConnection =
queueConnectionFactory.createQueueConnection();
queueSession =
queueConnection.createQueueSession(false,
Session.AUTO_ACKNOWLEDGE);
consumer = queueSession.createConsumer(queue);
queueConnection.start();
} catch (JMSException ex) {
System.err.println(ex.getMessage());
} catch (NamingException e) {
System.err.println(e.getMessage());
}
}
}
This is my solution. It works. Any extra advise is welcome!
Main class:
public class Notifier {
public static void main(String[] args) throws Exception {
// Start a thread for each JMQ queue to monitor.
DestinationThread destination1 = new DestinationThread("queue1");
DestinationThread destination2 = new DestinationThread("queue2");
destination1.start();
destination2.start();
}
}
The Thread:
public class DestinationThread extends Thread {
private String destinationQueue;
private static ActiveMQConnectionFactory connectionFactory = null;
private static Connection connection = null;
private static Session session = null;
private static Destination destination = null;
private static MessageConsumer consumer = null;
public DestinationThread(String destinationQueue) {
this.destinationQueue = destinationQueue;
}
#Override
public void run() {
try {
initializeThread(destinationQueue);
startThread(destinationQueue);
} catch (Exception e) {
//TODO
}
}
private void initializeThread(String destinationQueue) {
boolean connectionMade = false;
while (!connectionMade) {
try {
connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
connection = connectionFactory.createConnection();
connection.start();
session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
destination = session.createQueue(destinationQueue);
consumer = session.createConsumer(destination);
connectionMade = true;
} catch (JMSException e) {
//TODO
try {
Thread.sleep(30000);
} catch (InterruptedException ie) {
}
}
}
}
private void startThreadOther(String destinationQueue) throws Exception {
while (true) {
try {
Message message = consumer.receive(300000);
if (message == null) {
//No message received for 5 minutes - Re-initializing the connection
initializeThread(destinationQueue);
} else if (message instanceof TextMessage) {
if (destinationQueue.equals("queue1") {
//Message received from queue1 - do something with it
} else if (destinationQueue.equals("queue2") {
//Message received from queue2 - do something with it
} else {
//nothing
}
} else {
//nothing
}
} catch (Exception e) {
//TODO
}
}
}
}
I have a Glassfish 3.1.2 server running on a remote machine (JDK 1.6.0_30). The following code is the stand-alone client running in a Java SE environment, connecting to the JMS using a JNDI lookup. The client is publisher and subscriber at the same time.
I created the JMS connection pool and topic as follows:
./asadmin create-jms-resource --restype javax.jms.ConnectionFactory jms/TopicConnectionFactory
./asadmin create-jms-resource --restype javax.jms.Topic jms/TopicUpdate
I start two instances of this client. The messages seem to be delivered - no errors - but the messages do not arrive at the subscribers ...
What I am doing wrong ?
Any help appreciated - many thanks in advance!
public class JMS implements MessageListener {
private TopicConnectionFactory factory;
private TopicConnection connection;
private Topic topic;
private void subscribe() {
try {
System.setProperty("org.omg.CORBA.ORBInitialHost", "192.168.1.6");
System.setProperty("org.omg.CORBA.ORBInitialPort", "3700");
InitialContext ctx = new InitialContext();
factory = (TopicConnectionFactory)ctx.lookup("jms/TopicConnectionFactory");
topic = (Topic)ctx.lookup("jms/TopicUpdate");
connection = factory.createTopicConnection();
TopicSession session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
TopicSubscriber subscriber = session.createSubscriber(topic);
subscriber.setMessageListener(this);
connection.start();
while(true) {
Thread.sleep(5000);
sendMessage();
}
} catch (InterruptedException ex) {
Logger.getLogger(JMS.class.getName()).log(Level.SEVERE, null, ex);
} catch (NamingException ex) {
Logger.getLogger(JMS.class.getName()).log(Level.SEVERE, null, ex);
} catch (JMSException ex) {
Logger.getLogger(JMS.class.getName()).log(Level.SEVERE, null, ex);
}
}
private void sendMessage() {
try {
TopicSession session = connection.createTopicSession(true, Session.AUTO_ACKNOWLEDGE);
TopicPublisher publisher = session.createPublisher(topic);
TextMessage message = session.createTextMessage();
message.setText("Message from client.");
publisher.send(message);
session.close();
System.out.println("Message sent.");
} catch (JMSException ex) {
Logger.getLogger(JMS.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public void onMessage(Message msg) {
System.out.println("Message received.");
}
public JMS() {
subscribe();
}
public static void main(String[] args) {
new JMS();
}
}
When you use true as the first argument when creating a session, the acknowledge mode is ignored and you're assumed to be transacted. try it with the first argument as false.
Just so it's clear, modify this line of code:
TopicSession session = connection.createTopicSession(true, Session.AUTO_ACKNOWLEDGE);
to be :
TopicSession session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
In your send message method.
It's good idea to have publisher and subscriber different.I
Here is code how to subscribe using Spring JMS template.
public class MsgReader implements
SessionAwareMessageListener<Message> {
#Override
public void onMessage(Message message, Session session) throws JMSException {
if (message instanceof TextMessage) {
try {
System.out.println(((TextMessage) message).getText());
} catch (JMSException ex) {
throw new RuntimeException(ex);
}
} else {
throw new IllegalArgumentException(
"Message must be of type TextMessage");
}
}
}
Spring Bean file.
Finally load beans.
public class SpringJMSTest {
/**
* #param args
*/
public static void main(String[] args) {
ApplicationContext context = new FileSystemXmlApplicationContext(new String[]{"/resource/consumerBean.xml"});
}
}
Now you will start receiving messages in console.