/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.core.communication.transport.jms.common;
import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Base class for single-threaded consumers of a JMS {@link Queue}.
*
* @author Robert Mischke
*/
public abstract class AbstractJmsQueueConsumer implements Runnable {
protected final Log log = LogFactory.getLog(getClass());
protected final Connection jmsConnection;
protected final String queueName;
private Session session;
public AbstractJmsQueueConsumer(Connection connection, String queueName) throws JMSException {
this.jmsConnection = connection;
this.queueName = queueName;
}
@Override
public void run() {
try {
// synchronize for session visibility
synchronized (this) {
if (session != null) {
// not meant to be run twice
throw new IllegalStateException("Session not null");
}
session = jmsConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
}
Queue queue = session.createQueue(queueName);
MessageConsumer consumer = session.createConsumer(queue);
log.debug("Running listener for queue " + queue.getQueueName() + " in thread " + Thread.currentThread().getName());
try {
while (true) {
Message message;
try {
message = consumer.receive();
if (message == null) {
log.debug("Clean shutdown of queue listener for " + queue.getQueueName() + ": received NULL");
break;
}
} catch (JMSException e) {
log.warn("Exception while listening on queue " + queue.getQueueName() + " (unclean shutdown?): " + e.toString());
break;
}
try {
if (checkForShutdown(message)) {
log.debug("Clean shutdown of queue listener for " + queue.getQueueName() + ": received shutdown message");
break;
}
dispatchMessage(message, jmsConnection);
} catch (JMSException e) {
log.warn("Error while processing received message; continuing to listen", e);
}
}
} finally {
if (session != null) {
try {
session.close();
} catch (JMSException e1) {
// TODO how to prevent these? (they should be harmless, though)
log.debug("JMS exception while closing inbox consumer session on " + queueName + ": " + e1.toString());
}
}
}
} catch (JMSException e) {
log.warn("Unhandled exception in inbox consumer thread, terminating", e);
}
}
/**
* Provides a direct way to shut down this listener (instead of posting a shutdown message to the queue). Can be called from any thread,
* and does not wait for the shutdown to complete.
*
* @throws JMSException on internal JMS errors
*/
public void triggerShutDown() throws JMSException {
// synchronize for session visibility
synchronized (this) {
if (session == null) {
log.warn("Queue consumer received shutdown command, but had no session yet");
return;
}
session.close();
}
}
private boolean checkForShutdown(Message message) throws JMSException {
String messageType = message.getStringProperty(JmsProtocolConstants.MESSAGE_FIELD_MESSAGE_TYPE);
if (JmsProtocolConstants.MESSAGE_TYPE_QUEUE_SHUTDOWN.equals(messageType)) {
String textContent = ((TextMessage) message).getText();
log.debug("Received shutdown command, token=" + textContent);
// FIXME check token
return true;
}
return false;
}
protected abstract void dispatchMessage(Message message, Connection connection);
}