1 // Copyright 2004-2007 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 TransactionDisposedEvent
= new object();
30 private static readonly object ChildTransactionCreatedEvent
= new object();
32 private EventHandlerList events
= new EventHandlerList();
33 private ILogger logger
= NullLogger
.Instance
;
34 private IActivityManager activityManager
;
37 /// Initializes a new instance of the <see cref="DefaultTransactionManager"/> class.
39 public DefaultTransactionManager() : this(new CallContextActivityManager())
44 /// Initializes a new instance of the <see cref="DefaultTransactionManager"/> class.
46 /// <param name="activityManager">The activity manager.</param>
47 public DefaultTransactionManager(IActivityManager activityManager
)
49 this.activityManager
= activityManager
;
53 /// Gets or sets the activity manager.
55 /// <value>The activity manager.</value>
56 public IActivityManager ActivityManager
58 get { return activityManager; }
59 set { activityManager = value; }
63 /// Gets or sets the logger.
65 /// <value>The logger.</value>
68 get { return logger; }
69 set { logger = value; }
72 #region MarshalByRefObject
74 public override object InitializeLifetimeService()
81 #region ITransactionManager Members
84 /// Creates a transaction.
86 /// <param name="transactionMode">The transaction mode.</param>
87 /// <param name="isolationMode">The isolation mode.</param>
88 /// <returns></returns>
89 public virtual ITransaction
CreateTransaction(TransactionMode transactionMode
, IsolationMode isolationMode
)
91 return CreateTransaction(transactionMode
, isolationMode
, false);
95 /// Creates a transaction.
97 /// <param name="transactionMode">The transaction mode.</param>
98 /// <param name="isolationMode">The isolation mode.</param>
99 /// <param name="distributedTransaction">if set to <c>true</c>, the TM will create a distributed transaction.</param>
100 /// <returns></returns>
101 public virtual ITransaction
CreateTransaction(TransactionMode transactionMode
, IsolationMode isolationMode
, bool distributedTransaction
)
103 if (transactionMode
== TransactionMode
.Unspecified
)
105 transactionMode
= ObtainDefaultTransactionMode(transactionMode
);
108 CheckNotSupportedTransaction(transactionMode
);
110 if (CurrentTransaction
== null &&
111 (transactionMode
== TransactionMode
.Supported
||
112 transactionMode
== TransactionMode
.NotSupported
))
117 StandardTransaction transaction
= null;
119 if (CurrentTransaction
!= null)
121 if (transactionMode
== TransactionMode
.Requires
|| transactionMode
== TransactionMode
.Supported
)
123 transaction
= ((StandardTransaction
) CurrentTransaction
).CreateChildTransaction();
125 RaiseChildTransactionCreated(transaction
, transactionMode
, isolationMode
, distributedTransaction
);
127 logger
.DebugFormat("Child Transaction {0} created", transaction
.GetHashCode());
131 if (transaction
== null)
133 transaction
= new StandardTransaction(
134 new TransactionDelegate(RaiseTransactionCommitted
),
135 new TransactionDelegate(RaiseTransactionRolledback
), transactionMode
, isolationMode
, distributedTransaction
);
137 if (distributedTransaction
)
139 transaction
.Enlist(new TransactionScopeResourceAdapter(transactionMode
, isolationMode
));
142 RaiseTransactionCreated(transaction
, transactionMode
, isolationMode
, distributedTransaction
);
144 logger
.DebugFormat("Transaction {0} created", transaction
.GetHashCode());
147 transaction
.Logger
= logger
.CreateChildLogger(transaction
.GetType().FullName
);
149 activityManager
.CurrentActivity
.Push(transaction
);
154 public virtual ITransaction CurrentTransaction
156 get { return activityManager.CurrentActivity.CurrentTransaction; }
161 public event TransactionCreationInfoDelegate TransactionCreated
163 add { events.AddHandler(TransactionCreatedEvent, value); }
164 remove { events.RemoveHandler(TransactionCreatedEvent, value); }
167 public event TransactionCreationInfoDelegate ChildTransactionCreated
169 add { events.AddHandler(ChildTransactionCreatedEvent, value); }
170 remove { events.RemoveHandler(ChildTransactionCreatedEvent, value); }
173 public event TransactionDelegate TransactionCommitted
175 add { events.AddHandler(TransactionCommittedEvent, value); }
176 remove { events.RemoveHandler(TransactionCommittedEvent, value); }
179 public event TransactionDelegate TransactionRolledback
181 add { events.AddHandler(TransactionRolledbackEvent, value); }
182 remove { events.RemoveHandler(TransactionRolledbackEvent, value); }
185 public event TransactionDelegate TransactionDisposed
187 add { events.AddHandler(TransactionDisposedEvent, value); }
188 remove { events.RemoveHandler(TransactionDisposedEvent, value); }
191 protected void RaiseTransactionCreated(ITransaction transaction
, TransactionMode transactionMode
,
192 IsolationMode isolationMode
, bool distributedTransaction
)
194 TransactionCreationInfoDelegate eventDelegate
= (TransactionCreationInfoDelegate
) events
[TransactionCreatedEvent
];
196 if (eventDelegate
!= null)
198 eventDelegate(transaction
, transactionMode
, isolationMode
, distributedTransaction
);
202 protected void RaiseChildTransactionCreated(ITransaction transaction
, TransactionMode transactionMode
,
203 IsolationMode isolationMode
, bool distributedTransaction
)
205 TransactionCreationInfoDelegate eventDelegate
=
206 (TransactionCreationInfoDelegate
) events
[ChildTransactionCreatedEvent
];
208 if (eventDelegate
!= null)
210 eventDelegate(transaction
, transactionMode
, isolationMode
, distributedTransaction
);
214 protected void RaiseTransactionDisposed(ITransaction transaction
)
216 TransactionDelegate eventDelegate
= (TransactionDelegate
) events
[TransactionDisposedEvent
];
218 if (eventDelegate
!= null)
220 eventDelegate(transaction
);
224 protected void RaiseTransactionCommitted(ITransaction transaction
)
226 TransactionDelegate eventDelegate
= (TransactionDelegate
) events
[TransactionCommittedEvent
];
228 if (eventDelegate
!= null)
230 eventDelegate(transaction
);
234 protected void RaiseTransactionRolledback(ITransaction transaction
)
236 TransactionDelegate eventDelegate
= (TransactionDelegate
) events
[TransactionRolledbackEvent
];
238 if (eventDelegate
!= null)
240 eventDelegate(transaction
);
246 public virtual void Dispose(ITransaction transaction
)
248 if (transaction
== null)
250 throw new ArgumentNullException("transaction", "Tried to dispose a null transaction");
253 if (CurrentTransaction
!= transaction
)
255 throw new ArgumentException("transaction",
256 "Tried to dispose a transaction that is not on the current active transaction");
259 activityManager
.CurrentActivity
.Pop();
261 if (transaction
is IDisposable
)
263 (transaction
as IDisposable
).Dispose();
266 RaiseTransactionDisposed(transaction
);
268 logger
.DebugFormat("Transaction {0} disposed successfully", transaction
.GetHashCode());
273 protected virtual TransactionMode
ObtainDefaultTransactionMode(TransactionMode transactionMode
)
275 return TransactionMode
.Requires
;
278 private void CheckNotSupportedTransaction(TransactionMode transactionMode
)
280 if (transactionMode
== TransactionMode
.NotSupported
&&
281 CurrentTransaction
!= null &&
282 CurrentTransaction
.Status
== TransactionStatus
.Active
)
284 String message
= "There is a transaction active and the transaction mode " +
285 "explicit says that no transaction is supported for this context";
287 logger
.Error(message
);
289 throw new TransactionException(message
);