File: System\Messaging\MessageQueueTransaction.cs
Project: ndp\cdf\src\NetFx20\System.Messaging\System.Messaging.csproj (System.Messaging)
//------------------------------------------------------------------------------
// <copyright file="MessageQueueTransaction.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
namespace System.Messaging
{
    using System.Threading;
    using System.Diagnostics;
    using System.Messaging.Interop;
 
    /// <include file='doc\MessageQueueTransaction.uex' path='docs/doc[@for="MessageQueueTransaction"]/*' />
    /// <devdoc>
    ///    <para>[To be supplied.]</para>
    /// </devdoc>
    public class MessageQueueTransaction : IDisposable
    {
        private ITransaction internalTransaction;
        private MessageQueueTransactionStatus transactionStatus;
        private bool disposed;
 
        /// <include file='doc\MessageQueueTransaction.uex' path='docs/doc[@for="MessageQueueTransaction.MessageQueueTransaction"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Creates a new Message Queuing internal transaction context.
        ///    </para>
        /// </devdoc>                
        public MessageQueueTransaction()
        {
            this.transactionStatus = MessageQueueTransactionStatus.Initialized;
        }
 
        internal ITransaction InnerTransaction
        {
            get
            {
                return this.internalTransaction;
            }
        }
 
        /// <include file='doc\MessageQueueTransaction.uex' path='docs/doc[@for="MessageQueueTransaction.Status"]/*' />
        /// <devdoc>
        ///    <para>
        ///       The status of the transaction that this object represents.
        ///    </para>
        /// </devdoc>   
        public MessageQueueTransactionStatus Status
        {
            get
            {
                return this.transactionStatus;
            }
        }
 
        /// <include file='doc\MessageQueueTransaction.uex' path='docs/doc[@for="MessageQueueTransaction.Abort"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Rolls back the pending internal transaction.
        ///    </para>
        /// </devdoc>
        public void Abort()
        {
            lock (this)
            {
                if (this.internalTransaction == null)
                    throw new InvalidOperationException(Res.GetString(Res.TransactionNotStarted));
                else
                {
                    this.AbortInternalTransaction();
                }
            }
        }
 
        /// <include file='doc\MessageQueueTransaction.uex' path='docs/doc[@for="MessageQueueTransaction.AbortInternalTransaction"]/*' />
        /// <internalonly/>                                 
        private void AbortInternalTransaction()
        {
            int status = this.internalTransaction.Abort(0, 0, 0);
            if (MessageQueue.IsFatalError(status))
                throw new MessageQueueException(status);
 
            this.internalTransaction = null;
            this.transactionStatus = MessageQueueTransactionStatus.Aborted;
        }
 
        /// <include file='doc\MessageQueueTransaction.uex' path='docs/doc[@for="MessageQueueTransaction.Begin"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Begins a new Message Queuing internal transaction context.
        ///    </para>
        /// </devdoc>
        public void Begin()
        {
            //Won't allow begining a new transaction after the object has been disposed.
            if (this.disposed)
                throw new ObjectDisposedException(GetType().Name);
 
            lock (this)
            {
                if (internalTransaction != null)
                    throw new InvalidOperationException(Res.GetString(Res.TransactionStarted));
                else
                {
                    int status = SafeNativeMethods.MQBeginTransaction(out this.internalTransaction);
                    if (MessageQueue.IsFatalError(status))
                    {
                        this.internalTransaction = null;
                        throw new MessageQueueException(status);
                    }
 
                    this.transactionStatus = MessageQueueTransactionStatus.Pending;
                }
            }
        }
 
        /// <include file='doc\MessageQueueTransaction.uex' path='docs/doc[@for="MessageQueueTransaction.BeginQueueOperation"]/*' />
        /// <internalonly/>                                           
        internal ITransaction BeginQueueOperation()
        {
#pragma warning disable 0618
            //@
            Monitor.Enter(this);
#pragma warning restore 0618
            return this.internalTransaction;
        }
 
        /// <include file='doc\MessageQueueTransaction.uex' path='docs/doc[@for="MessageQueueTransaction.Commit"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Commits a pending internal transaction.
        ///    </para>
        /// </devdoc>
        public void Commit()
        {
            lock (this)
            {
                if (this.internalTransaction == null)
                    throw new InvalidOperationException(Res.GetString(Res.TransactionNotStarted));
                else
                {
                    int status = this.internalTransaction.Commit(0, 0, 0);
                    if (MessageQueue.IsFatalError(status))
                        throw new MessageQueueException(status);
 
                    this.internalTransaction = null;
                    this.transactionStatus = MessageQueueTransactionStatus.Committed;
                }
            }
        }
 
        /// <include file='doc\MessageQueueTransaction.uex' path='docs/doc[@for="MessageQueueTransaction.Dispose"]/*' />
        /// <devdoc>
        ///    <para>
        ///       Disposes this transaction instance, if it is in a 
        ///       pending status, the transaction will be aborted.  
        ///    </para>
        /// </devdoc>   
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
 
        /// <include file='doc\MessageQueueTransaction.uex' path='docs/doc[@for="MessageQueueTransaction.Dispose1"]/*' />
        /// <devdoc>
        ///    <para>
        ///    </para>
        /// </devdoc>
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                lock (this)
                {
                    if (internalTransaction != null)
                        this.AbortInternalTransaction();
                }
            }
 
            this.disposed = true;
        }
 
        /// <include file='doc\MessageQueueTransaction.uex' path='docs/doc[@for="MessageQueueTransaction.Finalize"]/*' />
        /// <internalonly/>   
        ~MessageQueueTransaction()
        {
            Dispose(false);
        }
 
        /// <include file='doc\MessageQueueTransaction.uex' path='docs/doc[@for="MessageQueueTransaction.EndQueueOperation"]/*' />
        /// <internalonly/>        
        internal void EndQueueOperation()
        {
            Monitor.Exit(this);
        }
    }
}