Merge pull request #1304 from slluis/mac-proxy-autoconfig
[mono.git] / mcs / class / System.Transactions / System.Transactions / TransactionScope.cs
1 //
2 // TransactionScope.cs
3 //
4 // Author:
5 //      Atsushi Enomoto  <atsushi@ximian.com>
6 //      Ankit Jain       <JAnkit@novell.com>
7 //
8 // (C)2005 Novell Inc,
9 // (C)2006 Novell Inc,
10 //
11
12 #if NET_2_0
13
14 using DTCOption = System.Transactions.EnterpriseServicesInteropOption;
15
16 namespace System.Transactions
17 {
18         public sealed class TransactionScope : IDisposable
19         {
20                 static TransactionOptions defaultOptions =
21                         new TransactionOptions (0, TransactionManager.DefaultTimeout);
22
23                 Transaction transaction;
24                 Transaction oldTransaction;
25                 TransactionScope parentScope;
26                 TimeSpan timeout;
27
28                 /* Num of non-disposed nested scopes */
29                 int nested;
30
31                 bool disposed;
32                 bool completed;
33                 bool isRoot;
34
35                 public TransactionScope ()
36                         : this (TransactionScopeOption.Required,
37                                 TransactionManager.DefaultTimeout)
38                 {
39                 }
40
41                 public TransactionScope (Transaction transaction)
42                         : this (transaction, TransactionManager.DefaultTimeout)
43                 {
44                 }
45
46                 public TransactionScope (Transaction transaction,
47                         TimeSpan timeout)
48                         : this (transaction, timeout, DTCOption.None)
49                 {
50                 }
51
52                 [MonoTODO ("EnterpriseServicesInteropOption not supported.")]
53                 public TransactionScope (Transaction transaction,
54                         TimeSpan timeout, DTCOption opt)
55                 {
56                         Initialize (TransactionScopeOption.Required,
57                                 transaction, defaultOptions, opt, timeout);
58                 }
59
60                 public TransactionScope (TransactionScopeOption option)
61                         : this (option, TransactionManager.DefaultTimeout)
62                 {
63                 }
64
65                 public TransactionScope (TransactionScopeOption option,
66                         TimeSpan timeout)
67                 {
68                         Initialize (option, null, defaultOptions,
69                                 DTCOption.None, timeout);
70                 }
71
72                 public TransactionScope (TransactionScopeOption scopeOption,
73                         TransactionOptions options)
74                         : this (scopeOption, options, DTCOption.None)
75                 {
76                 }
77
78                 [MonoTODO ("EnterpriseServicesInteropOption not supported")]
79                 public TransactionScope (TransactionScopeOption scopeOption,
80                         TransactionOptions options,
81                         DTCOption opt)
82                 {
83                         Initialize (scopeOption, null, options, opt,
84                                 TransactionManager.DefaultTimeout);
85                 }
86
87                 void Initialize (TransactionScopeOption scopeOption,
88                         Transaction tx, TransactionOptions options,
89                         DTCOption interop, TimeSpan timeout)
90                 {
91                         completed = false;
92                         isRoot = false;
93                         nested = 0;
94
95                         if (timeout < TimeSpan.Zero)
96                                 throw new ArgumentOutOfRangeException ("timeout");
97
98                         this.timeout = timeout;
99
100                         oldTransaction = Transaction.CurrentInternal;
101
102                         Transaction.CurrentInternal = transaction = InitTransaction (tx, scopeOption);
103                         if (transaction != null)
104                                 transaction.InitScope (this);
105                         if (parentScope != null)
106                                 parentScope.nested ++;
107                 }
108
109                 Transaction InitTransaction (Transaction tx, TransactionScopeOption scopeOption)
110                 {
111                         if (tx != null)
112                                 return tx;
113                                 
114                         if (scopeOption == TransactionScopeOption.Suppress) {
115                                 if (Transaction.CurrentInternal != null)
116                                         parentScope = Transaction.CurrentInternal.Scope;
117                                 return null;
118                         }
119
120                         if (scopeOption == TransactionScopeOption.Required) {
121                                 if (Transaction.CurrentInternal == null) {
122                                         isRoot = true;
123                                         return new Transaction ();
124                                 }
125
126                                 parentScope = Transaction.CurrentInternal.Scope;
127                                 return Transaction.CurrentInternal;
128                         }
129
130                         /* RequiresNew */
131                         if (Transaction.CurrentInternal != null)
132                                 parentScope = Transaction.CurrentInternal.Scope;
133                         isRoot = true;
134                         return new Transaction ();
135                 }
136
137                 public void Complete ()
138                 {
139                         if (completed)
140                                 throw new InvalidOperationException ("The current TransactionScope is already complete. You should dispose the TransactionScope.");
141
142                         completed = true;
143                 }
144
145                 internal bool IsComplete {
146                         get { return completed; }
147                 }
148
149                 internal TimeSpan Timeout
150                 {
151                         get { return timeout; }
152                 }
153
154                 public void Dispose ()
155                 {
156                         if (disposed)
157                                 return;
158
159                         disposed = true;
160
161                         if (parentScope != null)
162                                 parentScope.nested --;
163
164                         if (nested > 0) {
165                                 transaction.Rollback ();
166                                 throw new InvalidOperationException ("TransactionScope nested incorrectly");
167                         }
168
169                         if (Transaction.CurrentInternal != transaction) {
170                                 if (transaction != null)
171                                         transaction.Rollback ();
172                                 if (Transaction.CurrentInternal != null)
173                                         Transaction.CurrentInternal.Rollback ();
174
175                                 throw new InvalidOperationException ("Transaction.Current has changed inside of the TransactionScope");
176                         }
177
178                         if (Transaction.CurrentInternal == oldTransaction && oldTransaction != null)
179                                 oldTransaction.Scope = parentScope;
180
181                         Transaction.CurrentInternal = oldTransaction;
182
183                         if (transaction == null)
184                                 /* scope was not in a transaction, (Suppress) */
185                                 return;
186
187                         transaction.Scope = null;
188
189                         if (!IsComplete) {
190                                 transaction.Rollback ();
191                                 return;
192                         }
193
194                         if (!isRoot)
195                                 /* Non-root scope has completed+ended */
196                                 return;
197
198                         transaction.CommitInternal ();
199                 }
200
201
202         }
203 }
204
205 #endif