/* * 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 org.apache.activemq.artemis.jms.client; import javax.jms.BytesMessage; import javax.jms.ConnectionMetaData; import javax.jms.Destination; import javax.jms.ExceptionListener; import javax.jms.IllegalStateRuntimeException; import javax.jms.JMSConsumer; import javax.jms.JMSContext; import javax.jms.JMSException; import javax.jms.JMSProducer; import javax.jms.MapMessage; import javax.jms.Message; import javax.jms.MessageProducer; import javax.jms.ObjectMessage; import javax.jms.Queue; import javax.jms.QueueBrowser; 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.XAConnection; import javax.jms.XASession; import javax.transaction.xa.XAResource; import java.io.Serializable; /** * ActiveMQ Artemis implementation of a JMSContext. */ public class ActiveMQJMSContext implements JMSContext { private static final boolean DEFAULT_AUTO_START = true; private final int sessionMode; private final ThreadAwareContext threadAwareContext; /** * Client ACK needs to hold last acked messages, so context.ack calls will be respected. */ private volatile Message lastMessagesWaitingAck; private final ActiveMQConnectionForContext connection; private Session session; private boolean autoStart = ActiveMQJMSContext.DEFAULT_AUTO_START; private MessageProducer innerProducer; private boolean xa; private boolean closed; ActiveMQJMSContext(final ActiveMQConnectionForContext connection, final int ackMode, final boolean xa, ThreadAwareContext threadAwareContext) { this.connection = connection; this.sessionMode = ackMode; this.xa = xa; this.threadAwareContext = threadAwareContext; } public ActiveMQJMSContext(ActiveMQConnectionForContext connection, int ackMode, ThreadAwareContext threadAwareContext) { this(connection, ackMode, false, threadAwareContext); } public ActiveMQJMSContext(ActiveMQConnectionForContext connection, ThreadAwareContext threadAwareContext) { this(connection, SESSION_TRANSACTED, true, threadAwareContext); } // XAJMSContext implementation ------------------------------------- public JMSContext getContext() { return this; } public Session getSession() { return session; } public XAResource getXAResource() { checkSession(); return ((XASession) session).getXAResource(); } // JMSContext implementation ------------------------------------- @Override public JMSContext createContext(int sessionMode) { return connection.createContext(sessionMode); } @Override public JMSProducer createProducer() { checkSession(); try { return new ActiveMQJMSProducer(this, getInnerProducer()); } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } private synchronized MessageProducer getInnerProducer() throws JMSException { if (innerProducer == null) { innerProducer = session.createProducer(null); } return innerProducer; } /** * */ private void checkSession() { if (session == null) { synchronized (this) { if (closed) throw new IllegalStateRuntimeException("Context is closed"); if (session == null) { try { if (xa) { session = ((XAConnection) connection).createXASession(); } else { session = connection.createSession(sessionMode); } } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } } } } @Override public String getClientID() { try { return connection.getClientID(); } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public void setClientID(String clientID) { try { connection.setClientID(clientID); } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public ConnectionMetaData getMetaData() { try { return connection.getMetaData(); } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public ExceptionListener getExceptionListener() { try { return connection.getExceptionListener(); } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public void setExceptionListener(ExceptionListener listener) { try { connection.setExceptionListener(listener); } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public void start() { try { connection.start(); } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public void stop() { threadAwareContext.assertNotMessageListenerThreadRuntime(); try { connection.stop(); } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public void setAutoStart(boolean autoStart) { this.autoStart = autoStart; } @Override public boolean getAutoStart() { return autoStart; } @Override public void close() { threadAwareContext.assertNotCompletionListenerThreadRuntime(); threadAwareContext.assertNotMessageListenerThreadRuntime(); try { synchronized (this) { if (session != null) session.close(); connection.closeFromContext(); closed = true; } } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public BytesMessage createBytesMessage() { checkSession(); try { return session.createBytesMessage(); } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public MapMessage createMapMessage() { checkSession(); try { return session.createMapMessage(); } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public Message createMessage() { checkSession(); try { return session.createMessage(); } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public ObjectMessage createObjectMessage() { checkSession(); try { return session.createObjectMessage(); } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public ObjectMessage createObjectMessage(Serializable object) { checkSession(); try { return session.createObjectMessage(object); } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public StreamMessage createStreamMessage() { checkSession(); try { return session.createStreamMessage(); } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public TextMessage createTextMessage() { checkSession(); try { return session.createTextMessage(); } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public TextMessage createTextMessage(String text) { checkSession(); try { return session.createTextMessage(text); } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public boolean getTransacted() { checkSession(); try { return session.getTransacted(); } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public int getSessionMode() { return sessionMode; } @Override public void commit() { threadAwareContext.assertNotCompletionListenerThreadRuntime(); checkSession(); try { session.commit(); } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public void rollback() { threadAwareContext.assertNotCompletionListenerThreadRuntime(); checkSession(); try { session.rollback(); } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public void recover() { checkSession(); try { session.recover(); } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public JMSConsumer createConsumer(Destination destination) { checkSession(); try { ActiveMQJMSConsumer consumer = new ActiveMQJMSConsumer(this, session.createConsumer(destination)); checkAutoStart(); return consumer; } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public JMSConsumer createConsumer(Destination destination, String messageSelector) { checkSession(); try { ActiveMQJMSConsumer consumer = new ActiveMQJMSConsumer(this, session.createConsumer(destination, messageSelector)); checkAutoStart(); return consumer; } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public JMSConsumer createConsumer(Destination destination, String messageSelector, boolean noLocal) { checkSession(); try { ActiveMQJMSConsumer consumer = new ActiveMQJMSConsumer(this, session.createConsumer(destination, messageSelector, noLocal)); checkAutoStart(); return consumer; } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public Queue createQueue(String queueName) { checkSession(); try { return session.createQueue(queueName); } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public Topic createTopic(String topicName) { checkSession(); try { return session.createTopic(topicName); } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public JMSConsumer createDurableConsumer(Topic topic, String name) { checkSession(); try { ActiveMQJMSConsumer consumer = new ActiveMQJMSConsumer(this, session.createDurableConsumer(topic, name)); checkAutoStart(); return consumer; } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public JMSConsumer createDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal) { checkSession(); try { ActiveMQJMSConsumer consumer = new ActiveMQJMSConsumer(this, session.createDurableConsumer(topic, name, messageSelector, noLocal)); checkAutoStart(); return consumer; } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public JMSConsumer createSharedDurableConsumer(Topic topic, String name) { checkSession(); try { ActiveMQJMSConsumer consumer = new ActiveMQJMSConsumer(this, session.createSharedDurableConsumer(topic, name)); checkAutoStart(); return consumer; } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public JMSConsumer createSharedDurableConsumer(Topic topic, String name, String messageSelector) { checkSession(); try { ActiveMQJMSConsumer consumer = new ActiveMQJMSConsumer(this, session.createSharedDurableConsumer(topic, name, messageSelector)); checkAutoStart(); return consumer; } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public JMSConsumer createSharedConsumer(Topic topic, String sharedSubscriptionName) { checkSession(); try { ActiveMQJMSConsumer consumer = new ActiveMQJMSConsumer(this, session.createSharedConsumer(topic, sharedSubscriptionName)); checkAutoStart(); return consumer; } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public JMSConsumer createSharedConsumer(Topic topic, String sharedSubscriptionName, String messageSelector) { checkSession(); try { ActiveMQJMSConsumer consumer = new ActiveMQJMSConsumer(this, session.createSharedConsumer(topic, sharedSubscriptionName, messageSelector)); checkAutoStart(); return consumer; } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public QueueBrowser createBrowser(Queue queue) { checkSession(); try { QueueBrowser browser = session.createBrowser(queue); checkAutoStart(); return browser; } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public QueueBrowser createBrowser(Queue queue, String messageSelector) { checkSession(); try { QueueBrowser browser = session.createBrowser(queue, messageSelector); checkAutoStart(); return browser; } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public TemporaryQueue createTemporaryQueue() { checkSession(); try { return session.createTemporaryQueue(); } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public TemporaryTopic createTemporaryTopic() { checkSession(); try { return session.createTemporaryTopic(); } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public void unsubscribe(String name) { checkSession(); try { session.unsubscribe(name); } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } @Override public void acknowledge() { checkSession(); if (closed) throw new IllegalStateRuntimeException("Context is closed"); try { if (lastMessagesWaitingAck != null) { lastMessagesWaitingAck.acknowledge(); } } catch (JMSException e) { throw JmsExceptionUtils.convertToRuntimeException(e); } } /** * This is to be used on tests only. It's not part of the interface and it's not guaranteed to be kept * on the API contract. * * @return */ public Session getUsedSession() { return this.session; } private synchronized void checkAutoStart() throws JMSException { if (closed) throw new IllegalStateRuntimeException("Context is closed"); if (autoStart) { connection.start(); } } /** * this is to ensure Context.acknowledge would work on ClientACK */ Message setLastMessage(final JMSConsumer consumer, final Message lastMessageReceived) { if (sessionMode == CLIENT_ACKNOWLEDGE) { lastMessagesWaitingAck = lastMessageReceived; } return lastMessageReceived; } public ThreadAwareContext getThreadAwareContext() { return threadAwareContext; } }