/// <summary>Obtain a RabbitMQ Channel that is synchronized with the current transaction, if any.</summary>
        /// <param name="connectionFactory">The connection factory.</param>
        /// <param name="resourceFactory">The resource factory.</param>
        /// <returns>The transactional Channel, or null if none found.</returns>
        private static RabbitResourceHolder DoGetTransactionalResourceHolder(IConnectionFactory connectionFactory, IResourceFactory resourceFactory)
        {
            AssertUtils.ArgumentNotNull(connectionFactory, "ConnectionFactory must not be null");
            AssertUtils.ArgumentNotNull(resourceFactory, "ResourceFactory must not be null");

            var resourceHolder = (RabbitResourceHolder)TransactionSynchronizationManager.GetResource(connectionFactory);

            if (resourceHolder != null)
            {
                var tempchannel = resourceFactory.GetChannel(resourceHolder);
                if (tempchannel != null)
                {
                    return(resourceHolder);
                }
            }

            var resourceHolderToUse = resourceHolder;

            if (resourceHolderToUse == null)
            {
                resourceHolderToUse = new RabbitResourceHolder();
            }

            var    connection = resourceFactory.GetConnection(resourceHolderToUse);
            IModel channel    = null;

            try
            {
                var isExistingCon = connection != null;
                if (!isExistingCon)
                {
                    connection = resourceFactory.CreateConnection();
                    resourceHolderToUse.AddConnection(connection);
                }

                channel = consumerChannel.Value;

                if (channel == null)
                {
                    channel = resourceFactory.CreateChannel(connection);
                }

                resourceHolderToUse.AddChannel(channel, connection);

                if (resourceHolderToUse != resourceHolder)
                {
                    BindResourceToTransaction(resourceHolderToUse, connectionFactory, resourceFactory.IsSynchedLocalTransactionAllowed);
                }

                return(resourceHolderToUse);
            }
            catch (Exception ex)
            {
                RabbitUtils.CloseChannel(channel);
                RabbitUtils.CloseConnection(connection);
                throw new AmqpIOException(ex);
            }
        }
        /// <summary>Release the resources.</summary>
        /// <param name="resourceHolder">The resource holder.</param>
        public static void ReleaseResources(RabbitResourceHolder resourceHolder)
        {
            if (resourceHolder == null || resourceHolder.SynchronizedWithTransaction)
            {
                return;
            }

            RabbitUtils.CloseChannel(resourceHolder.Channel);
            RabbitUtils.CloseConnection(resourceHolder.Connection);
        }
        /// <summary>
        /// Bind a resource to a transaction.
        /// </summary>
        /// <param name="resourceHolder">
        /// The resource holder.
        /// </param>
        /// <param name="connectionFactory">
        /// The connection factory.
        /// </param>
        /// <param name="synched">
        /// The synched.
        /// </param>
        public static void BindResourceToTransaction(RabbitResourceHolder resourceHolder, IConnectionFactory connectionFactory, bool synched)
        {
            if (TransactionSynchronizationManager.HasResource(connectionFactory) || !TransactionSynchronizationManager.ActualTransactionActive || !synched)
            {
                return;
            }

            TransactionSynchronizationManager.BindResource(connectionFactory, resourceHolder);
            resourceHolder.SynchronizedWithTransaction = true;
            if (TransactionSynchronizationManager.SynchronizationActive)
            {
                TransactionSynchronizationManager.RegisterSynchronization(new RabbitResourceSynchronization(resourceHolder, connectionFactory, synched));
            }
        }
        /// <summary>Bind a resource to a transaction.</summary>
        /// <param name="resourceHolder">The resource holder.</param>
        /// <param name="connectionFactory">The connection factory.</param>
        /// <param name="synched">The synched.</param>
        public static void BindResourceToTransaction(RabbitResourceHolder resourceHolder, IConnectionFactory connectionFactory, bool synched)
        {
            if (TransactionSynchronizationManager.HasResource(connectionFactory) || !TransactionSynchronizationManager.ActualTransactionActive || !synched)
            {
                return;
            }

            TransactionSynchronizationManager.BindResource(connectionFactory, resourceHolder);
            resourceHolder.SynchronizedWithTransaction = true;
            if (TransactionSynchronizationManager.SynchronizationActive)
            {
                TransactionSynchronizationManager.RegisterSynchronization(new RabbitResourceSynchronization(resourceHolder, connectionFactory, synched));
            }
        }
        /// <summary>
        /// Obtain a RabbitMQ Channel that is synchronized with the current transaction, if any.
        /// </summary>
        /// <param name="connectionFactory">
        /// The connection factory.
        /// </param>
        /// <param name="resourceFactory">
        /// The resource factory.
        /// </param>
        /// <returns>
        /// The transactional Channel, or null if none found.
        /// </returns>
        /// <exception cref="AmqpException">
        /// </exception>
        private static RabbitResourceHolder DoGetTransactionalResourceHolder(IConnectionFactory connectionFactory, IResourceFactory resourceFactory)
        {
            AssertUtils.ArgumentNotNull(connectionFactory, "ConnectionFactory must not be null");
            AssertUtils.ArgumentNotNull(resourceFactory, "ResourceFactory must not be null");

            var resourceHolder = (RabbitResourceHolder)TransactionSynchronizationManager.GetResource(connectionFactory);
            if (resourceHolder != null)
            {
                var tempchannel = resourceFactory.GetChannel(resourceHolder);
                if (tempchannel != null)
                {
                    return resourceHolder;
                }
            }

            var resourceHolderToUse = resourceHolder;
            if (resourceHolderToUse == null)
            {
                resourceHolderToUse = new RabbitResourceHolder();
            }

            var connection = resourceFactory.GetConnection(resourceHolderToUse);
            IModel channel = null;
            try
            {
                bool isExistingCon = connection != null;
                if (!isExistingCon)
                {
                    connection = resourceFactory.CreateConnection();
                    resourceHolderToUse.AddConnection(connection);
                }
                channel = resourceFactory.CreateChannel(connection);
                resourceHolderToUse.AddChannel(channel, connection);

                if (resourceHolderToUse != resourceHolder)
                {
                    BindResourceToTransaction(resourceHolderToUse, connectionFactory, resourceFactory.IsSynchedLocalTransactionAllowed);
                }

                return resourceHolderToUse;

            }
            catch (Exception ex)
            {
                RabbitUtils.CloseChannel(channel);
                RabbitUtils.CloseConnection(connection);
                throw;
            }
        }
 /// <summary>
 /// Release the resources.
 /// </summary>
 /// <param name="resourceHolder">
 /// The resource holder.
 /// </param>
 public static void ReleaseResources(RabbitResourceHolder resourceHolder)
 {
     if (resourceHolder == null || resourceHolder.SynchronizedWithTransaction)
     {
         return;
     }
     RabbitUtils.CloseChannel(resourceHolder.Channel);
     ReleaseConnection(resourceHolder.Connection);
 }
