All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.activemq.artemis.jms.client.ActiveMQSession Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

There is a newer version: 34.0.0.Final
Show newest version
/*
 * 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 static org.apache.activemq.artemis.api.core.ActiveMQExceptionType.QUEUE_DOES_NOT_EXIST;

import jakarta.jms.BytesMessage;
import jakarta.jms.Destination;
import jakarta.jms.IllegalStateException;
import jakarta.jms.InvalidDestinationException;
import jakarta.jms.JMSException;
import jakarta.jms.MapMessage;
import jakarta.jms.Message;
import jakarta.jms.MessageConsumer;
import jakarta.jms.MessageListener;
import jakarta.jms.MessageProducer;
import jakarta.jms.ObjectMessage;
import jakarta.jms.Queue;
import jakarta.jms.QueueBrowser;
import jakarta.jms.QueueReceiver;
import jakarta.jms.QueueSender;
import jakarta.jms.QueueSession;
import jakarta.jms.Session;
import jakarta.jms.StreamMessage;
import jakarta.jms.TemporaryQueue;
import jakarta.jms.TemporaryTopic;
import jakarta.jms.TextMessage;
import jakarta.jms.Topic;
import jakarta.jms.TopicPublisher;
import jakarta.jms.TopicSession;
import jakarta.jms.TopicSubscriber;
import jakarta.jms.TransactionInProgressException;
import javax.transaction.xa.XAResource;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration;
import org.apache.activemq.artemis.api.core.ActiveMQException;
import org.apache.activemq.artemis.api.core.ActiveMQQueueExistsException;
import org.apache.activemq.artemis.api.core.QueueAttributes;
import org.apache.activemq.artemis.api.core.QueueConfiguration;
import org.apache.activemq.artemis.api.core.SimpleString;
import org.apache.activemq.artemis.api.core.client.ClientConsumer;
import org.apache.activemq.artemis.api.core.client.ClientProducer;
import org.apache.activemq.artemis.api.core.client.ClientSession;
import org.apache.activemq.artemis.api.core.client.ClientSession.AddressQuery;
import org.apache.activemq.artemis.api.core.client.ClientSession.QueueQuery;
import org.apache.activemq.artemis.api.core.RoutingType;
import org.apache.activemq.artemis.core.protocol.core.impl.PacketImpl;
import org.apache.activemq.artemis.jms.client.compatible1X.ActiveMQBytesCompatibleMessage;
import org.apache.activemq.artemis.jms.client.compatible1X.ActiveMQCompatibleMessage;
import org.apache.activemq.artemis.jms.client.compatible1X.ActiveMQMapCompatibleMessage;
import org.apache.activemq.artemis.jms.client.compatible1X.ActiveMQObjectCompatibleMessage;
import org.apache.activemq.artemis.jms.client.compatible1X.ActiveMQStreamCompatibleMessage;
import org.apache.activemq.artemis.jms.client.compatible1X.ActiveMQTextCompatibleMessage;
import org.apache.activemq.artemis.selector.filter.FilterException;
import org.apache.activemq.artemis.selector.impl.SelectorParser;
import org.apache.activemq.artemis.utils.AutoCreateUtil;
import org.apache.activemq.artemis.utils.CompositeAddress;
import org.apache.activemq.artemis.utils.SelectorTranslator;

/**
 * ActiveMQ Artemis implementation of a JMS Session.
 * 
* Note that we *do not* support JMS ASF (Application Server Facilities) optional * constructs such as ConnectionConsumer */ public class ActiveMQSession implements QueueSession, TopicSession { public static final int TYPE_GENERIC_SESSION = 0; public static final int TYPE_QUEUE_SESSION = 1; public static final int TYPE_TOPIC_SESSION = 2; private static SimpleString REJECTING_FILTER = SimpleString.of("_AMQX=-1"); private final ConnectionFactoryOptions options; private final ActiveMQConnection connection; private final ClientSession session; private final int sessionType; private final int ackMode; private final boolean transacted; private final boolean xa; private boolean recoverCalled; private final Set consumers = new HashSet<>(); private final boolean cacheDestination; private final boolean enable1xPrefixes; private final Map topicCache = new ConcurrentHashMap<>(); private final Map queueCache = new ConcurrentHashMap<>(); protected ActiveMQSession(final ConnectionFactoryOptions options, final ActiveMQConnection connection, final boolean transacted, final boolean xa, final int ackMode, final boolean cacheDestination, final boolean enable1xPrefixes, final ClientSession session, final int sessionType) { this.options = options; this.connection = connection; this.ackMode = ackMode; this.session = session; this.sessionType = sessionType; this.transacted = transacted; this.xa = xa; this.cacheDestination = cacheDestination; this.enable1xPrefixes = enable1xPrefixes; } // Session implementation ---------------------------------------- @Override public BytesMessage createBytesMessage() throws JMSException { checkClosed(); ActiveMQBytesMessage message; if (enable1xPrefixes) { message = new ActiveMQBytesCompatibleMessage(session); } else { message = new ActiveMQBytesMessage(session); } return message; } @Override public MapMessage createMapMessage() throws JMSException { checkClosed(); ActiveMQMapMessage message; if (enable1xPrefixes) { message = new ActiveMQMapCompatibleMessage(session); } else { message = new ActiveMQMapMessage(session); } return message; } @Override public Message createMessage() throws JMSException { checkClosed(); ActiveMQMessage message; if (enable1xPrefixes) { message = new ActiveMQCompatibleMessage(session); } else { message = new ActiveMQMessage(session); } return message; } @Override public ObjectMessage createObjectMessage() throws JMSException { checkClosed(); ActiveMQObjectMessage message; if (enable1xPrefixes) { message = new ActiveMQObjectCompatibleMessage(session, options); } else { message = new ActiveMQObjectMessage(session, options); } return message; } @Override public ObjectMessage createObjectMessage(final Serializable object) throws JMSException { checkClosed(); ActiveMQObjectMessage msg; if (enable1xPrefixes) { msg = new ActiveMQObjectCompatibleMessage(session, options); } else { msg = new ActiveMQObjectMessage(session, options); } msg.setObject(object); return msg; } @Override public StreamMessage createStreamMessage() throws JMSException { checkClosed(); ActiveMQStreamMessage message; if (enable1xPrefixes) { message = new ActiveMQStreamCompatibleMessage(session); } else { message = new ActiveMQStreamMessage(session); } return message; } @Override public TextMessage createTextMessage() throws JMSException { checkClosed(); ActiveMQTextMessage msg; if (enable1xPrefixes) { msg = new ActiveMQTextCompatibleMessage(session); } else { msg = new ActiveMQTextMessage(session); } msg.setText(null); return msg; } @Override public TextMessage createTextMessage(final String text) throws JMSException { checkClosed(); ActiveMQTextMessage msg; if (enable1xPrefixes) { msg = new ActiveMQTextCompatibleMessage(session); } else { msg = new ActiveMQTextMessage(session); } msg.setText(text); return msg; } @Override public boolean getTransacted() throws JMSException { checkClosed(); return transacted; } @Override public int getAcknowledgeMode() throws JMSException { checkClosed(); return ackMode; } public boolean isXA() { return xa; } @Override public void commit() throws JMSException { if (!transacted) { throw new IllegalStateException("Cannot commit a non-transacted session"); } if (xa) { throw new TransactionInProgressException("Cannot call commit on an XA session"); } try { session.commit(); } catch (ActiveMQException e) { throw JMSExceptionHelper.convertFromActiveMQException(e); } } @Override public void rollback() throws JMSException { if (!transacted) { throw new IllegalStateException("Cannot rollback a non-transacted session"); } if (xa) { throw new TransactionInProgressException("Cannot call rollback on an XA session"); } try { session.rollback(); } catch (ActiveMQException e) { throw JMSExceptionHelper.convertFromActiveMQException(e); } } @Override public void close() throws JMSException { connection.getThreadAwareContext().assertNotCompletionListenerThread(); connection.getThreadAwareContext().assertNotMessageListenerThread(); synchronized (connection) { try { for (ActiveMQMessageConsumer cons : new HashSet<>(consumers)) { cons.close(); } session.close(); connection.removeSession(this); } catch (ActiveMQException e) { throw JMSExceptionHelper.convertFromActiveMQException(e); } } topicCache.clear(); queueCache.clear(); } @Override public void recover() throws JMSException { if (transacted) { throw new IllegalStateException("Cannot recover a transacted session"); } try { session.rollback(true); } catch (ActiveMQException e) { throw JMSExceptionHelper.convertFromActiveMQException(e); } recoverCalled = true; } @Override public MessageListener getMessageListener() throws JMSException { checkClosed(); return null; } @Override public void setMessageListener(final MessageListener listener) throws JMSException { checkClosed(); } @Override public void run() { } @Override public MessageProducer createProducer(final Destination destination) throws JMSException { if (destination != null && !(destination instanceof ActiveMQDestination)) { throw new InvalidDestinationException("Not an ActiveMQ Artemis Destination:" + destination); } try { ActiveMQDestination jbd = (ActiveMQDestination) destination; if (jbd != null) { checkDestination(jbd); } ClientProducer producer = session.createProducer(jbd == null ? null : jbd.getSimpleAddress()); return new ActiveMQMessageProducer(connection, producer, jbd, this, options); } catch (ActiveMQException e) { throw JMSExceptionHelper.convertFromActiveMQException(e); } } void checkDestination(ActiveMQDestination destination) throws JMSException { SimpleString address = destination.getSimpleAddress(); if (!destination.isCreated()) { try { ClientSession.AddressQuery addressQuery = session.addressQuery(address); // First we create the address if (!addressQuery.isExists()) { if (destination.isQueue()) { if (addressQuery.isAutoCreateAddresses() && addressQuery.isAutoCreateQueues()) { session.createAddress(address, RoutingType.ANYCAST, true); } else { throw new InvalidDestinationException("Destination " + address + " does not exist, autoCreateAddresses=" + addressQuery.isAutoCreateAddresses() + " , autoCreateQueues=" + addressQuery.isAutoCreateQueues()); } } else { if (addressQuery.isAutoCreateAddresses()) { session.createAddress(address, RoutingType.MULTICAST, true); } else { throw new InvalidDestinationException("Destination " + address + " does not exist, autoCreateAddresses=" + addressQuery.isAutoCreateAddresses()); } } } else { if ((!addressQuery.isSupportsMulticast() && !destination.isQueue()) || (!addressQuery.isSupportsAnycast() && destination.isQueue())) { throw new InvalidDestinationException("Destination " + address + " exists, but does not support " + (destination.isQueue() ? RoutingType.ANYCAST.name() : RoutingType.MULTICAST.name()) + " routing"); } } // Second we create the queue, the address would have existed or successfully created. if (destination.isQueue()) { ClientSession.QueueQuery queueQuery = session.queueQuery(address); if (!queueQuery.isExists()) { if (addressQuery.isAutoCreateQueues()) { if (destination.isTemporary()) { createTemporaryQueue(destination, RoutingType.ANYCAST, address, null, addressQuery); } else { createQueue(destination, RoutingType.ANYCAST, address, null, true, true, addressQuery); } } else { throw new InvalidDestinationException("Destination " + address + " does not exist, address exists but autoCreateQueues=" + addressQuery.isAutoCreateQueues()); } } } else if (CompositeAddress.isFullyQualified(address)) { // it could be a topic using FQQN ClientSession.QueueQuery queueQuery = session.queueQuery(address); if (!queueQuery.isExists()) { if (addressQuery.isAutoCreateQueues()) { if (destination.isTemporary()) { createTemporaryQueue(destination, RoutingType.MULTICAST, address, null, addressQuery); } else { createQueue(destination, RoutingType.MULTICAST, address, null, true, true, addressQuery); } } else { throw new InvalidDestinationException("Destination " + address + " does not exist, address exists but autoCreateQueues=" + addressQuery.isAutoCreateQueues()); } } } } catch (ActiveMQQueueExistsException thatsOK) { // nothing to be done } catch (ActiveMQException e) { throw JMSExceptionHelper.convertFromActiveMQException(e); } // this is done at the end, if no exceptions are thrown destination.setCreated(true); } } @Override public MessageConsumer createConsumer(final Destination destination) throws JMSException { return createConsumer(destination, null, false); } @Override public MessageConsumer createConsumer(final Destination destination, final String messageSelector) throws JMSException { return createConsumer(destination, messageSelector, false); } @Override public MessageConsumer createConsumer(final Destination destination, final String messageSelector, final boolean noLocal) throws JMSException { if (destination == null) { throw new InvalidDestinationException("Cannot create a consumer with a null destination"); } if (!(destination instanceof ActiveMQDestination)) { throw new InvalidDestinationException("Not an ActiveMQDestination:" + destination); } ActiveMQDestination jbdest = (ActiveMQDestination) destination; if (jbdest.isTemporary() && !connection.containsTemporaryQueue(jbdest.getSimpleAddress())) { throw new JMSException("Can not create consumer for temporary destination " + destination + " from another JMS connection"); } return createConsumer(jbdest, null, messageSelector, noLocal, ConsumerDurability.NON_DURABLE); } @Override public Queue createQueue(final String queueName) throws JMSException { // As per spec. section 4.11 if (sessionType == ActiveMQSession.TYPE_TOPIC_SESSION) { throw new IllegalStateException("Cannot create a queue using a TopicSession"); } try { Queue queue = null; if (cacheDestination) { queue = queueCache.get(queueName); } if (queue == null) { queue = internalCreateQueue(queueName); } if (cacheDestination) { queueCache.put(queueName, queue); } return queue; } catch (ActiveMQException e) { throw JMSExceptionHelper.convertFromActiveMQException(e); } } protected Queue internalCreateQueue(String queueName) throws ActiveMQException, JMSException { ActiveMQQueue queue = lookupQueue(queueName, false); if (queue == null) { queue = lookupQueue(queueName, true); } if (queue == null) { queue = internalCreateQueueCompatibility("jms.queue." + queueName); } if (queue == null) { throw new JMSException("There is no queue with name " + queueName); } else { return queue; } } protected ActiveMQQueue internalCreateQueueCompatibility(String queueName) throws ActiveMQException, JMSException { ActiveMQQueue queue = lookupQueue(queueName, false); if (queue == null) { queue = lookupQueue(queueName, true); } return queue; } @Override public Topic createTopic(final String topicName) throws JMSException { // As per spec. section 4.11 if (sessionType == ActiveMQSession.TYPE_QUEUE_SESSION) { throw new IllegalStateException("Cannot create a topic on a QueueSession"); } try { Topic topic = null; if (cacheDestination) { topic = topicCache.get(topicName); } if (topic == null) { topic = internalCreateTopic(topicName, false); } if (cacheDestination) { topicCache.put(topicName, topic); } return topic; } catch (ActiveMQException e) { throw JMSExceptionHelper.convertFromActiveMQException(e); } } protected Topic internalCreateTopic(String topicName, boolean retry) throws ActiveMQException, JMSException { ActiveMQTopic topic = lookupTopic(topicName, false); if (topic == null) { topic = lookupTopic(topicName, true); } if (topic == null) { if (!retry) { return internalCreateTopic("jms.topic." + topicName, true); } throw new JMSException("There is no topic with name " + topicName); } else { return topic; } } @Override public TopicSubscriber createDurableSubscriber(final Topic topic, final String name) throws JMSException { return createDurableSubscriber(topic, name, null, false); } @Override public TopicSubscriber createDurableSubscriber(final Topic topic, final String name, String messageSelector, final boolean noLocal) throws JMSException { // As per spec. section 4.11 if (sessionType == ActiveMQSession.TYPE_QUEUE_SESSION) { throw new IllegalStateException("Cannot create a durable subscriber on a QueueSession"); } checkTopic(topic); if (!(topic instanceof ActiveMQDestination)) { throw new InvalidDestinationException("Not an ActiveMQTopic:" + topic); } if ("".equals(messageSelector)) { messageSelector = null; } ActiveMQDestination jbdest = (ActiveMQDestination) topic; if (jbdest.isQueue()) { throw new InvalidDestinationException("Cannot create a subscriber on a queue"); } return createConsumer(jbdest, name, messageSelector, noLocal, ConsumerDurability.DURABLE); } private void checkTopic(Topic topic) throws InvalidDestinationException { if (topic == null) { throw ActiveMQJMSClientBundle.BUNDLE.nullTopic(); } } @Override public MessageConsumer createSharedConsumer(Topic topic, String sharedSubscriptionName) throws JMSException { return createSharedConsumer(topic, sharedSubscriptionName, null); } /** * Note: Needs to throw an exception if a subscriptionName is already in use by another topic, or if the messageSelector is different * * validate multiple subscriptions on the same session. * validate multiple subscriptions on different sessions * validate failure in one connection while another connection stills fine. * Validate different filters in different possible scenarios * * @param topic * @param name * @param messageSelector * @return * @throws JMSException */ @Override public MessageConsumer createSharedConsumer(Topic topic, String name, String messageSelector) throws JMSException { if (sessionType == ActiveMQSession.TYPE_QUEUE_SESSION) { throw new IllegalStateException("Cannot create a shared consumer on a QueueSession"); } checkTopic(topic); ActiveMQTopic localTopic; if (topic instanceof ActiveMQTopic) { localTopic = (ActiveMQTopic) topic; } else { localTopic = new ActiveMQTopic(topic.getTopicName()); } return internalCreateSharedConsumer(localTopic, name, messageSelector, ConsumerDurability.NON_DURABLE); } @Override public MessageConsumer createDurableConsumer(Topic topic, String name) throws JMSException { return createDurableConsumer(topic, name, null, false); } @Override public MessageConsumer createDurableConsumer(Topic topic, String name, String messageSelector, boolean noLocal) throws JMSException { if (sessionType == ActiveMQSession.TYPE_QUEUE_SESSION) { throw new IllegalStateException("Cannot create a durable consumer on a QueueSession"); } checkTopic(topic); ActiveMQTopic localTopic; if (topic instanceof ActiveMQTopic) { localTopic = (ActiveMQTopic) topic; } else { localTopic = new ActiveMQTopic(topic.getTopicName()); } return createConsumer(localTopic, name, messageSelector, noLocal, ConsumerDurability.DURABLE); } @Override public MessageConsumer createSharedDurableConsumer(Topic topic, String name) throws JMSException { return createSharedDurableConsumer(topic, name, null); } @Override public MessageConsumer createSharedDurableConsumer(Topic topic, String name, String messageSelector) throws JMSException { if (sessionType == ActiveMQSession.TYPE_QUEUE_SESSION) { throw new IllegalStateException("Cannot create a shared durable consumer on a QueueSession"); } checkTopic(topic); ActiveMQTopic localTopic; if (topic instanceof ActiveMQTopic) { localTopic = (ActiveMQTopic) topic; } else { localTopic = new ActiveMQTopic(topic.getTopicName()); } return internalCreateSharedConsumer(localTopic, name, messageSelector, ConsumerDurability.DURABLE); } @Deprecated(forRemoval = true) public String getDeserializationBlackList() { return getDeserializationDenyList(); } @Deprecated(forRemoval = true) public String getDeserializationWhiteList() { return getDeserializationAllowList(); } public String getDeserializationDenyList() { return connection.getDeserializationDenyList(); } public String getDeserializationAllowList() { return connection.getDeserializationAllowList(); } enum ConsumerDurability { DURABLE, NON_DURABLE; } /** * This is an internal method for shared consumers */ private ActiveMQMessageConsumer internalCreateSharedConsumer(final ActiveMQDestination dest, final String subscriptionName, String selectorString, ConsumerDurability durability) throws JMSException { try { if (dest.isQueue()) { // This is not really possible unless someone makes a mistake on code // createSharedConsumer only accepts Topics by declaration throw new RuntimeException("Internal error: createSharedConsumer is only meant for Topics"); } if (subscriptionName == null) { throw ActiveMQJMSClientBundle.BUNDLE.invalidSubscriptionName(); } selectorString = "".equals(selectorString) ? null : selectorString; SimpleString coreFilterString = null; if (selectorString != null) { coreFilterString = SimpleString.of(SelectorTranslator.convertToActiveMQFilterString(selectorString)); } ClientConsumer consumer; SimpleString autoDeleteQueueName = null; AddressQuery response = session.addressQuery(dest.getSimpleAddress()); if (!response.isExists() && !response.isAutoCreateAddresses()) { throw ActiveMQJMSClientBundle.BUNDLE.destinationDoesNotExist(dest.getSimpleAddress()); } SimpleString queueName; if (dest.isTemporary() && durability == ConsumerDurability.DURABLE) { throw new InvalidDestinationException("Cannot create a durable subscription on a temporary topic"); } queueName = ActiveMQDestination.createQueueNameForSubscription(durability == ConsumerDurability.DURABLE, connection.getClientID(), subscriptionName); QueueQuery subResponse = session.queueQuery(queueName); if ((!subResponse.isExists() || !Objects.equals(subResponse.getAddress(), dest.getSimpleAddress()) || !Objects.equals(subResponse.getFilterString(), coreFilterString)) && !Boolean.TRUE.equals(subResponse.isConfigurationManaged())) { try { createSharedQueue(dest, RoutingType.MULTICAST, queueName, coreFilterString, durability == ConsumerDurability.DURABLE, response); } catch (ActiveMQQueueExistsException ignored) { // We ignore this because querying and then creating the queue wouldn't be idempotent // we could also add a parameter to ignore existence what would require a bigger work around to avoid // compatibility. } } consumer = createClientConsumer(dest, queueName, null); ActiveMQMessageConsumer jbc = new ActiveMQMessageConsumer(options, connection, this, consumer, false, dest, selectorString, autoDeleteQueueName); consumers.add(jbc); return jbc; } catch (ActiveMQException e) { throw JMSExceptionHelper.convertFromActiveMQException(e); } } private ActiveMQMessageConsumer createConsumer(final ActiveMQDestination dest, final String subscriptionName, String selectorString, final boolean noLocal, ConsumerDurability durability) throws JMSException { try { selectorString = "".equals(selectorString) ? null : selectorString; if (noLocal) { connection.setHasNoLocal(); String filter; if (connection.getClientID() != null) { filter = ActiveMQConnection.CONNECTION_ID_PROPERTY_NAME.toString() + "<>'" + connection.getClientID() + "'"; } else { filter = ActiveMQConnection.CONNECTION_ID_PROPERTY_NAME.toString() + "<>'" + connection.getUID() + "'"; } if (selectorString != null) { selectorString += " AND " + filter; } else { selectorString = filter; } } SimpleString coreFilterString = null; if (selectorString != null) { coreFilterString = SimpleString.of(SelectorTranslator.convertToActiveMQFilterString(selectorString)); } ClientConsumer consumer; SimpleString autoDeleteQueueName = null; if (dest.isQueue()) { try { AutoCreateUtil.autoCreateQueue(session, dest.getSimpleAddress(), null); } catch (ActiveMQException ex) { if (ex.getType() == QUEUE_DOES_NOT_EXIST) { throw new InvalidDestinationException("Destination " + dest.getName() + " does not exist"); } throw ex; } dest.setCreated(true); consumer = createClientConsumer(dest, null, coreFilterString); } else { AddressQuery response = session.addressQuery(dest.getSimpleAddress()); if (!response.isExists()) { if (response.isAutoCreateAddresses()) { session.createAddress(dest.getSimpleAddress(), RoutingType.MULTICAST, true); } else { throw new InvalidDestinationException("Topic " + dest.getName() + " does not exist"); } } dest.setCreated(true); SimpleString queueName; if (subscriptionName == null) { if (durability != ConsumerDurability.NON_DURABLE) throw new RuntimeException("Subscription name cannot be null for durable topic consumer"); // Non durable sub if (CompositeAddress.isFullyQualified(dest.getAddress())) { queueName = createFQQNSubscription(dest, coreFilterString, response); } else { queueName = SimpleString.of(UUID.randomUUID().toString()); createTemporaryQueue(dest, RoutingType.MULTICAST, queueName, coreFilterString, response); } consumer = createClientConsumer(dest, queueName, coreFilterString); autoDeleteQueueName = queueName; } else { // Durable sub if (durability != ConsumerDurability.DURABLE) throw new RuntimeException("Subscription name must be null for non-durable topic consumer"); if (connection.getClientID() == null) { throw new IllegalStateException("Cannot create durable subscription - client ID has not been set"); } if (dest.isTemporary()) { throw new InvalidDestinationException("Cannot create a durable subscription on a temporary topic"); } queueName = ActiveMQDestination.createQueueNameForSubscription(true, connection.getClientID(), subscriptionName); QueueQuery subResponse = session.queueQuery(queueName); if (!subResponse.isExists()) { // durable subscription queues are not technically considered to be auto-created createQueue(dest, RoutingType.MULTICAST, queueName, coreFilterString, true, false, response); } else { // Already exists if (subResponse.getConsumerCount() > 0) { throw new IllegalStateException("Cannot create a subscriber on the durable subscription since it already has subscriber(s)"); } // From jakarta.jms.Session Javadoc (and also JMS 1.1 6.11.1): // A client can change an existing durable subscription by // creating a durable TopicSubscriber with the same name and // a new topic and/or message selector. // Changing a durable subscriber is equivalent to unsubscribing // (deleting) the old one and creating a new one. SimpleString oldFilterString = subResponse.getFilterString(); boolean selectorChanged = coreFilterString == null && oldFilterString != null || oldFilterString == null && coreFilterString != null || oldFilterString != null && coreFilterString != null && !oldFilterString.equals(coreFilterString); SimpleString oldTopicName = subResponse.getAddress(); boolean topicChanged = !oldTopicName.equals(dest.getSimpleAddress()); if ((selectorChanged || topicChanged) && !subResponse.isConfigurationManaged()) { // Delete the old durable sub session.deleteQueue(queueName); // Create the new one createQueue(dest, RoutingType.MULTICAST, queueName, coreFilterString, true, false, response); } } consumer = createClientConsumer(dest, queueName, null); } } ActiveMQMessageConsumer jbc = new ActiveMQMessageConsumer(options, connection, this, consumer, noLocal, dest, selectorString, autoDeleteQueueName); consumers.add(jbc); return jbc; } catch (ActiveMQException e) { throw JMSExceptionHelper.convertFromActiveMQException(e); } } // This method is for the actual queue creation on the Multicast queue / subscription private SimpleString createFQQNSubscription(ActiveMQDestination dest, SimpleString coreFilterString, AddressQuery response) throws ActiveMQException, JMSException { SimpleString queueName; queueName = CompositeAddress.extractQueueName(dest.getSimpleAddress()); if (!response.isExists() || !response.getQueueNames().contains(AutoCreateUtil.getCoreQueueName(session, dest.getSimpleAddress()))) { if (response.isAutoCreateQueues()) { try { createQueue(dest, RoutingType.MULTICAST, dest.getSimpleAddress(), coreFilterString, true, true, response); return queueName; } catch (ActiveMQQueueExistsException e) { // The queue was created by another client/admin between the query check and send create queue packet // on this case we will switch to the regular verification to validate the coreFilterString } } else { throw new InvalidDestinationException("Destination " + dest.getName() + " does not exist"); } } QueueQuery queueQuery = session.queueQuery(queueName); if (!queueQuery.isExists()) { throw new InvalidDestinationException("Destination " + queueName + " does not exist"); } if (coreFilterString != null && queueQuery.getFilterString() != null && !coreFilterString.equals(queueQuery.getFilterString())) { throw new JMSException(queueName + " filter mismatch [" + coreFilterString + "] is different than existing filter [" + queueQuery.getFilterString() + "]"); } return queueName; } private ClientConsumer createClientConsumer(ActiveMQDestination destination, SimpleString queueName, SimpleString coreFilterString) throws ActiveMQException { QueueAttributes queueAttributes = destination.getQueueAttributes() == null ? new QueueAttributes() : destination.getQueueAttributes(); int priority = queueAttributes.getConsumerPriority() == null ? ActiveMQDefaultConfiguration.getDefaultConsumerPriority() : queueAttributes.getConsumerPriority(); return session.createConsumer(queueName == null ? destination.getSimpleAddress() : queueName, coreFilterString, priority, false); } public void ackAllConsumers() throws JMSException { checkClosed(); } @Override public QueueBrowser createBrowser(final Queue queue) throws JMSException { return createBrowser(queue, null); } @Override public QueueBrowser createBrowser(final Queue queue, String filterString) throws JMSException { // As per spec. section 4.11 if (sessionType == ActiveMQSession.TYPE_TOPIC_SESSION) { throw new IllegalStateException("Cannot create a browser on a TopicSession"); } if (queue == null) { throw new InvalidDestinationException("Cannot create a browser with a null queue"); } if (!(queue instanceof ActiveMQDestination)) { throw new InvalidDestinationException("Not an ActiveMQQueue:" + queue); } if ("".equals(filterString)) { filterString = null; } // eager test of the filter syntax as required by JMS spec try { if (filterString != null) { SelectorParser.parse(filterString.trim()); } } catch (FilterException e) { throw JMSExceptionHelper.convertFromActiveMQException(ActiveMQJMSClientBundle.BUNDLE.invalidFilter(SimpleString.of(filterString), e)); } ActiveMQDestination activeMQDestination = (ActiveMQDestination) queue; if (!activeMQDestination.isQueue()) { throw new InvalidDestinationException("Cannot create a browser on a topic"); } try { AddressQuery response = session.addressQuery(SimpleString.of(activeMQDestination.getAddress())); if (!response.isExists()) { if (response.isAutoCreateQueues()) { createQueue(activeMQDestination, RoutingType.ANYCAST, activeMQDestination.getSimpleAddress(), null, true, true, response); } else { throw new InvalidDestinationException("Destination " + activeMQDestination.getName() + " does not exist"); } } } catch (ActiveMQException e) { throw JMSExceptionHelper.convertFromActiveMQException(e); } return new ActiveMQQueueBrowser(options, (ActiveMQQueue) activeMQDestination, filterString, session, enable1xPrefixes); } @Override public TemporaryQueue createTemporaryQueue() throws JMSException { // As per spec. section 4.11 if (sessionType == ActiveMQSession.TYPE_TOPIC_SESSION) { throw new IllegalStateException("Cannot create a temporary queue using a TopicSession"); } try { final ActiveMQTemporaryQueue queue; if (enable1xPrefixes) { queue = ActiveMQDestination.createTemporaryQueue(this, PacketImpl.OLD_TEMP_QUEUE_PREFIX.toString()); } else { queue = ActiveMQDestination.createTemporaryQueue(this); } SimpleString simpleAddress = queue.getSimpleAddress(); session.createQueue(QueueConfiguration.of(simpleAddress).setRoutingType(RoutingType.ANYCAST).setDurable(false).setTemporary(true)); connection.addTemporaryQueue(simpleAddress); queue.setCreated(true); return queue; } catch (ActiveMQException e) { throw JMSExceptionHelper.convertFromActiveMQException(e); } } @Override public TemporaryTopic createTemporaryTopic() throws JMSException { // As per spec. section 4.11 if (sessionType == ActiveMQSession.TYPE_QUEUE_SESSION) { throw new IllegalStateException("Cannot create a temporary topic on a QueueSession"); } try { final ActiveMQTemporaryTopic topic; if (enable1xPrefixes) { topic = ActiveMQDestination.createTemporaryTopic(this, PacketImpl.OLD_TEMP_TOPIC_PREFIX.toString()); } else { topic = ActiveMQDestination.createTemporaryTopic(this); } SimpleString simpleAddress = topic.getSimpleAddress(); // We create a dummy subscription on the topic, that never receives messages - this is so we can perform JMS // checks when routing messages to a topic that // does not exist - otherwise we would not be able to distinguish from a non existent topic and one with no // subscriptions - core has no notion of a topic session.createQueue(QueueConfiguration.of(simpleAddress).setAddress(simpleAddress).setFilterString(ActiveMQSession.REJECTING_FILTER).setDurable(false).setTemporary(true)); connection.addTemporaryQueue(simpleAddress); return topic; } catch (ActiveMQException e) { throw JMSExceptionHelper.convertFromActiveMQException(e); } } @Override public void unsubscribe(final String name) throws JMSException { // As per spec. section 4.11 if (sessionType == ActiveMQSession.TYPE_QUEUE_SESSION) { throw new IllegalStateException("Cannot unsubscribe using a QueueSession"); } SimpleString queueName = ActiveMQDestination.createQueueNameForSubscription(true, connection.getClientID(), name); try { QueueQuery response = session.queueQuery(queueName); if (!response.isExists()) { throw new InvalidDestinationException("Cannot unsubscribe, subscription with name " + name + " does not exist"); } if (response.getConsumerCount() != 0) { throw new IllegalStateException("Cannot unsubscribe durable subscription " + name + " since it has active subscribers"); } session.deleteQueue(queueName); } catch (ActiveMQException e) { throw JMSExceptionHelper.convertFromActiveMQException(e); } } // XASession implementation public Session getSession() throws JMSException { if (!xa) { throw new IllegalStateException("Isn't an XASession"); } return this; } public XAResource getXAResource() { return session.getXAResource(); } // QueueSession implementation @Override public QueueReceiver createReceiver(final Queue queue, final String messageSelector) throws JMSException { return (QueueReceiver) createConsumer(queue, messageSelector); } @Override public QueueReceiver createReceiver(final Queue queue) throws JMSException { return (QueueReceiver) createConsumer(queue); } @Override public QueueSender createSender(final Queue queue) throws JMSException { return (QueueSender) createProducer(queue); } // XAQueueSession implementation public QueueSession getQueueSession() throws JMSException { return (QueueSession) getSession(); } // TopicSession implementation @Override public TopicPublisher createPublisher(final Topic topic) throws JMSException { return (TopicPublisher) createProducer(topic); } @Override public TopicSubscriber createSubscriber(final Topic topic, final String messageSelector, final boolean noLocal) throws JMSException { return (TopicSubscriber) createConsumer(topic, messageSelector, noLocal); } @Override public TopicSubscriber createSubscriber(final Topic topic) throws JMSException { return (TopicSubscriber) createConsumer(topic); } // XATopicSession implementation public TopicSession getTopicSession() throws JMSException { return (TopicSession) getSession(); } @Override public String toString() { return "ActiveMQSession->" + session; } public ClientSession getCoreSession() { return session; } public boolean isRecoverCalled() { return recoverCalled; } public void setRecoverCalled(final boolean recoverCalled) { this.recoverCalled = recoverCalled; } public void deleteTemporaryTopic(final ActiveMQDestination tempTopic) throws JMSException { if (!tempTopic.isTemporary()) { throw new InvalidDestinationException("Not a temporary topic " + tempTopic); } try { AddressQuery response = session.addressQuery(tempTopic.getSimpleAddress()); if (!response.isExists()) { throw new InvalidDestinationException("Cannot delete temporary topic " + tempTopic.getName() + " does not exist"); } if (response.getQueueNames().size() > 1) { throw new IllegalStateException("Cannot delete temporary topic " + tempTopic.getName() + " since it has subscribers"); } SimpleString address = tempTopic.getSimpleAddress(); session.deleteQueue(address); connection.removeTemporaryQueue(address); } catch (ActiveMQException e) { throw JMSExceptionHelper.convertFromActiveMQException(e); } } public void deleteTemporaryQueue(final ActiveMQDestination tempQueue) throws JMSException { if (!tempQueue.isTemporary()) { throw new InvalidDestinationException("Not a temporary queue " + tempQueue); } try { QueueQuery response = session.queueQuery(tempQueue.getSimpleAddress()); if (!response.isExists()) { throw new InvalidDestinationException("Cannot delete temporary queue " + tempQueue.getName() + " does not exist"); } if (response.getConsumerCount() > 0) { throw new IllegalStateException("Cannot delete temporary queue " + tempQueue.getName() + " since it has subscribers"); } SimpleString address = tempQueue.getSimpleAddress(); session.deleteQueue(address); connection.removeTemporaryQueue(address); } catch (ActiveMQException e) { throw JMSExceptionHelper.convertFromActiveMQException(e); } } public void start() throws JMSException { try { session.start(); } catch (ActiveMQException e) { throw JMSExceptionHelper.convertFromActiveMQException(e); } } public void stop() throws JMSException { try { session.stop(); } catch (ActiveMQException e) { throw JMSExceptionHelper.convertFromActiveMQException(e); } } public void removeConsumer(final ActiveMQMessageConsumer consumer) { consumers.remove(consumer); } public boolean isEnable1xPrefixes() { return enable1xPrefixes; } void deleteQueue(final SimpleString queueName) throws JMSException { if (!session.isClosed()) { try { session.deleteQueue(queueName); } catch (ActiveMQException ignore) { // Exception on deleting queue shouldn't prevent close from completing } } } public ActiveMQConnection getConnection() { return connection; } void checkClosed() throws JMSException { if (session.isClosed()) { throw new IllegalStateException("Session is closed"); } } void createTemporaryQueue(ActiveMQDestination destination, RoutingType routingType, SimpleString queueName, SimpleString filter, ClientSession.AddressQuery addressQuery) throws ActiveMQException { QueueConfiguration queueConfiguration = destination.getQueueConfiguration() == null ? QueueConfiguration.of(queueName) : destination.getQueueConfiguration(); AutoCreateUtil.setRequiredQueueConfigurationIfNotSet(queueConfiguration, addressQuery, routingType, filter, false); session.createQueue(queueConfiguration.setName(queueName).setAddress(destination.getAddress()).setDurable(false).setTemporary(true)); } void createSharedQueue(ActiveMQDestination destination, RoutingType routingType, SimpleString queueName, SimpleString filter, boolean durable, ClientSession.AddressQuery addressQuery) throws ActiveMQException { QueueConfiguration queueConfiguration = destination.getQueueConfiguration() == null ? QueueConfiguration.of(queueName) : destination.getQueueConfiguration(); AutoCreateUtil.setRequiredQueueConfigurationIfNotSet(queueConfiguration, addressQuery, routingType, filter, durable); session.createSharedQueue(queueConfiguration.setName(queueName).setAddress(destination.getAddress()).setDurable(durable)); } void createQueue(ActiveMQDestination destination, RoutingType routingType, SimpleString queueName, SimpleString filter, boolean durable, boolean autoCreated, ClientSession.AddressQuery addressQuery) throws ActiveMQException { QueueConfiguration queueConfiguration = destination.getQueueConfiguration() == null ? QueueConfiguration.of(queueName) : destination.getQueueConfiguration(); AutoCreateUtil.setRequiredQueueConfigurationIfNotSet(queueConfiguration, addressQuery, routingType, filter, durable); session.createQueue(queueConfiguration.setName(queueName).setAddress(destination.getAddress()).setAutoCreated(autoCreated).setDurable(durable)); } private ActiveMQQueue lookupQueue(final String queueName, boolean isTemporary) throws ActiveMQException { String queueNameToUse = queueName; if (enable1xPrefixes) { queueNameToUse = (isTemporary ? PacketImpl.OLD_TEMP_QUEUE_PREFIX.toString() : PacketImpl.OLD_QUEUE_PREFIX.toString()) + queueName; } ActiveMQQueue queue; if (isTemporary) { queue = ActiveMQDestination.createTemporaryQueue(queueNameToUse); } else { queue = ActiveMQDestination.createQueue(queueNameToUse); } if (queueName != queueNameToUse) { queue.setName(queueName); } QueueQuery response = session.queueQuery(queue.getSimpleAddress()); if (!response.isExists() && !response.isAutoCreateQueues()) { return null; } else { return queue; } } private ActiveMQTopic lookupTopic(final String topicName, final boolean isTemporary) throws ActiveMQException { String topicNameToUse = topicName; if (enable1xPrefixes) { topicNameToUse = (isTemporary ? PacketImpl.OLD_TEMP_TOPIC_PREFIX.toString() : PacketImpl.OLD_TOPIC_PREFIX.toString()) + topicName; } ActiveMQTopic topic; if (isTemporary) { topic = ActiveMQDestination.createTemporaryTopic(topicNameToUse); } else { topic = ActiveMQDestination.createTopic(topicNameToUse); } if (topicNameToUse != topicName) { topic.setName(topicName); } AddressQuery query = session.addressQuery(topic.getSimpleAddress()); if (!query.isExists() && !query.isAutoCreateAddresses()) { return null; } else { return topic; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy