/// <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>
        /// 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;

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

                // Actually invoke the message listener
                try
                {
                    listener.OnMessage(message, channelToUse);
                }
                catch (Exception e)
                {
                    throw this.WrapToListenerExecutionFailedExceptionIfNeeded(e);
                }
            }
            finally
            {
                ConnectionFactoryUtils.ReleaseResources(resourceHolder);
            }
        }
예제 #3
0
 public MockChannelAwareMessageListener(IMessageListener messageListener, CountdownEvent latch)
 {
     MessageListener = messageListener as IChannelAwareMessageListener;
     Latch           = latch;
 }
 internal void SetChannelAwareMessageListener(IChannelAwareMessageListener listener)
 {
     base.MessageListener = listener;
 }
예제 #5
0
        protected virtual void DoInvokeListener(IChannelAwareMessageListener listener, R.IModel channel, object data)
        {
            Message message = null;
            RabbitResourceHolder resourceHolder = null;
            var channelToUse = channel;
            var boundHere    = false;

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

                    /*
                     * If there is a real transaction, the resource will have been bound; otherwise
                     * we need to bind it temporarily here. Any work done on this channel
                     * will be committed in the finally block.
                     */
                    if (IsChannelLocallyTransacted &&
                        !TransactionSynchronizationManager.IsActualTransactionActive())
                    {
                        resourceHolder.SynchronizedWithTransaction = true;
                        TransactionSynchronizationManager.BindResource(ConnectionFactory, resourceHolder);
                        boundHere = true;
                    }
                }
                else
                {
                    // if locally transacted, bind the current channel to make it available to RabbitTemplate
                    if (IsChannelLocallyTransacted)
                    {
                        var localResourceHolder = new RabbitResourceHolder(channelToUse, false);
                        localResourceHolder.SynchronizedWithTransaction = true;
                        TransactionSynchronizationManager.BindResource(ConnectionFactory, localResourceHolder);
                        boundHere = true;
                    }
                }

                // Actually invoke the message listener...
                try
                {
                    if (data is List <Message> asList)
                    {
                        listener.OnMessageBatch(asList, channelToUse);
                    }
                    else
                    {
                        message = (Message)data;
                        listener.OnMessage(message, channelToUse);
                    }
                }
                catch (Exception e)
                {
                    _logger?.LogError("Exception in OnMessage call", e);
                    throw WrapToListenerExecutionFailedExceptionIfNeeded(e, data);
                }
            }
            finally
            {
                CleanUpAfterInvoke(resourceHolder, channelToUse, boundHere);
            }
        }
        /// <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)
        {
            IConnection conToClose = null;
            IModel channelToClose = null;
            try
            {
                IModel channelToUse = channel;
                if (!ExposeListenerChannel)
                {
                    //We need to expose a separate Session.
                    conToClose = CreateConnection();
                    channelToClose = CreateChannel(conToClose);
                    channelToUse = channelToClose;
                }
                // Actually invoke the message listener
                if (logger.IsDebugEnabled)
                {
                    logger.Debug("Invoking listener with message of type [" + message.GetType() +
                                 "] and session [" + channelToUse + "]");
                }
                listener.OnMessage(message, channelToUse);

                /* TODO need to figure out tx usage more
                // Clean up specially exposed Channel, if any
                if (channelToUse != channel)
                {
                    if (channelToUse.Transacted && ChannelTransacted)
                    {
                        // Transacted session created by this container -> commit.
                        Rabbit.CommitIfNecessary(channelToUse);
                    }
                }*/

            }
            finally
            {
                RabbitUtils.CloseChannel(channelToClose);
                RabbitUtils.CloseConnection(conToClose);
            }
        }
        /// <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);
                    }
                }
            }
        }