예제 #7
0
 /// <summary>Create the channel.</summary>
 /// <param name="holder">The rabbit resource holder.</param>
 /// <returns>The channel.</returns>
 protected IModel GetChannel(RabbitResourceHolder holder) { return holder.Channel; }
예제 #8
0
 /// <summary>Fetch an appropriate Connection from the given RabbitResourceHolder.</summary>
 /// <param name="holder">The holder.</param>
 /// <returns>The connection.</returns>
 protected IConnection GetConnection(RabbitResourceHolder holder) { return holder.Connection; }
 /// <summary>
 /// Process resources after commit.
 /// </summary>
 /// <param name="resourceHolder">
 /// The resource holder.
 /// </param>
 protected void ProcessResourceAfterCommit(RabbitResourceHolder resourceHolder)
 {
     resourceHolder.CommitAll();
 }
예제 #10
0
 /// <summary>Gets a connection.</summary>
 /// <param name="holder">The holder.</param>
 /// <returns>The connection.</returns>
 public IConnection GetConnection(RabbitResourceHolder holder) { return holder.Connection; }
예제 #11
0
 /// <summary>Gets a channel.</summary>
 /// <param name="holder">The holder.</param>
 /// <returns>The channel.</returns>
 public IModel GetChannel(RabbitResourceHolder holder) { return holder.Channel; }
