/
Db4oPlatformTransactionManager.cs
317 lines (280 loc) · 10.6 KB
/
Db4oPlatformTransactionManager.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
using Spring.Transaction.Support;
using Spring.Transaction;
using System;
using System.Data;
using com.db4o;
using log4net;
namespace Spring.Data
{
public class Db4oPlatformTransactionManager : AbstractPlatformTransactionManager
{
private IDb4oDataSource _DataSource;
#region Logging
private readonly ILog logger = LogManager.GetLogger(this.GetType());
#endregion
/// <summary>
/// The DataSource used to query the TransactionSynchronizationManager
/// Should be the same as the one specified in the DataUtils calls, since
/// it is used as the key in the TransactionSynchronizationManager calls
/// </summary>
public IDb4oDataSource DataSource
{
set {
_DataSource = value;
}
get {
return _DataSource;
}
}
public Db4oPlatformTransactionManager(){
NestedTransactionsAllowed = false;
}
public Db4oPlatformTransactionManager(IDb4oDataSource dataSource) : this() {
_DataSource = DataSource;
}
/// <summary>
/// Return the current transaction object.
/// </summary>
/// <returns>The current transaction object.</returns>
/// <exception cref="Spring.Transaction.CannotCreateTransactionException">
/// If transaction support is not available.
/// </exception>
/// <exception cref="Spring.Transaction.TransactionException">
/// In the case of lookup or system errors.
/// </exception>
protected override Object DoGetTransaction()
{
logger.Debug("Do Get Transaction");
Db4oTransactionObject txObject = new Db4oTransactionObject();
ObjectContainerHolder contHolder = (ObjectContainerHolder) TransactionSynchronizationManager.GetResource(_DataSource);
txObject.ObjectContainerHolder = contHolder;
return txObject;
}
/// <summary>
/// Check if the given transaction object indicates an existing,
/// i.e. already begun, transaction.
/// </summary>
/// <param name="transaction">
/// Transaction object returned by
/// <see cref="Spring.Transaction.Support.AbstractPlatformTransactionManager.DoGetTransaction"/>.
/// </param>
/// <returns>True if there is an existing transaction.</returns>
/// <exception cref="Spring.Transaction.TransactionException">
/// In the case of system errors.
/// </exception>
protected override bool IsExistingTransaction(Object transaction)
{
logger.Debug("Transaction Already exists ?" + ((Db4oTransactionObject) transaction).HasTransaction);
return ((Db4oTransactionObject) transaction).HasTransaction;
}
/// <summary>
/// Begin a new transaction with the given transaction definition.
/// </summary>
/// <param name="transaction">
/// Transaction object returned by
/// <see cref="Spring.Transaction.Support.AbstractPlatformTransactionManager.DoGetTransaction"/>.
/// </param>
/// <param name="definition">
/// <see cref="Spring.Transaction.ITransactionDefinition"/> instance, describing
/// propagation behavior, isolation level, timeout etc.
/// </param>
/// <remarks>
/// Does not have to care about applying the propagation behavior,
/// as this has already been handled by this abstract manager.
/// </remarks>
/// <exception cref="Spring.Transaction.TransactionException">
/// In the case of creation or system errors.
/// </exception>
protected override void DoBegin(Object transaction, ITransactionDefinition definition)
{
logger.Debug("Do Begin Transaction");
if(definition.TransactionIsolationLevel != IsolationLevel.Unspecified){
logger.Error("Db4o Does not support Isolation Level");
throw new CannotCreateTransactionException("Db4o does not support an isolation level concept");
}
try{
Db4oTransactionObject txObject = (Db4oTransactionObject) transaction;
if (txObject.ObjectContainerHolder == null) {
// use the given container
logger.Warn ("Are we supposed to be in this case ??");
ObjectContainer container = Db4oUtils.GetConnection(_DataSource);
logger.Debug("Using given objectContainer ["
+ container
+ "] for the current thread transaction");
txObject.ObjectContainerHolder = new ObjectContainerHolder(container);
}
ObjectContainerHolder holder = txObject.ObjectContainerHolder;
//holder. set readonly ??
if(definition.TransactionTimeout != -1){
logger.Debug("Setting Transaction Timeout : " + definition.TransactionTimeout);
holder.TimeoutInSeconds = definition.TransactionTimeout;
}
} catch(Exception e){
logger.Error("Cannot create transaction");
throw new CannotCreateTransactionException("Cannot create transaction", e);
}
}
/// <summary>
/// Suspend the resources of the current transaction.
/// </summary>
/// <param name="transaction">
/// Transaction object returned by
/// <see cref="Spring.Transaction.Support.AbstractPlatformTransactionManager.DoGetTransaction"/>.
/// </param>
/// <returns>
/// An object that holds suspended resources (will be kept unexamined for passing it into
/// <see cref="Spring.Transaction.Support.AbstractPlatformTransactionManager.DoResume"/>.)
/// </returns>
/// <remarks>
/// Transaction synchronization will already have been suspended.
/// </remarks>
/// <exception cref="Spring.Transaction.IllegalTransactionStateException">
/// If suspending is not supported by the transaction manager implementation.
/// </exception>
/// <exception cref="Spring.Transaction.TransactionException">
/// in case of system errors.
/// </exception>
protected override Object DoSuspend(Object transaction)
{
logger.Debug("Do Suspend");
Db4oTransactionObject txObject = (Db4oTransactionObject) transaction;
txObject.ObjectContainerHolder = null;
ObjectContainerHolder containerHolder = (ObjectContainerHolder) TransactionSynchronizationManager.GetResource(_DataSource);
return new SuspendedResourcesHolder(containerHolder);
}
/// <summary>
/// Resume the resources of the current transaction.
/// </summary>
/// <param name="transaction">
/// Transaction object returned by
/// <see cref="Spring.Transaction.Support.AbstractPlatformTransactionManager.DoGetTransaction"/>.
/// </param>
/// <param name="suspendedResources">
/// The object that holds suspended resources as returned by
/// <see cref="Spring.Transaction.Support.AbstractPlatformTransactionManager.DoSuspend"/>.
/// </param>
/// <remarks>
/// Transaction synchronization will be resumed afterwards.
/// </remarks>
/// <exception cref="Spring.Transaction.IllegalTransactionStateException">
/// If suspending is not supported by the transaction manager implementation.
/// </exception>
/// <exception cref="Spring.Transaction.TransactionException">
/// In the case of system errors.
/// </exception>
protected override void DoResume(Object transaction, Object suspendedResources)
{
logger.Debug("Do Resume");
SuspendedResourcesHolder resourcesHolder = (SuspendedResourcesHolder) suspendedResources;
Db4oTransactionObject txObject = (Db4oTransactionObject) transaction;
txObject.ObjectContainerHolder = resourcesHolder.ObjectContainerHolder;
if (TransactionSynchronizationManager.HasResource(_DataSource)) {
TransactionSynchronizationManager.UnbindResource(_DataSource);
}
TransactionSynchronizationManager.BindResource(_DataSource,
resourcesHolder.ObjectContainerHolder);
}
/// <summary>
/// Perform an actual commit on the given transaction.
/// </summary>
/// <param name="status">The status representation of the transaction.</param>
/// <remarks>
/// <p>
/// An implementation does not need to check the rollback-only flag.
/// </p>
/// </remarks>
/// <exception cref="Spring.Transaction.TransactionException">
/// In the case of system errors.
/// </exception>
protected override void DoCommit(DefaultTransactionStatus status)
{
logger.Debug("Do Commit");
Db4oTransactionObject txObject = (Db4oTransactionObject) status.Transaction;
try{
txObject.ObjectContainerHolder.ObjectContainer.commit();
}catch(Exception e){
throw new TransactionSystemException("Cannot commit Db4o transaction", e);
}
}
/// <summary>
/// Perform an actual rollback on the given transaction.
/// </summary>
/// <param name="status">The status representation of the transaction.</param>
/// <remarks>
/// An implementation does not need to check the new transaction flag.
/// </remarks>
/// <exception cref="Spring.Transaction.TransactionException">
/// In the case of system errors.
/// </exception>
protected override void DoRollback(DefaultTransactionStatus status)
{
logger.Debug("Do Rollback");
Db4oTransactionObject txObject = (Db4oTransactionObject) status.Transaction;
try{
txObject.ObjectContainerHolder.ObjectContainer.rollback();
}catch(Exception e){
throw new TransactionSystemException("Cannot rollback Db4o transaction", e);
}
}
/// <summary>
/// Set the given transaction rollback-only. Only called on rollback
/// if the current transaction takes part in an existing one.
/// </summary>
/// <param name="status">The status representation of the transaction.</param>
/// <exception cref="Spring.Transaction.TransactionException">
/// In the case of system errors.
/// </exception>
protected override void DoSetRollbackOnly(DefaultTransactionStatus status)
{
logger.Debug("Do Set Rollback Only");
Db4oTransactionObject txObject = (Db4oTransactionObject) status.Transaction;
//txObject.
// FIXME
}
private static class Db4oTransactionObject : ISmartTransactionObject
{
private ObjectContainerHolder _ObjectContainerHolder;
/// <summary> The associated ObjectContainerHolder
/// </summary>
public ObjectContainerHolder ObjectContainerHolder
{
set {
_ObjectContainerHolder = value;
}
get {
return _ObjectContainerHolder;
}
}
/// <summary>
/// Return whether the transaction is internally marked as rollback-only.
/// </summary>
/// <returns>True of the transaction is marked as rollback-only.</returns>
public bool IsRollbackOnly()
{
return _ObjectContainerHolder.RollbackOnly;
}
public bool HasTransaction {
get{
// Db4o executes everything in a transaction
return _ObjectContainerHolder != null;
}
}
}
/// <summary>
/// Holder for suspended resources. Used internally by doSuspend and
/// doResume.
/// </summary>
private static class SuspendedResourcesHolder {
private readonly ObjectContainerHolder _ObjectContainerHolder;
public SuspendedResourcesHolder(ObjectContainerHolder containerHolder) {
this._ObjectContainerHolder = containerHolder;
}
public ObjectContainerHolder ObjectContainerHolder
{
get {
return _ObjectContainerHolder;
}
}
}
}
}