/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.hawtjms.jms;
import io.hawtjms.jms.message.JmsInboundMessageDispatch;
import io.hawtjms.jms.message.JmsMessage;
import io.hawtjms.jms.message.JmsMessageFactory;
import io.hawtjms.jms.message.JmsMessageTransformation;
import io.hawtjms.jms.message.JmsOutboundMessageDispatch;
import io.hawtjms.jms.meta.JmsConsumerId;
import io.hawtjms.jms.meta.JmsMessageId;
import io.hawtjms.jms.meta.JmsProducerId;
import io.hawtjms.jms.meta.JmsSessionId;
import io.hawtjms.jms.meta.JmsSessionInfo;
import io.hawtjms.provider.BlockingProvider;
import io.hawtjms.provider.ProviderConstants.ACK_TYPE;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;
import javax.jms.BytesMessage;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.IllegalStateException;
import javax.jms.InvalidDestinationException;
import javax.jms.InvalidSelectorException;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueBrowser;
import javax.jms.QueueReceiver;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.StreamMessage;
import javax.jms.TemporaryQueue;
import javax.jms.TemporaryTopic;
import javax.jms.TextMessage;
import javax.jms.Topic;
import javax.jms.TopicPublisher;
import javax.jms.TopicSession;
import javax.jms.TopicSubscriber;
import org.apache.activemq.apollo.filter.FilterException;
import org.apache.activemq.apollo.selector.SelectorParser;
/**
* JMS Session implementation
*/
@SuppressWarnings("static-access")
public class JmsSession implements Session, QueueSession, TopicSession, JmsMessageListener, JmsMessageDispatcher {
private final JmsConnection connection;
private final int acknowledgementMode;
private final List<JmsMessageProducer> producers = new CopyOnWriteArrayList<JmsMessageProducer>();
private final Map<JmsConsumerId, JmsMessageConsumer> consumers = new ConcurrentHashMap<JmsConsumerId, JmsMessageConsumer>();
private MessageListener messageListener;
private final AtomicBoolean closed = new AtomicBoolean();
private final AtomicBoolean started = new AtomicBoolean();
private final LinkedBlockingQueue<JmsInboundMessageDispatch> stoppedMessages =
new LinkedBlockingQueue<JmsInboundMessageDispatch>(10000);
private JmsPrefetchPolicy prefetchPolicy;
private JmsSessionInfo sessionInfo;
private ExecutorService executor;
private final ReentrantLock sendLock = new ReentrantLock();
private final AtomicLong consumerIdGenerator = new AtomicLong();
private final AtomicLong producerIdGenerator = new AtomicLong();
private JmsLocalTransactionContext transactionContext;
private JmsMessageFactory messageFactory;
protected JmsSession(JmsConnection connection, JmsSessionId sessionId, int acknowledgementMode) throws JMSException {
this.connection = connection;
this.acknowledgementMode = acknowledgementMode;
this.prefetchPolicy = new JmsPrefetchPolicy(connection.getPrefetchPolicy());
setTransactionContext(new JmsLocalTransactionContext(this));
this.sessionInfo = new JmsSessionInfo(sessionId);
this.sessionInfo.setAcknowledgementMode(acknowledgementMode);
this.sessionInfo.setSendAcksAsync(connection.isSendAcksAsync());
this.sessionInfo = connection.createResource(sessionInfo);
this.messageFactory = connection.getMessageFactory();
}
int acknowledgementMode() {
return this.acknowledgementMode;
}
//////////////////////////////////////////////////////////////////////////
// Session methods
//////////////////////////////////////////////////////////////////////////
@Override
public int getAcknowledgeMode() throws JMSException {
checkClosed();
return this.acknowledgementMode;
}
@Override
public boolean getTransacted() throws JMSException {
checkClosed();
return isTransacted();
}
@Override
public MessageListener getMessageListener() throws JMSException {
checkClosed();
return this.messageListener;
}
@Override
public void setMessageListener(MessageListener listener) throws JMSException {
checkClosed();
this.messageListener = listener;
}
@Override
public void recover() throws JMSException {
checkClosed();
if (getTransacted()) {
throw new javax.jms.IllegalStateException("Cannot call recover() on a transacted session");
}
this.connection.recover(getSessionId());
}
@Override
public void commit() throws JMSException {
checkClosed();
if (!getTransacted()) {
throw new javax.jms.IllegalStateException("Not a transacted session");
}
this.transactionContext.commit();
}
@Override
public void rollback() throws JMSException {
checkClosed();
if (!getTransacted()) {
throw new javax.jms.IllegalStateException("Not a transacted session");
}
this.transactionContext.rollback();
getExecutor().execute(new Runnable() {
@Override
public void run() {
for (JmsMessageConsumer c : consumers.values()) {
c.drainMessageQueueToListener();
}
}
});
}
@Override
public void run() {
try {
checkClosed();
} catch (IllegalStateException e) {
throw new RuntimeException(e);
}
throw new UnsupportedOperationException();
}
@Override
public void close() throws JMSException {
if (!closed.get()) {
doClose();
}
}
/**
* Shutdown the Session and release all resources. Once completed the Session can
* request that the Provider destroy the Session and it's child resources.
*
* @throws JMSException
*/
protected void doClose() throws JMSException {
boolean interrupted = Thread.interrupted();
shutdown();
this.connection.removeSession(this);
this.connection.destroyResource(sessionInfo);
if (interrupted) {
Thread.currentThread().interrupt();
}
}
/**
* This method should terminate all Session resources and prepare for disposal of the
* Session. It is called either from the Session close method or from the Connection
* when a close request is made and the Connection wants to cleanup all Session resources.
*
* This method should not attempt to send a destroy request to the Provider as that
* will either be done by another session method or is not needed when done by the parent
* Connection.
*
* @throws JMSException
*/
protected void shutdown() throws JMSException {
if (closed.compareAndSet(false, true)) {
stop();
for (JmsMessageConsumer consumer : new ArrayList<JmsMessageConsumer>(this.consumers.values())) {
consumer.shutdown();
}
for (JmsMessageProducer producer : this.producers) {
producer.shutdown();
}
try {
if (getTransactionContext().isInTransaction()) {
rollback();
}
} catch (JMSException e) {
}
}
}
//////////////////////////////////////////////////////////////////////////
// Consumer creation
//////////////////////////////////////////////////////////////////////////
/**
* @param destination
* @return a MessageConsumer
* @throws JMSException
* @see javax.jms.Session#createConsumer(javax.jms.Destination)
*/
@Override
public MessageConsumer createConsumer(Destination destination) throws JMSException {
return createConsumer(destination, null);
}
/**
* @param destination
* @param messageSelector
* @return MessageConsumer
* @throws JMSException
* @see javax.jms.Session#createConsumer(javax.jms.Destination,
* java.lang.String)
*/
@Override
public MessageConsumer createConsumer(Destination destination, String messageSelector) throws JMSException {
return createConsumer(destination, messageSelector, false);
}
/**
* @param destination
* @param messageSelector
* @param NoLocal
* @return the MessageConsumer
* @throws JMSException
* @see javax.jms.Session#createConsumer(javax.jms.Destination,
* java.lang.String, boolean)
*/
@Override
public MessageConsumer createConsumer(Destination destination, String messageSelector, boolean NoLocal) throws JMSException {
checkClosed();
checkDestination(destination);
messageSelector = checkSelector(messageSelector);
JmsDestination dest = JmsMessageTransformation.transformDestination(connection, destination);
JmsTopicSubscriber result = new JmsTopicSubscriber(getNextConsumerId(), this, dest, NoLocal, messageSelector);
result.init();
return result;
}
/**
* @param queue
* @return QueueRecevier
* @throws JMSException
* @see javax.jms.QueueSession#createReceiver(javax.jms.Queue)
*/
@Override
public QueueReceiver createReceiver(Queue queue) throws JMSException {
checkClosed();
checkDestination(queue);
JmsDestination dest = JmsMessageTransformation.transformDestination(connection, queue);
JmsQueueReceiver result = new JmsQueueReceiver(getNextConsumerId(), this, dest, "");
result.init();
return result;
}
/**
* @param queue
* @param messageSelector
* @return QueueReceiver
* @throws JMSException
* @see javax.jms.QueueSession#createReceiver(javax.jms.Queue,
* java.lang.String)
*/
@Override
public QueueReceiver createReceiver(Queue queue, String messageSelector) throws JMSException {
checkClosed();
checkDestination(queue);
messageSelector = checkSelector(messageSelector);
JmsDestination dest = JmsMessageTransformation.transformDestination(connection, queue);
JmsQueueReceiver result = new JmsQueueReceiver(getNextConsumerId(), this, dest, messageSelector);
result.init();
return result;
}
/**
* @param destination
* @return QueueBrowser
* @throws JMSException
* @see javax.jms.Session#createBrowser(javax.jms.Queue)
*/
@Override
public QueueBrowser createBrowser(Queue destination) throws JMSException {
return createBrowser(destination, null);
}
/**
* @param destination
* @param messageSelector
* @return QueueBrowser
* @throws JMSException
* @see javax.jms.Session#createBrowser(javax.jms.Queue, java.lang.String)
*/
@Override
public QueueBrowser createBrowser(Queue destination, String messageSelector) throws JMSException {
checkClosed();
checkDestination(destination);
messageSelector = checkSelector(messageSelector);
JmsDestination dest = JmsMessageTransformation.transformDestination(connection, destination);
JmsQueueBrowser result = new JmsQueueBrowser(this, dest, messageSelector);
return result;
}
/**
* @param topic
* @return TopicSubscriber
* @throws JMSException
* @see javax.jms.TopicSession#createSubscriber(javax.jms.Topic)
*/
@Override
public TopicSubscriber createSubscriber(Topic topic) throws JMSException {
return createSubscriber(topic, null, false);
}
/**
* @param topic
* @param messageSelector
* @param noLocal
* @return TopicSubscriber
* @throws JMSException
* @see javax.jms.TopicSession#createSubscriber(javax.jms.Topic,
* java.lang.String, boolean)
*/
@Override
public TopicSubscriber createSubscriber(Topic topic, String messageSelector, boolean noLocal) throws JMSException {
checkClosed();
checkDestination(topic);
messageSelector = checkSelector(messageSelector);
JmsDestination dest = JmsMessageTransformation.transformDestination(connection, topic);
JmsTopicSubscriber result = new JmsTopicSubscriber(getNextConsumerId(), this, dest, noLocal, messageSelector);
result.init();
return result;
}
/**
* @param topic
* @param name
* @return a TopicSubscriber
* @throws JMSException
* @see javax.jms.Session#createDurableSubscriber(javax.jms.Topic,
* java.lang.String)
*/
@Override
public TopicSubscriber createDurableSubscriber(Topic topic, String name) throws JMSException {
return createDurableSubscriber(topic, name, null, false);
}
/**
* @param topic
* @param name
* @param messageSelector
* @param noLocal
* @return TopicSubscriber
* @throws JMSException
* @see javax.jms.Session#createDurableSubscriber(javax.jms.Topic,
* java.lang.String, java.lang.String, boolean)
*/
@Override
public TopicSubscriber createDurableSubscriber(Topic topic, String name, String messageSelector, boolean noLocal) throws JMSException {
checkClosed();
checkDestination(topic);
messageSelector = checkSelector(messageSelector);
JmsDestination dest = JmsMessageTransformation.transformDestination(connection, topic);
JmsTopicSubscriber result = new JmsDurableTopicSubscriber(getNextConsumerId(), this, dest, name, false, messageSelector);
result.init();
return result;
}
/**
* @param name
* @throws JMSException
* @see javax.jms.Session#unsubscribe(java.lang.String)
*/
@Override
public void unsubscribe(String name) throws JMSException {
checkClosed();
this.connection.unsubscribe(name);
}
//////////////////////////////////////////////////////////////////////////
// Producer creation
//////////////////////////////////////////////////////////////////////////
/**
* @param destination
* @return MessageProducer
* @throws JMSException
* @see javax.jms.Session#createProducer(javax.jms.Destination)
*/
@Override
public MessageProducer createProducer(Destination destination) throws JMSException {
checkClosed();
JmsDestination dest = JmsMessageTransformation.transformDestination(connection, destination);
JmsMessageProducer result = new JmsMessageProducer(getNextProducerId(), this, dest);
add(result);
return result;
}
/**
* @param queue
* @return QueueSender
* @throws JMSException
* @see javax.jms.QueueSession#createSender(javax.jms.Queue)
*/
@Override
public QueueSender createSender(Queue queue) throws JMSException {
checkClosed();
JmsDestination dest = JmsMessageTransformation.transformDestination(connection, queue);
JmsQueueSender result = new JmsQueueSender(getNextProducerId(), this, dest);
return result;
}
/**
* @param topic
* @return TopicPublisher
* @throws JMSException
* @see javax.jms.TopicSession#createPublisher(javax.jms.Topic)
*/
@Override
public TopicPublisher createPublisher(Topic topic) throws JMSException {
checkClosed();
JmsDestination dest = JmsMessageTransformation.transformDestination(connection, topic);
JmsTopicPublisher result = new JmsTopicPublisher(getNextProducerId(), this, dest);
add(result);
return result;
}
//////////////////////////////////////////////////////////////////////////
// Message creation
//////////////////////////////////////////////////////////////////////////
/**
* @return BytesMessage
* @throws IllegalStateException
* @see javax.jms.Session#createBytesMessage()
*/
@Override
public BytesMessage createBytesMessage() throws IllegalStateException {
checkClosed();
return init(messageFactory.createBytesMessage());
}
/**
* @return MapMessage
* @throws IllegalStateException
* @see javax.jms.Session#createMapMessage()
*/
@Override
public MapMessage createMapMessage() throws IllegalStateException {
checkClosed();
return init(messageFactory.createMapMessage());
}
/**
* @return Message
* @throws IllegalStateException
* @see javax.jms.Session#createMessage()
*/
@Override
public Message createMessage() throws IllegalStateException {
checkClosed();
return init(messageFactory.createMessage());
}
/**
* @return ObjectMessage
* @throws IllegalStateException
* @see javax.jms.Session#createObjectMessage()
*/
@Override
public ObjectMessage createObjectMessage() throws IllegalStateException {
checkClosed();
return init(messageFactory.createObjectMessage(null));
}
/**
* @param object
* @return ObjectMessage
* @throws JMSException
* @see javax.jms.Session#createObjectMessage(java.io.Serializable)
*/
@Override
public ObjectMessage createObjectMessage(Serializable object) throws JMSException {
checkClosed();
return init(messageFactory.createObjectMessage(object));
}
/**
* @return StreamMessage
* @throws JMSException
* @see javax.jms.Session#createStreamMessage()
*/
@Override
public StreamMessage createStreamMessage() throws JMSException {
checkClosed();
return init(messageFactory.createStreamMessage());
}
/**
* @return TextMessage
* @throws JMSException
* @see javax.jms.Session#createTextMessage()
*/
@Override
public TextMessage createTextMessage() throws JMSException {
checkClosed();
return init(messageFactory.createTextMessage(null));
}
/**
* @param text
* @return TextMessage
* @throws JMSException
* @see javax.jms.Session#createTextMessage(java.lang.String)
*/
@Override
public TextMessage createTextMessage(String text) throws JMSException {
checkClosed();
return init(messageFactory.createTextMessage(text));
}
//////////////////////////////////////////////////////////////////////////
// Destination creation
//////////////////////////////////////////////////////////////////////////
/**
* @param queueName
* @return Queue
* @throws JMSException
* @see javax.jms.Session#createQueue(java.lang.String)
*/
@Override
public Queue createQueue(String queueName) throws JMSException {
checkClosed();
return new JmsQueue(queueName);
}
/**
* @param topicName
* @return Topic
* @throws JMSException
* @see javax.jms.Session#createTopic(java.lang.String)
*/
@Override
public Topic createTopic(String topicName) throws JMSException {
checkClosed();
return new JmsTopic(topicName);
}
/**
* @return TemporaryQueue
* @throws JMSException
* @see javax.jms.Session#createTemporaryQueue()
*/
@Override
public TemporaryQueue createTemporaryQueue() throws JMSException {
checkClosed();
return connection.createTemporaryQueue();
}
/**
* @return TemporaryTopic
* @throws JMSException
* @see javax.jms.Session#createTemporaryTopic()
*/
@Override
public TemporaryTopic createTemporaryTopic() throws JMSException {
checkClosed();
return connection.createTemporaryTopic();
}
//////////////////////////////////////////////////////////////////////////
// Session Implementation methods
//////////////////////////////////////////////////////////////////////////
protected void add(JmsMessageConsumer consumer) throws JMSException {
this.consumers.put(consumer.getConsumerId(), consumer);
this.connection.addDispatcher(consumer.getConsumerId(), this);
if (started.get()) {
consumer.start();
}
}
protected void remove(JmsMessageConsumer consumer) throws JMSException {
this.connection.removeDispatcher(consumer.getConsumerId());
this.consumers.remove(consumer.getConsumerId());
}
protected void add(JmsMessageProducer producer) {
this.producers.add(producer);
}
protected void remove(MessageProducer producer) {
this.producers.remove(producer);
}
protected void onException(Exception ex) {
this.connection.onException(ex);
}
protected void onException(JMSException ex) {
this.connection.onException(ex);
}
protected void send(JmsMessageProducer producer, Destination dest, Message msg, int deliveryMode, int priority, long timeToLive, boolean disableMsgId) throws JMSException {
JmsDestination destination = JmsMessageTransformation.transformDestination(connection, dest);
send(producer, destination, msg, deliveryMode, priority, timeToLive, disableMsgId);
}
private void send(JmsMessageProducer producer, JmsDestination destination, Message original, int deliveryMode, int priority, long timeToLive, boolean disableMsgId) throws JMSException {
sendLock.lock();
try {
startNextTransaction();
original.setJMSDeliveryMode(deliveryMode);
original.setJMSPriority(priority);
original.setJMSRedelivered(false);
if (timeToLive > 0) {
long timeStamp = System.currentTimeMillis();
original.setJMSTimestamp(timeStamp);
original.setJMSExpiration(System.currentTimeMillis() + timeToLive);
}
JmsMessageId msgId = null;
if (!disableMsgId) {
msgId = getNextMessageId(producer);
}
boolean isJmsMessageType = original instanceof JmsMessage;
if (isJmsMessageType) {
((JmsMessage) original).setConnection(connection);
if (!disableMsgId) {
((JmsMessage) original).setJMSMessageID(msgId);
}
original.setJMSDestination(destination);
}
JmsMessage copy = JmsMessageTransformation.transformMessage(connection, original);
// Ensure original message gets the destination and message ID as per spec.
if (!isJmsMessageType) {
if (!disableMsgId) {
original.setJMSMessageID(msgId.toString());
copy.setJMSMessageID(msgId);
}
original.setJMSDestination(destination);
copy.setJMSDestination(destination);
}
boolean sync = connection.isAlwaysSyncSend() ||
(!connection.isForceAsyncSend() && deliveryMode == DeliveryMode.PERSISTENT && !getTransacted());
copy.onSend();
JmsOutboundMessageDispatch envelope = new JmsOutboundMessageDispatch();
envelope.setMessage(copy);
envelope.setProducerId(producer.getProducerId());
envelope.setDestination(destination);
envelope.setSendAsync(!sync);
this.connection.send(envelope);
} finally {
sendLock.unlock();
}
}
void acknowledge(JmsInboundMessageDispatch envelope, ACK_TYPE ackType) throws JMSException {
startNextTransaction();
this.connection.acknowledge(envelope, ackType);
}
/**
* Acknowledge all previously delivered messages in this Session as consumed. This
* method is usually only called when the Session is in the CLIENT_ACKNOWLEDGE mode.
*
* @throws JMSException if an error occurs while the acknowledge is processed.
*/
void acknowledge() throws JMSException {
this.connection.acknowledge(sessionInfo.getSessionId());
}
public boolean isClosed() {
return this.closed.get();
}
/**
* Checks whether the session uses transactions.
*
* @return true - if the session uses transactions.
*/
public boolean isTransacted() {
return this.acknowledgementMode == Session.SESSION_TRANSACTED;
}
/**
* Checks whether the session used client acknowledgment.
*
* @return true - if the session uses client acknowledgment.
*/
protected boolean isClientAcknowledge() {
return this.acknowledgementMode == Session.CLIENT_ACKNOWLEDGE;
}
/**
* Checks whether the session used auto acknowledgment.
*
* @return true - if the session uses client acknowledgment.
*/
public boolean isAutoAcknowledge() {
return acknowledgementMode == Session.AUTO_ACKNOWLEDGE;
}
/**
* Checks whether the session used dup ok acknowledgment.
*
* @return true - if the session uses client acknowledgment.
*/
public boolean isDupsOkAcknowledge() {
return acknowledgementMode == Session.DUPS_OK_ACKNOWLEDGE;
}
protected void checkClosed() throws IllegalStateException {
if (this.closed.get()) {
throw new IllegalStateException("The MessageProducer is closed");
}
}
// This extra wrapping class around SelectorParser is used to avoid
// ClassNotFoundException if SelectorParser is not in the class path.
static class OptionalSectorParser {
public static void check(String selector) throws InvalidSelectorException {
try {
SelectorParser.parse(selector);
} catch (FilterException e) {
throw new InvalidSelectorException(e.getMessage());
}
}
}
static final OptionalSectorParser SELECTOR_PARSER;
static {
OptionalSectorParser parser;
try {
// lets verify it's working..
parser = new OptionalSectorParser();
parser.check("x=1");
} catch (Throwable e) {
parser = null;
}
SELECTOR_PARSER = parser;
}
public static String checkSelector(String selector) throws InvalidSelectorException {
if (selector != null) {
if (selector.trim().length() == 0) {
return null;
}
if (SELECTOR_PARSER != null) {
SELECTOR_PARSER.check(selector);
}
}
return selector;
}
public static void checkDestination(Destination dest) throws InvalidDestinationException {
if (dest == null) {
throw new InvalidDestinationException("Destination cannot be null");
}
}
protected void start() throws JMSException {
if (started.compareAndSet(false, true)) {
JmsInboundMessageDispatch message = null;
while ((message = this.stoppedMessages.poll()) != null) {
deliver(message);
}
for (JmsMessageConsumer consumer : consumers.values()) {
consumer.start();
}
}
}
protected void stop() throws JMSException {
started.set(false);
if (executor != null) {
executor.shutdown();
executor = null;
}
for (JmsMessageConsumer consumer : consumers.values()) {
consumer.stop();
}
}
protected boolean isStarted() {
return this.started.get();
}
public JmsConnection getConnection() {
return this.connection;
}
Executor getExecutor() {
if (executor == null) {
executor = Executors.newSingleThreadExecutor(new ThreadFactory() {
@Override
public Thread newThread(Runnable runner) {
Thread executor = new Thread(runner);
executor.setName("JmsSession ["+ sessionInfo.getSessionId() + "] dispatcher");
executor.setDaemon(true);
return executor;
}
});
}
return executor;
}
protected JmsSessionInfo getSessionInfo() {
return this.sessionInfo;
}
protected JmsSessionId getSessionId() {
return this.sessionInfo.getSessionId();
}
protected JmsConsumerId getNextConsumerId() {
return new JmsConsumerId(sessionInfo.getSessionId(), consumerIdGenerator.incrementAndGet());
}
protected JmsProducerId getNextProducerId() {
return new JmsProducerId(sessionInfo.getSessionId(), producerIdGenerator.incrementAndGet());
}
private JmsMessageId getNextMessageId(JmsMessageProducer producer) {
return new JmsMessageId(producer.getProducerId(), producer.getNextMessageSequence());
}
private <T extends JmsMessage> T init(T message) {
message.setConnection(connection);
return message;
}
private synchronized void startNextTransaction() throws JMSException {
if (getTransacted()) {
transactionContext.begin();
}
}
boolean isDestinationInUse(JmsDestination destination) {
for (JmsMessageConsumer consumer : consumers.values()) {
if (consumer.isUsingDestination(destination)) {
return true;
}
}
return false;
}
void checkMessageListener() throws JMSException {
if (messageListener != null) {
throw new IllegalStateException("Cannot synchronously receive a message when a MessageListener is set");
}
for (JmsMessageConsumer consumer : consumers.values()) {
if (consumer.hasMessageListener()) {
throw new IllegalStateException("Cannot synchronously receive a message when a MessageListener is set");
}
}
}
public JmsPrefetchPolicy getPrefetchPolicy() {
return prefetchPolicy;
}
public void setPrefetchPolicy(JmsPrefetchPolicy prefetchPolicy) {
this.prefetchPolicy = prefetchPolicy;
}
@Override
public void onMessage(JmsInboundMessageDispatch envelope) {
if (started.get()) {
deliver(envelope);
} else {
this.stoppedMessages.add(envelope);
}
}
protected void onConnectionInterrupted() {
for (JmsMessageProducer producer : producers) {
producer.onConnectionInterrupted();
}
for (JmsMessageConsumer consumer : consumers.values()) {
consumer.onConnectionInterrupted();
}
}
protected void onConnectionRecovery(BlockingProvider provider) throws Exception {
provider.create(sessionInfo);
if (this.acknowledgementMode == SESSION_TRANSACTED) {
if (transactionContext.isInTransaction()) {
transactionContext.clear();
transactionContext.begin();
}
}
for (JmsMessageProducer producer : producers) {
producer.onConnectionRecovery(provider);
}
for (JmsMessageConsumer consumer : consumers.values()) {
consumer.onConnectionRecovery(provider);
}
}
protected void onConnectionRecovered(BlockingProvider provider) throws Exception {
this.messageFactory = provider.getMessageFactory();
for (JmsMessageProducer producer : producers) {
producer.onConnectionRecovered(provider);
}
for (JmsMessageConsumer consumer : consumers.values()) {
consumer.onConnectionRecovered(provider);
}
}
protected void onConnectionRestored() {
for (JmsMessageProducer producer : producers) {
producer.onConnectionRestored();
}
for (JmsMessageConsumer consumer : consumers.values()) {
consumer.onConnectionRestored();
}
}
private void deliver(JmsInboundMessageDispatch envelope) {
JmsConsumerId id = envelope.getConsumerId();
if (id == null) {
this.connection.onException(new JMSException("No ConsumerId set for " + envelope.getMessage()));
}
if (this.messageListener != null) {
this.messageListener.onMessage(envelope.getMessage());
} else {
JmsMessageConsumer consumer = this.consumers.get(id);
if (consumer != null) {
consumer.onMessage(envelope);
}
}
}
/**
* Sets the transaction context of the session.
*
* @param transactionContext
* provides the means to control a JMS transaction.
*/
public void setTransactionContext(JmsLocalTransactionContext transactionContext) {
this.transactionContext = transactionContext;
}
/**
* Returns the transaction context of the session.
*
* @return transactionContext
* session's transaction context.
*/
public JmsLocalTransactionContext getTransactionContext() {
return transactionContext;
}
}