1 package org.csc.phynixx.xa;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 import org.csc.phynixx.common.cast.ImplementorUtils;
25 import org.csc.phynixx.common.exceptions.DelegatedRuntimeException;
26 import org.csc.phynixx.common.exceptions.ExceptionUtils;
27 import org.csc.phynixx.common.logger.IPhynixxLogger;
28 import org.csc.phynixx.common.logger.PhynixxLogManager;
29 import org.csc.phynixx.connection.IPhynixxConnection;
30 import org.csc.phynixx.connection.IPhynixxManagedConnection;
31 import org.csc.phynixx.connection.IPhynixxManagedConnectionFactory;
32
33 import javax.transaction.RollbackException;
34 import javax.transaction.SystemException;
35 import javax.transaction.Transaction;
36 import javax.transaction.TransactionManager;
37 import javax.transaction.xa.XAResource;
38 import javax.transaction.xa.Xid;
39
40
41
42
43
44
45
46 class PhynixxManagedXAConnection<C extends IPhynixxConnection> implements IPhynixxXAConnection<C> {
47
48 private static final IPhynixxLogger LOG = PhynixxLogManager.getLogger(PhynixxManagedXAConnection.class);
49
50 private final PhynixxXAResource<C> xaResource;
51
52 private IPhynixxManagedConnectionFactory<C> managedConnectionFactory;
53
54 private transient ITransactionBinding<C> transactionBinding = null;
55
56 private TransactionManager transactionManager = null;
57
58 private final IXATransactionalBranchRepository<C> xaTransactionalBranchDictionary;
59
60 private boolean enlisted;
61
62 PhynixxManagedXAConnection(PhynixxXAResource<C> xaResource,
63 TransactionManager transactionManager,
64 IXATransactionalBranchRepository<C> xaTransactionalBranchDictionary,
65 IPhynixxManagedConnectionFactory<C> managedConnectionFactory) {
66 this.xaResource = xaResource;
67 this.xaTransactionalBranchDictionary = xaTransactionalBranchDictionary;
68 this.managedConnectionFactory = managedConnectionFactory;
69 this.transactionManager = transactionManager;
70 }
71
72 public XAResource getXAResource() {
73 return xaResource;
74 }
75
76
77
78
79
80 XATransactionalBranch<C> toGlobalTransactionBranch() {
81 if (this.transactionBinding != null && this.transactionBinding.getTransactionBindingType() == TransactionBindingType.GlobalTransaction) {
82 return ImplementorUtils.cast(this.transactionBinding, GlobalTransactionProxy.class).getGlobalTransactionalBranch();
83 }
84 return null;
85 }
86
87
88
89
90
91
92
93
94 void startTransactionalBranch(Xid xid) {
95
96
97 cleanupTransactionBinding();
98
99 final TransactionBindingType transactionBindingType = getTransactionBindingType();
100
101
102
103 if (transactionBindingType == TransactionBindingType.LocalTransaction) {
104 LocalTransactionProxy<C> localTransactionProxy = ImplementorUtils.cast(this.transactionBinding, LocalTransactionProxy.class);
105 if (localTransactionProxy.hasTransactionalData()) {
106 throw new IllegalStateException("Connection is associated to a local transaction and has uncommitted transactional data");
107 }
108
109 XATransactionalBranch<C> xaTransactionalBranch = this.xaTransactionalBranchDictionary.findTransactionalBranch(xid);
110
111 if (xaTransactionalBranch == null) {
112 xaTransactionalBranch= this.xaTransactionalBranchDictionary.instanciateTransactionalBranch(xid, localTransactionProxy.getConnection());
113 }
114 this.transactionBinding = new GlobalTransactionProxy<C>().assignTransactionalBranch(this.xaTransactionalBranchDictionary.findTransactionalBranch(xid));
115
116
117 } else if (transactionBindingType == TransactionBindingType.NoTransaction) {
118 XATransactionalBranch<C> xaTransactionalBranch = this.xaTransactionalBranchDictionary.findTransactionalBranch(xid);
119
120
121 if (xaTransactionalBranch == null) {
122 IPhynixxManagedConnection<C> physicalConnection = this.createPhysicalConnection();
123 xaTransactionalBranch =
124 this.xaTransactionalBranchDictionary.instanciateTransactionalBranch(xid, physicalConnection);
125 this.xaTransactionalBranchDictionary.instanciateTransactionalBranch(xid, physicalConnection);
126 }
127 this.transactionBinding = new GlobalTransactionProxy<C>().assignTransactionalBranch(this.xaTransactionalBranchDictionary.findTransactionalBranch(xid));
128
129
130 } else if (transactionBindingType == TransactionBindingType.GlobalTransaction) {
131 GlobalTransactionProxy<C> globalTransactionProxy = ImplementorUtils.cast(this.transactionBinding, GlobalTransactionProxy.class);
132 XATransactionalBranch<C> xaTransactionalBranch = this.xaTransactionalBranchDictionary.findTransactionalBranch(xid);
133
134
135 if (xaTransactionalBranch == null) {
136 IPhynixxManagedConnection<C> physicalConnection = this.createPhysicalConnection();
137 xaTransactionalBranch =
138 this.xaTransactionalBranchDictionary.instanciateTransactionalBranch(xid, physicalConnection);
139 this.xaTransactionalBranchDictionary.instanciateTransactionalBranch(xid, physicalConnection);
140 } else {
141
142 if (globalTransactionProxy.getGlobalTransactionalBranch()==null) {
143 throw new IllegalStateException("XAConnection already associated toXID but not to a global Transaction ");
144 }
145 if (!globalTransactionProxy.getXid().equals(xid)) {
146 throw new IllegalStateException("XAConnection already associated to a global Transaction "+globalTransactionProxy.getXid());
147 }
148 }
149 this.transactionBinding = globalTransactionProxy.assignTransactionalBranch(this.xaTransactionalBranchDictionary.findTransactionalBranch(xid));
150
151
152 }
153
154
155 }
156
157 private void cleanupTransactionBinding() {
158
159 if (getTransactionBindingType() == TransactionBindingType.LocalTransaction) {
160 LocalTransactionProxy<C> localTransactionProxy = ImplementorUtils.cast(this.transactionBinding, LocalTransactionProxy.class);
161 if (localTransactionProxy.isClosed()) {
162 this.transactionBinding.release();
163 this.transactionBinding = null;
164 }
165 }
166 }
167
168 private TransactionBindingType getTransactionBindingType() {
169 return (this.transactionBinding != null) ? this.transactionBinding.getTransactionBindingType() : TransactionBindingType.NoTransaction;
170 }
171
172 private IPhynixxManagedConnection<C> createPhysicalConnection() {
173 return this.managedConnectionFactory.getManagedConnection();
174 }
175
176
177 void resumeTransactionalBranch(Xid xid) {
178
179 this.cleanupTransactionBinding();
180
181 TransactionBindingType transactionBindingType = getTransactionBindingType();
182 if (transactionBindingType == TransactionBindingType.GlobalTransaction) {
183 throw new IllegalStateException("XAConnection associated to a global transaction and can not be resumed");
184 }
185 XATransactionalBranch<C> transactionalBranch = this.xaTransactionalBranchDictionary.findTransactionalBranch(xid);
186 if (transactionalBranch == null) {
187 throw new IllegalStateException("No suspended branch for XID " + xid);
188 }
189 transactionalBranch.resume();
190 this.transactionBinding = new GlobalTransactionProxy<C>().assignTransactionalBranch(transactionalBranch);
191
192 }
193
194 void suspendTransactionalBranch(Xid xid) {
195
196 this.cleanupTransactionBinding();
197
198 TransactionBindingType transactionBindingType = getTransactionBindingType();
199 if (transactionBindingType != TransactionBindingType.GlobalTransaction) {
200 throw new IllegalStateException("XAConnection not associated to a global transaction and can not be suspended");
201 }
202 GlobalTransactionProxy<C> globalTransactionProxy = ImplementorUtils.cast(this.transactionBinding, GlobalTransactionProxy.class);
203 if (!globalTransactionProxy.getXid().equals(xid)) {
204 throw new IllegalStateException("XAConnection already associated to a global Transaction");
205 }
206 globalTransactionProxy.getGlobalTransactionalBranch().suspend();
207
208 this.transactionBinding.release();
209 this.transactionBinding = null;
210
211 }
212
213 void joinTransactionalBranch(Xid xid) {
214
215 cleanupTransactionBinding();
216
217 TransactionBindingType transactionBindingType = getTransactionBindingType();
218 if (transactionBindingType == TransactionBindingType.GlobalTransaction) {
219 throw new IllegalStateException("XAConnection already associated to a global transaction and can not be joined to XID " + xid);
220 }
221
222
223 this.transactionBinding.release();
224 this.transactionBinding = null;
225
226 }
227
228
229
230
231
232
233 void closeTransactionalBranch(Xid xid) {
234
235 if (this.getTransactionBindingType() != TransactionBindingType.GlobalTransaction) {
236 throw new IllegalStateException("XAConnection not associated to a global transaction");
237 }
238
239 GlobalTransactionProxy<C> globalTransactionProxy = ImplementorUtils.cast(this.transactionBinding, GlobalTransactionProxy.class);
240
241 XATransactionalBranch<C> transactionalBranch = globalTransactionProxy.getGlobalTransactionalBranch();
242 transactionalBranch.close();
243
244 delistTransaction();
245 }
246
247
248 @Override
249 public void close() {
250 if(this.transactionBinding!=null) {
251 this.transactionBinding.close();
252 this.transactionBinding=null;
253 }
254 }
255
256 private void delistTransaction() {
257 if (this.transactionBinding != null) {
258 this.transactionBinding.release();
259 }
260 this.transactionBinding = null;
261 }
262
263 public IPhynixxManagedConnection<C> getManagedConnection() {
264
265
266 this.checkTransactionBinding();
267
268 return this.transactionBinding.getConnection();
269 }
270
271 public C getConnection() {
272 return this.getManagedConnection().toConnection();
273 }
274
275
276 boolean isInGlobalTransaction() {
277 try {
278 return transactionManager!=null && this.transactionManager.getTransaction()!=null;
279 } catch (SystemException e) {
280 throw new DelegatedRuntimeException(e);
281 }
282 }
283
284
285
286
287
288
289
290 private void enlistTransaction() {
291
292 this.cleanupTransactionBinding();
293
294 TransactionBindingType transactionBindingType = this.getTransactionBindingType();
295
296
297 if (this.isInGlobalTransaction() && transactionBindingType != TransactionBindingType.GlobalTransaction) {
298 try {
299 Transaction ntx = this.transactionManager.getTransaction();
300
301
302 if (!enlisted && ntx != null) {
303 this.enlisted=true;
304
305 this.enlisted = ntx.enlistResource(this.xaResource);
306 if (!enlisted) {
307 LOG.error("Enlisting " + xaResource + " failed");
308 } else {
309
310 }
311 } else {
312 LOG.debug(
313 "SampleXAConnection:connectionRequiresTransaction (no globalTransaction found)");
314 }
315 } catch (RollbackException n) {
316 LOG.error(
317 "SampleXAConnection:prevokeAction enlistResource exception : "
318 + n.toString());
319 } catch (SystemException n) {
320 LOG.error("SampleXAConnection:connectionRequiresTransaction " + n + "\n" + ExceptionUtils.getStackTrace(n));
321 throw new DelegatedRuntimeException(n);
322 }
323 } else if (transactionBindingType == TransactionBindingType.NoTransaction) {
324 this.transactionBinding = new LocalTransactionProxy<C>(this.managedConnectionFactory.getManagedConnection());
325 } else
326 if (this.isInGlobalTransaction() && transactionBindingType == TransactionBindingType.GlobalTransaction) {
327 } else
328
329
330 if (!this.isInGlobalTransaction() && transactionBindingType == TransactionBindingType.LocalTransaction) {
331 }
332
333 }
334
335
336 @Override
337 public boolean equals(Object o) {
338 if (this == o) return true;
339 if (o == null || getClass() != o.getClass()) return false;
340
341 PhynixxManagedXAConnection that = (PhynixxManagedXAConnection) o;
342
343 return xaResource.equals(that.xaResource);
344
345 }
346
347 @Override
348 public int hashCode() {
349 return xaResource.hashCode();
350 }
351
352
353 @Override
354 public String toString() {
355 return "PhynixxManagedXAConnection{" +
356 "xaResource=" + xaResource +
357 ", transactionBinding=" + this.transactionBinding +
358 '}';
359 }
360
361
362 void checkTransactionBinding() {
363
364
365 if( this.isInGlobalTransaction()) {
366 this.enlistTransaction();
367 }
368 if (this.transactionBinding == null || this.transactionBinding.getTransactionBindingType() == TransactionBindingType.NoTransaction) {
369 this.transactionBinding = new LocalTransactionProxy<C>(this.createPhysicalConnection());
370
371 }
372 }
373
374 }