Added DictionaryAdapter.build.
[castle.git] / Services / Transaction / Castle.Services.Transaction / AbstractTransaction.cs
blobfe94c5e6b458a75866c1038043f28c18a9270584
1 // Copyright 2004-2007 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.Collections;
19 using System.Collections.Specialized;
20 using Castle.Core.Logging;
22 /// <summary>
23 /// Helper abstract class for <see cref="ITransaction"/> implementors.
24 /// </summary>
25 public abstract class AbstractTransaction : MarshalByRefObject, ITransaction, IDisposable
27 private HybridDictionary context;
28 private IList synchronizations;
29 private TransactionStatus state = TransactionStatus.NoTransaction;
30 private TransactionMode transactionMode;
31 private IsolationMode isolationMode;
32 private bool distributedTransaction;
33 private string name;
34 private ILogger logger = NullLogger.Instance;
36 internal IList resources;
38 public AbstractTransaction()
40 resources = new ArrayList();
41 synchronizations = new ArrayList();
42 context = new HybridDictionary(true);
45 public AbstractTransaction(TransactionMode transactionMode, IsolationMode isolationMode, bool distributedTransaction)
46 : this(transactionMode, isolationMode, distributedTransaction, null)
50 public AbstractTransaction(TransactionMode transactionMode, IsolationMode isolationMode, bool distributedTransaction,
51 string name) : this()
53 this.transactionMode = transactionMode;
54 this.isolationMode = isolationMode;
55 this.distributedTransaction = distributedTransaction;
57 if (String.IsNullOrEmpty(name))
59 this.name = ObtainName();
61 else
63 this.name = name;
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 ITransaction
84 public virtual void Enlist(IResource resource)
86 logger.DebugFormat("Enlisting resource {0}", resource);
88 if (resource == null) throw new ArgumentNullException("resource");
90 // We can't add the resource more than once
91 if (resources.Contains(resource)) return;
93 if (Status == TransactionStatus.Active)
95 try
97 resource.Start();
99 catch(Exception ex)
101 state = TransactionStatus.Invalid;
103 logger.Error("Enlisting resource failed", ex);
105 throw;
109 resources.Add(resource);
111 logger.DebugFormat("Resource enlisted successfully {0}", resource);
114 public virtual void Begin()
116 logger.DebugFormat("Transaction '{0}' Begin", Name);
118 AssertState(TransactionStatus.NoTransaction);
119 state = TransactionStatus.Active;
121 foreach(IResource resource in resources)
125 resource.Start();
127 catch(Exception ex)
129 state = TransactionStatus.Invalid;
131 logger.Error("Failed to start transaction on resource.", ex);
133 throw;
138 public virtual void Rollback()
140 logger.DebugFormat("Transaction '{0}' Rollback", Name);
142 AssertState(TransactionStatus.Active);
143 state = TransactionStatus.RolledBack;
145 PerformSynchronizations(false);
147 Exception error = null;
148 ArrayList failedResources = new ArrayList(resources.Count);
150 foreach(IResource resource in resources)
154 resource.Rollback();
156 catch(Exception ex)
158 state = TransactionStatus.Invalid;
160 logger.Error("Failed to rollback transaction on resource.", ex);
162 error = ex;
164 failedResources.Add(resource);
168 PerformSynchronizations(true);
170 if (error != null)
172 throw new RollbackResourceException("Could not rollback transaction, one (or more) resources failed.", error,
173 (IResource) failedResources[failedResources.Count - 1],
174 (IResource[]) failedResources.ToArray((typeof(IResource))));
178 public virtual void Commit()
180 logger.DebugFormat("Transaction '{0}' Commit", Name);
182 AssertState(TransactionStatus.Active);
183 state = TransactionStatus.Committed;
185 PerformSynchronizations(false);
187 Exception error = null;
188 ArrayList failedResources = new ArrayList(resources.Count);
190 foreach(IResource resource in resources)
194 resource.Commit();
196 catch(Exception ex)
198 state = TransactionStatus.Invalid;
200 logger.Error("Failed to commit transaction on resource.", ex);
202 error = ex;
204 failedResources.Add(resource);
208 PerformSynchronizations(true);
210 if (error != null)
212 throw new CommitResourceException("Could not commit transaction, one (or more) of the resources failed", error,
213 (IResource) failedResources[failedResources.Count - 1],
214 (IResource[]) failedResources.ToArray((typeof(IResource))));
218 public virtual void SetRollbackOnly()
222 public TransactionStatus Status
224 get { return state; }
227 public virtual void RegisterSynchronization(ISynchronization synchronization)
229 logger.DebugFormat("Registering Synchronization {0}", synchronization);
231 if (synchronization == null) throw new ArgumentNullException("synchronization");
233 synchronizations.Add(synchronization);
235 logger.DebugFormat("Synchronization registered successfully {0}", synchronization);
238 public virtual IDictionary Context
240 get { return context; }
243 public abstract bool IsChildTransaction { get; }
245 public abstract bool IsRollbackOnlySet { get; }
247 public TransactionMode TransactionMode
249 get { return transactionMode; }
252 public IsolationMode IsolationMode
254 get { return isolationMode; }
257 public bool DistributedTransaction
259 get { return distributedTransaction; }
262 public string Name
264 get { return name; }
267 #region ITransaction Members
269 public IResource[] Resources
271 get { return (IResource[]) ((ArrayList) resources).ToArray(typeof(IResource)); }
274 #endregion
276 #endregion
278 #region IDisposable Members
280 public virtual void Dispose()
282 resources.Clear();
283 synchronizations.Clear();
286 #endregion
288 #region Helper methods
290 protected virtual void AssertState(TransactionStatus state)
292 if (this.state != state)
294 throw new TransactionException("Invalid transaction state to perform the requested action");
298 protected string ObtainName()
300 return Convert.ToString(GetHashCode());
303 private void PerformSynchronizations(bool runAfterCompletion)
305 foreach(ISynchronization sync in synchronizations)
309 if (runAfterCompletion)
311 sync.AfterCompletion();
313 else
315 sync.BeforeCompletion();
318 catch(Exception ex)
320 logger.Error("Synchronization failed", ex);
322 // Exceptions should not be threw by syncs.
323 // They will be swalled
328 #endregion