1 // Copyright 2004-2008 Castle Project - http://www.castleproject.org/
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle
.Services
.Transaction
18 using System
.ComponentModel
;
19 using Castle
.Core
.Logging
;
22 /// TODO: Ensure this class is thread-safe
24 public class DefaultTransactionManager
: MarshalByRefObject
, ITransactionManager
26 private static readonly object TransactionCreatedEvent
= new object();
27 private static readonly object TransactionCommittedEvent
= new object();
28 private static readonly object TransactionRolledbackEvent
= new object();
29 private static readonly object TransactionFailedEvent
= new object();
30 private static readonly object TransactionDisposedEvent
= new object();
31 private static readonly object ChildTransactionCreatedEvent
= new object();
33 private EventHandlerList events
= new EventHandlerList();
34 private ILogger logger
= NullLogger
.Instance
;
35 private IActivityManager activityManager
;
38 /// Initializes a new instance of the <see cref="DefaultTransactionManager"/> class.
40 public DefaultTransactionManager() : this(new CallContextActivityManager())
45 /// Initializes a new instance of the <see cref="DefaultTransactionManager"/> class.
47 /// <param name="activityManager">The activity manager.</param>
48 public DefaultTransactionManager(IActivityManager activityManager
)
50 this.activityManager
= activityManager
;
54 /// Gets or sets the activity manager.
56 /// <value>The activity manager.</value>
57 public IActivityManager ActivityManager
59 get { return activityManager; }
60 set { activityManager = value; }
64 /// Gets or sets the logger.
66 /// <value>The logger.</value>
69 get { return logger; }
70 set { logger = value; }
73 #region MarshalByRefObject
75 public override object InitializeLifetimeService()
82 #region ITransactionManager Members
85 /// Creates a transaction.
87 /// <param name="transactionMode">The transaction mode.</param>
88 /// <param name="isolationMode">The isolation mode.</param>
89 /// <returns></returns>
90 public virtual ITransaction
CreateTransaction(TransactionMode transactionMode
, IsolationMode isolationMode
)
92 return CreateTransaction(transactionMode
, isolationMode
, false);
96 /// Creates a transaction.
98 /// <param name="transactionMode">The transaction mode.</param>
99 /// <param name="isolationMode">The isolation mode.</param>
100 /// <param name="distributedTransaction">if set to <c>true</c>, the TM will create a distributed transaction.</param>
101 /// <returns></returns>
102 public virtual ITransaction
CreateTransaction(TransactionMode transactionMode
, IsolationMode isolationMode
, bool distributedTransaction
)
104 if (transactionMode
== TransactionMode
.Unspecified
)
106 transactionMode
= ObtainDefaultTransactionMode(transactionMode
);
109 CheckNotSupportedTransaction(transactionMode
);
111 if (CurrentTransaction
== null &&
112 (transactionMode
== TransactionMode
.Supported
||
113 transactionMode
== TransactionMode
.NotSupported
))
118 AbstractTransaction transaction
= null;
120 if (CurrentTransaction
!= null)
122 if (transactionMode
== TransactionMode
.Requires
|| transactionMode
== TransactionMode
.Supported
)
124 transaction
= ((StandardTransaction
) CurrentTransaction
).CreateChildTransaction();
126 RaiseChildTransactionCreated(transaction
, transactionMode
, isolationMode
, distributedTransaction
);
128 logger
.DebugFormat("Child Transaction {0} created", transaction
.GetHashCode());
132 if (transaction
== null)
134 transaction
= InstantiateTransaction(transactionMode
, isolationMode
, distributedTransaction
);
136 if (distributedTransaction
)
139 throw new TransactionException("Distributed transactions are not supported on Mono");
141 transaction
.Enlist(new TransactionScopeResourceAdapter(transactionMode
, isolationMode
));
145 RaiseTransactionCreated(transaction
, transactionMode
, isolationMode
, distributedTransaction
);
147 logger
.DebugFormat("Transaction {0} created", transaction
.GetHashCode());
150 transaction
.Logger
= logger
.CreateChildLogger(transaction
.GetType().FullName
);
152 activityManager
.CurrentActivity
.Push(transaction
);
158 /// Factory method for creating a transaction.
160 /// <param name="transactionMode">The transaction mode.</param>
161 /// <param name="isolationMode">The isolation mode.</param>
162 /// <param name="distributedTransaction">if set to <c>true</c>, the TM will create a distributed transaction.</param>
163 /// <returns>A transaction</returns>
164 protected virtual AbstractTransaction
InstantiateTransaction(TransactionMode transactionMode
, IsolationMode isolationMode
, bool distributedTransaction
)
166 return new StandardTransaction(
167 new TransactionDelegate(RaiseTransactionCommitted
),
168 new TransactionDelegate(RaiseTransactionRolledback
),
169 new TransactionErrorDelegate(RaiseTransactionFailed
),
170 transactionMode
, isolationMode
, distributedTransaction
);
173 public virtual ITransaction CurrentTransaction
175 get { return activityManager.CurrentActivity.CurrentTransaction; }
180 public event TransactionCreationInfoDelegate TransactionCreated
182 add { events.AddHandler(TransactionCreatedEvent, value); }
183 remove { events.RemoveHandler(TransactionCreatedEvent, value); }
186 public event TransactionCreationInfoDelegate ChildTransactionCreated
188 add { events.AddHandler(ChildTransactionCreatedEvent, value); }
189 remove { events.RemoveHandler(ChildTransactionCreatedEvent, value); }
192 public event TransactionDelegate TransactionCommitted
194 add { events.AddHandler(TransactionCommittedEvent, value); }
195 remove { events.RemoveHandler(TransactionCommittedEvent, value); }
198 public event TransactionDelegate TransactionRolledback
200 add { events.AddHandler(TransactionRolledbackEvent, value); }
201 remove { events.RemoveHandler(TransactionRolledbackEvent, value); }
204 public event TransactionErrorDelegate TransactionFailed
206 add { events.AddHandler(TransactionFailedEvent, value); }
207 remove { events.RemoveHandler(TransactionFailedEvent, value); }
210 public event TransactionDelegate TransactionDisposed
212 add { events.AddHandler(TransactionDisposedEvent, value); }
213 remove { events.RemoveHandler(TransactionDisposedEvent, value); }
216 protected void RaiseTransactionCreated(ITransaction transaction
, TransactionMode transactionMode
,
217 IsolationMode isolationMode
, bool distributedTransaction
)
219 TransactionCreationInfoDelegate eventDelegate
= (TransactionCreationInfoDelegate
) events
[TransactionCreatedEvent
];
221 if (eventDelegate
!= null)
223 eventDelegate(transaction
, transactionMode
, isolationMode
, distributedTransaction
);
227 protected void RaiseChildTransactionCreated(ITransaction transaction
, TransactionMode transactionMode
,
228 IsolationMode isolationMode
, bool distributedTransaction
)
230 TransactionCreationInfoDelegate eventDelegate
=
231 (TransactionCreationInfoDelegate
) events
[ChildTransactionCreatedEvent
];
233 if (eventDelegate
!= null)
235 eventDelegate(transaction
, transactionMode
, isolationMode
, distributedTransaction
);
239 protected void RaiseTransactionFailed(ITransaction transaction
, TransactionException exception
)
241 TransactionErrorDelegate eventDelegate
= (TransactionErrorDelegate
)events
[TransactionFailedEvent
];
243 if (eventDelegate
!= null)
245 eventDelegate(transaction
, exception
);
249 protected void RaiseTransactionDisposed(ITransaction transaction
)
251 TransactionDelegate eventDelegate
= (TransactionDelegate
) events
[TransactionDisposedEvent
];
253 if (eventDelegate
!= null)
255 eventDelegate(transaction
);
259 protected void RaiseTransactionCommitted(ITransaction transaction
)
261 TransactionDelegate eventDelegate
= (TransactionDelegate
) events
[TransactionCommittedEvent
];
263 if (eventDelegate
!= null)
265 eventDelegate(transaction
);
269 protected void RaiseTransactionRolledback(ITransaction transaction
)
271 TransactionDelegate eventDelegate
= (TransactionDelegate
) events
[TransactionRolledbackEvent
];
273 if (eventDelegate
!= null)
275 eventDelegate(transaction
);
281 public virtual void Dispose(ITransaction transaction
)
283 if (transaction
== null)
285 throw new ArgumentNullException("transaction", "Tried to dispose a null transaction");
288 if (CurrentTransaction
!= transaction
)
290 throw new ArgumentException("transaction",
291 "Tried to dispose a transaction that is not on the current active transaction");
294 activityManager
.CurrentActivity
.Pop();
296 if (transaction
is IDisposable
)
298 (transaction
as IDisposable
).Dispose();
301 RaiseTransactionDisposed(transaction
);
303 logger
.DebugFormat("Transaction {0} disposed successfully", transaction
.GetHashCode());
308 protected virtual TransactionMode
ObtainDefaultTransactionMode(TransactionMode transactionMode
)
310 return TransactionMode
.Requires
;
313 private void CheckNotSupportedTransaction(TransactionMode transactionMode
)
315 if (transactionMode
== TransactionMode
.NotSupported
&&
316 CurrentTransaction
!= null &&
317 CurrentTransaction
.Status
== TransactionStatus
.Active
)
319 String message
= "There is a transaction active and the transaction mode " +
320 "explicit says that no transaction is supported for this context";
322 logger
.Error(message
);
324 throw new TransactionException(message
);