New test.
[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
27                 /* Num of non-disposed nested scopes */
28                 int nested;
29
30                 TimeSpan timeout;
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]
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                 [MonoTODO]
66                 public TransactionScope (TransactionScopeOption option,
67                         TimeSpan timeout)
68                 {
69                         Initialize (option, null, defaultOptions,
70                                 DTCOption.None, timeout);
71                 }
72
73                 public TransactionScope (TransactionScopeOption scopeOption,
74                         TransactionOptions options)
75                         : this (scopeOption, options, DTCOption.None)
76                 {
77                 }
78
79                 [MonoTODO]
80                 public TransactionScope (TransactionScopeOption scopeOption,
81                         TransactionOptions options,
82                         DTCOption opt)
83                 {
84                         Initialize (scopeOption, null, options, opt,
85                                 TransactionManager.DefaultTimeout);
86                 }
87
88                 void Initialize (TransactionScopeOption scopeOption,
89                         Transaction tx, TransactionOptions options,
90                         DTCOption interop, TimeSpan timeout)
91                 {
92                         this.timeout = timeout;
93                         completed = false;
94                         isRoot = false;
95                         nested = 0;
96
97                         oldTransaction = Transaction.CurrentInternal;
98
99                         Transaction.CurrentInternal = transaction = InitTransaction (tx, scopeOption);
100                         if (transaction != null)
101                                 transaction.InitScope (this);
102                         if (parentScope != null)
103                                 parentScope.nested ++;
104                 }
105
106                 Transaction InitTransaction (Transaction tx, TransactionScopeOption scopeOption)
107                 {
108                         if (tx != null)
109                                 return tx;
110                                 
111                         if (scopeOption == TransactionScopeOption.Suppress) {
112                                 if (Transaction.CurrentInternal != null)
113                                         parentScope = Transaction.CurrentInternal.Scope;
114                                 return null;
115                         }
116
117                         if (scopeOption == TransactionScopeOption.Required) {
118                                 if (Transaction.CurrentInternal == null) {
119                                         isRoot = true;
120                                         return new Transaction ();
121                                 }
122
123                                 parentScope = Transaction.CurrentInternal.Scope;
124                                 return Transaction.CurrentInternal;
125                         }
126
127                         /* RequiresNew */
128                         if (Transaction.CurrentInternal != null)
129                                 parentScope = Transaction.CurrentInternal.Scope;
130                         isRoot = true;
131                         return new Transaction ();
132                 }
133
134                 public void Complete ()
135                 {
136                         if (completed)
137                                 throw new InvalidOperationException ("The current TransactionScope is already complete. You should dispose the TransactionScope.");
138
139                         completed = true;
140                 }
141
142                 internal bool IsComplete {
143                         get { return completed; }
144                 }
145
146                 public void Dispose ()
147                 {
148                         if (disposed)
149                                 return;
150
151                         disposed = true;
152
153                         if (parentScope != null)
154                                 parentScope.nested --;
155
156                         if (nested > 0) {
157                                 transaction.Rollback ();
158                                 throw new InvalidOperationException ("TransactionScope nested incorrectly");
159                         }
160
161                         if (Transaction.CurrentInternal != transaction) {
162                                 if (transaction != null)
163                                         transaction.Rollback ();
164                                 if (Transaction.CurrentInternal != null)
165                                         Transaction.CurrentInternal.Rollback ();
166
167                                 throw new InvalidOperationException ("Transaction.Current has changed inside of the TransactionScope");
168                         }
169
170                         if (Transaction.CurrentInternal == oldTransaction && oldTransaction != null)
171                                 oldTransaction.Scope = parentScope;
172
173                         Transaction.CurrentInternal = oldTransaction;
174
175                         if (transaction == null)
176                                 /* scope was not in a transaction, (Suppress) */
177                                 return;
178
179                         transaction.Scope = null;
180
181                         if (!IsComplete) {
182                                 transaction.Rollback ();
183                                 return;
184                         }
185
186                         if (!isRoot)
187                                 /* Non-root scope has completed+ended */
188                                 return;
189
190                         transaction.CommitInternal ();
191                 }
192
193
194         }
195 }
196
197 #endif