Fixing an issue with output parameters that are of type IntPtr
[castle.git] / Services / Transaction / Castle.Services.Transaction / DefaultTransactionManager.cs
blob36c4b1797d680e8bb6ce1b5a7ef084e04023ee70
1 // Copyright 2004-2008 Castle Project - http://www.castleproject.org/
2 //
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
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
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
17 using System;
18 using System.ComponentModel;
19 using Castle.Core.Logging;
21 /// <summary>
22 /// TODO: Ensure this class is thread-safe
23 /// </summary>
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;
37 /// <summary>
38 /// Initializes a new instance of the <see cref="DefaultTransactionManager"/> class.
39 /// </summary>
40 public DefaultTransactionManager() : this(new CallContextActivityManager())
44 /// <summary>
45 /// Initializes a new instance of the <see cref="DefaultTransactionManager"/> class.
46 /// </summary>
47 /// <param name="activityManager">The activity manager.</param>
48 public DefaultTransactionManager(IActivityManager activityManager)
50 this.activityManager = activityManager;
53 /// <summary>
54 /// Gets or sets the activity manager.
55 /// </summary>
56 /// <value>The activity manager.</value>
57 public IActivityManager ActivityManager
59 get { return activityManager; }
60 set { activityManager = value; }
63 /// <summary>
64 /// Gets or sets the logger.
65 /// </summary>
66 /// <value>The logger.</value>
67 public ILogger Logger
69 get { return logger; }
70 set { logger = value; }
73 #region MarshalByRefObject
75 public override object InitializeLifetimeService()
77 return null;
80 #endregion
82 #region ITransactionManager Members
84 /// <summary>
85 /// Creates a transaction.
86 /// </summary>
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);
95 /// <summary>
96 /// Creates a transaction.
97 /// </summary>
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))
115 return null;
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)
138 #if MONO
139 throw new TransactionException("Distributed transactions are not supported on Mono");
140 #else
141 transaction.Enlist(new TransactionScopeResourceAdapter(transactionMode, isolationMode));
142 #endif
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);
154 return transaction;
157 /// <summary>
158 /// Factory method for creating a transaction.
159 /// </summary>
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; }
178 #region events
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);
279 #endregion
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());
306 #endregion
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);