예제 #12
0
 /// <summary>
 /// Create the channel.
 /// </summary>
 /// <param name="holder">
 /// The rabbit resource holder.
 /// </param>
 /// <returns>
 /// The channel.
 /// </returns>
 protected RabbitMQ.Client.IModel GetChannel(RabbitResourceHolder holder)
 {
     return holder.Channel;
 }
 /// <summary>Gets a connection.</summary>
 /// <param name="holder">The holder.</param>
 /// <returns>The connection.</returns>
 public IConnection GetConnection(RabbitResourceHolder holder)
 {
     return(holder.Connection);
 }
 /// <summary>Gets a channel.</summary>
 /// <param name="holder">The holder.</param>
 /// <returns>The channel.</returns>
 public IModel GetChannel(RabbitResourceHolder holder)
 {
     return(holder.Channel);
 }
 /// <summary>
 /// Release the resource.
 /// </summary>
 /// <param name="resourceHolder">
 /// The resource holder.
 /// </param>
 /// <param name="resourceKey">
 /// The resource key.
 /// </param>
 protected void ReleaseResource(RabbitResourceHolder resourceHolder, object resourceKey)
 {
     ConnectionFactoryUtils.ReleaseResources(resourceHolder);
 }
        /// <summary>Invokes the specified listener</summary>
        /// <param name="channel">The channel to operate on.</param>
        /// <param name="message">The received message.</param>
        /// <see cref="MessageListener"/>
        public virtual void InvokeListener(IModel channel, Message message)
        {
            var listener = this.MessageListener;
            if (listener is IChannelAwareMessageListener)
            {
                this.DoInvokeListener((IChannelAwareMessageListener)listener, channel, message);
            }
            else if (listener is IMessageListener || listener is Action<Message>)
            {
                var bindChannel = this.ExposeListenerChannel && this.IsChannelLocallyTransacted(channel);
                if (bindChannel)
                {
                    var resourceHolder = new RabbitResourceHolder(channel, false);
                    resourceHolder.SynchronizedWithTransaction = true;
                    TransactionSynchronizationManager.BindResource(this.ConnectionFactory, resourceHolder);
                }

                try
                {
                    if (listener is IMessageListener)
                    {
                        this.DoInvokeListener((IMessageListener)listener, message);
                    }
                    else if (listener is Action<Message>)
                    {
                        this.DoInvokeListener((Action<Message>)listener, message);
                    }
                }
                finally
                {
                    if (bindChannel)
                    {
                        // unbind if we bound
                        TransactionSynchronizationManager.UnbindResource(this.ConnectionFactory);
                    }
                }
            }
            else if (listener != null)
            {
                throw new ArgumentException("Only MessageListener and SessionAwareMessageListener supported: " + listener);
            }
            else
            {
                throw new InvalidOperationException("No message listener specified - see property MessageListener");
            }
        }
        /// <summary>Invoke the specified listener as Spring SessionAwareMessageListener,
        /// exposing a new Rabbit Channel (potentially with its own transaction)
        /// to the listener if demanded.</summary>
        /// <param name="listener">The Spring ISessionAwareMessageListener to invoke.</param>
        /// <param name="channel">The channel to operate on.</param>
        /// <param name="message">The received message.</param>
        /// <see cref="IChannelAwareMessageListener"/><see cref="ExposeListenerChannel"/>
        protected virtual void DoInvokeListener(IChannelAwareMessageListener listener, IModel channel, Message message)
        {
            RabbitResourceHolder resourceHolder = null;

            var channelToUse = channel;
            var boundHere = false;

            try
            {
                if (!this.ExposeListenerChannel)
                {
                    // We need to expose a separate Channel.
                    resourceHolder = this.GetTransactionalResourceHolder();
                    channelToUse = resourceHolder.Channel;

                    if (this.IsChannelLocallyTransacted(channelToUse) &&
                        !TransactionSynchronizationManager.ActualTransactionActive)
                    {
                        resourceHolder.SynchronizedWithTransaction = true;
                        TransactionSynchronizationManager.BindResource(
                            this.ConnectionFactory, 
                            resourceHolder);
                        boundHere = true;
                    }
                }
                else
                {
                    // if locally transacted, bind the current channel to make it available to RabbitTemplate
                    if (this.IsChannelLocallyTransacted(channel))
                    {
                        var localResourceHolder = new RabbitResourceHolder(channelToUse, false);
                        localResourceHolder.SynchronizedWithTransaction = true;
                        TransactionSynchronizationManager.BindResource(this.ConnectionFactory, localResourceHolder);
                        boundHere = true;
                    }
                }

                // Actually invoke the message listener
                try
                {
                    listener.OnMessage(message, channelToUse);
                }
                catch (Exception e)
                {
                    throw this.WrapToListenerExecutionFailedExceptionIfNeeded(e);
                }
            }
            finally
            {
                if (resourceHolder != null && boundHere)
                {
                    // so the channel exposed (because exposeListenerChannel is false) will be closed
                    resourceHolder.SynchronizedWithTransaction = false;
                }

                ConnectionFactoryUtils.ReleaseResources(resourceHolder);
                if (boundHere)
                {
                    // unbind if we bound
                    TransactionSynchronizationManager.UnbindResource(this.ConnectionFactory);
                    if (!this.ExposeListenerChannel && this.IsChannelLocallyTransacted(channelToUse))
                    {
                        /*
                         *  commit the temporary channel we exposed; the consumer's channel
                         *  will be committed later. Note that when exposing a different channel
                         *  when there's no transaction manager, the exposed channel is committed
                         *  on each message, and not based on txSize.
                         */
                        RabbitUtils.CommitIfNecessary(channelToUse);
                    }
                }
            }
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="RabbitResourceSynchronization"/> class.
 /// </summary>
 /// <param name="resourceHolder">
 /// The resource holder.
 /// </param>
 /// <param name="resourceKey">
 /// The resource key.
 /// </param>
 /// <param name="transacted">
 /// The transacted.
 /// </param>
 public RabbitResourceSynchronization(RabbitResourceHolder resourceHolder, object resourceKey, bool transacted)
 {
     //super(resourceHolder, resourceKey);
     this.resourceHolder = resourceHolder;
     this.transacted = transacted;
 }