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.exceptions.DelegatedRuntimeException;
25 import org.csc.phynixx.common.exceptions.ExceptionUtils;
26 import org.csc.phynixx.common.logger.IPhynixxLogger;
27 import org.csc.phynixx.common.logger.PhynixxLogManager;
28 import org.csc.phynixx.connection.IPhynixxConnection;
29 import org.csc.phynixx.watchdog.ITimeoutCondition;
30 import org.csc.phynixx.watchdog.TimeoutCondition;
31 import org.csc.phynixx.watchdog.log.ConditionViolatedLog;
32 import org.csc.phynixx.xa.IPhynixxXAResourceListener.IPhynixxXAResourceEvent;
33
34 import javax.transaction.TransactionManager;
35 import javax.transaction.xa.XAException;
36 import javax.transaction.xa.XAResource;
37 import javax.transaction.xa.Xid;
38 import java.util.ArrayList;
39 import java.util.List;
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 public class PhynixxXAResource<C extends IPhynixxConnection> implements IPhynixxXAResource<C> {
55
56 private static final long DEFAULT_TIMEOUT = Long.MAX_VALUE;
57
58
59 private static final IPhynixxLogger LOG = PhynixxLogManager.getLogger(PhynixxXAResource.class);
60
61 private Object xaId = null;
62
63 private PhynixxXAResourceFactory<C> xaResourceFactory = null;
64
65
66
67
68 private PhynixxManagedXAConnection<C> xaConnectionHandle = null;
69
70 private volatile boolean closed = false;
71
72 private ITimeoutCondition timeoutCondition = null;
73
74 private boolean supportsTimeOut= false;
75
76
77
78
79 public PhynixxXAResource(
80 String xaId,
81 TransactionManager transactionManager,
82 PhynixxXAResourceFactory<C> xaResourceFactory) {
83 this.xaId = xaId;
84 this.xaResourceFactory = xaResourceFactory;
85 this.xaConnectionHandle = new PhynixxManagedXAConnection(this, transactionManager, xaResourceFactory.getXATransactionalBranchRepository(), xaResourceFactory.getManagedConnectionFactory());
86
87
88
89 if( this.isSupportsTimeOut()) {
90 this.timeoutCondition = new TimeoutCondition(DEFAULT_TIMEOUT) {
91 public void conditionViolated() {
92 PhynixxXAResource.this.conditionViolated();
93 }
94 };
95
96 xaResourceFactory.registerWatchCondition(this.timeoutCondition);
97 }
98
99 }
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114 public void conditionViolated() {
115 try {
116 if (this.xaConnectionHandle != null) {
117 XATransactionalBranch<C> transactionalBranch = this.xaConnectionHandle.toGlobalTransactionBranch();
118 if (transactionalBranch != null) {
119 transactionalBranch.setRollbackOnly(true);
120 }
121 }
122 if (LOG.isInfoEnabled()) {
123 String logString = "PhynixxXAResource.expired :: XAResource " + this.getId() + " is expired (time out occurred) and all associated TX are rollbacked ";
124 LOG.info(new ConditionViolatedLog(this.timeoutCondition, logString).toString());
125 }
126
127 } finally {
128
129 setTimeOutActive(false);
130 }
131
132 }
133
134 private void setTimeOutActive(boolean active) {
135 if(this.timeoutCondition!=null) {
136 this.timeoutCondition.setActive(false);
137 }
138 }
139
140
141 public boolean isSupportsTimeOut() {
142 return supportsTimeOut;
143 }
144
145 public void setSupportsTimeOut(boolean supportsTimeOut) {
146 throw new IllegalStateException("Timeout isn't yet supported. Will be in version 2.1");
147 }
148
149
150
151
152
153
154
155
156 public IPhynixxXAConnection<C> getXAConnection() {
157 return this.xaConnectionHandle;
158 }
159
160 public boolean isClosed() {
161 return closed;
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 public void start(Xid xid, int flags) throws XAException {
202 try {
203
204 if (xid == null) {
205 throw new XAException(XAException.XAER_INVAL);
206 }
207
208 XATransactionalBranch<C> transactionalBranch = null;
209
210
211 if (flags == TMRESUME) {
212 this.xaConnectionHandle.resumeTransactionalBranch(xid);
213 } else if (flags == TMJOIN || flags == TMNOFLAGS) {
214 this.xaConnectionHandle.startTransactionalBranch(xid);
215 }
216 LOG.debug(
217 "PhynixxXAResource[" + this.getId() + "]:start xid='"
218 + xid
219 + "' flags='"
220 + ConstantsPrinter.getXAResourceMessage(flags)
221 + "'"
222 + " Connected to " +
223 this.xaConnectionHandle);
224
225
226
227 this.setTimeOutActive(true);
228
229 } catch (XAException xaExc) {
230 LOG.error("PhynixxXAResource[" + this.getId() + "]:start xid='"
231 + xid
232 + "' flags='"
233 + ConstantsPrinter.getXAResourceMessage(flags)
234 + "'"
235 + " ERROR " + ConstantsPrinter.getXAErrorCode(xaExc.errorCode));
236 throw xaExc;
237 } catch (Exception ex) {
238 LOG.error("PhynixxXAResource.start(" + xid + "," + flags + ") on XAResourceProgressState " + this.xaId + " :: " + ex + "\n" + ExceptionUtils.getStackTrace(ex));
239 throw new DelegatedRuntimeException("start(" + xid + "," + flags + ") on XAResourceProgressState " + this.xaId, ex);
240
241 }
242 }
243
244
245 public void commit(Xid xid, boolean onePhase) throws XAException {
246
247 XATransactionalBranch<C> transactionalBranch = this.xaConnectionHandle.toGlobalTransactionBranch();
248 if (xid == null) {
249 LOG.error("No XID");
250 throw new XAException(XAException.XAER_INVAL);
251 }
252
253 if (transactionalBranch == null) {
254 LOG.error("XAConnection is not associated to a global Transaction (expected to XID=" + xid + ")");
255 throw new XAException(XAException.XAER_PROTO);
256 }
257
258
259 if (!transactionalBranch.getXid().equals(xid)) {
260 LOG.error("XAResource " + this + " isnt't active for XID=" + xid);
261 throw new XAException(XAException.XAER_PROTO);
262 }
263
264
265
266 try {
267 transactionalBranch.commit(onePhase);
268 } catch (XAException xaExc) {
269 LOG.error("PhynixxXAResource[" + this.getId() + "]:end xid='"
270 + xid
271 + "' onePhase='" + onePhase
272 + " ERROR " + ConstantsPrinter.getXAErrorCode(xaExc.errorCode));
273 throw xaExc;
274
275 } catch (Exception ex) {
276 LOG.error("PhynixxXAResource.commit(" + xid + "," + onePhase + ") on XAResourceProgressState " + this.xaId + " :: " + ex + "\n" + ExceptionUtils.getStackTrace(ex));
277 throw new DelegatedRuntimeException("commit(" + xid + "," + onePhase + ") on XAResourceProgressState " + this.xaId, ex);
278 } finally {
279 try {
280
281 this.xaConnectionHandle.closeTransactionalBranch(xid);
282 } finally {
283
284 this.setTimeOutActive(false);
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 public int prepare(Xid xid) throws XAException {
310 try {
311 LOG.debug(
312 "PhynixxXAResource[" + this.getId() + "]:prepare prepare to perform a commit for XID=" + xid);
313
314 XATransactionalBranch<C> transactionalBranch = this.xaConnectionHandle.toGlobalTransactionBranch();
315 if (xid == null) {
316 LOG.error("No XID");
317 throw new XAException(XAException.XAER_INVAL);
318 }
319
320 if (transactionalBranch == null) {
321 LOG.error("XAConnection is not associated to a global Transaction");
322 throw new XAException(XAException.XAER_PROTO);
323 }
324
325
326 if (!transactionalBranch.getXid().equals(xid)) {
327 LOG.error("XAResource " + this + " isnt't active for XID=" + xid);
328 throw new XAException(XAException.XAER_PROTO);
329 }
330
331
332
333 int retVal = transactionalBranch.prepare();
334
335 if (retVal == XAResource.XA_RDONLY) {
336 this.xaConnectionHandle.closeTransactionalBranch(xid);
337 }
338 return retVal;
339
340 } catch (XAException xaExc) {
341 LOG.error("PhynixxXAResource[" + this.getId() + "]:prepare xid='"
342 + xid
343 + " ERROR " + ConstantsPrinter.getXAErrorCode(xaExc.errorCode));
344 throw xaExc;
345 } catch (Exception ex) {
346 LOG.error("PhynixxXAResource.prepare(" + xid + ") on XAResourceProgressState " + this.xaId + " :: " + ex + "\n" + ExceptionUtils.getStackTrace(ex));
347 throw new DelegatedRuntimeException("prepare(" + xid + ") on XAResourceProgressState " + this.xaId, ex);
348
349 }
350 }
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370 public void rollback(Xid xid) throws XAException {
371 {
372 try {
373 LOG.debug("PhynixxXAResource[" + this.getId() + "]:rollback started xid=" + xid);
374
375 XATransactionalBranch<C> transactionalBranch = this.xaConnectionHandle.toGlobalTransactionBranch();
376 if (xid == null) {
377 LOG.error("No XID");
378 throw new XAException(XAException.XAER_INVAL);
379 }
380
381 if (transactionalBranch == null) {
382 LOG.error("XAConnection is not associated to a global Transaction");
383 throw new XAException(XAException.XAER_PROTO);
384 }
385
386
387 if (!transactionalBranch.getXid().equals(xid)) {
388 LOG.error("XAResource " + this + " isnt't active for XID=" + xid);
389 throw new XAException(XAException.XAER_PROTO);
390 }
391
392
393
394 if (transactionalBranch.isInActive()) {
395 throw new XAException(XAException.XAER_PROTO);
396 }
397
398 try {
399 transactionalBranch.rollback();
400 } finally {
401
402 this.xaConnectionHandle.closeTransactionalBranch(xid);
403 }
404
405
406 } catch (XAException xaExc) {
407 LOG.error("PhynixxXAResource[" + this.getId() + "]:rollback xid='"
408 + xid
409 + " ERROR " + ConstantsPrinter.getXAErrorCode(xaExc.errorCode));
410 throw xaExc;
411
412 } catch (Exception ex) {
413 LOG.error("PhynixxXAResource.rollback(" + xid + ") on XAResourceProgressState " + this.xaId + " :: " + ex + "\n" + ExceptionUtils.getStackTrace(ex));
414 throw new DelegatedRuntimeException("rollback(" + xid + ") on XAResourceProgressState " + this.xaId, ex);
415
416 } finally {
417
418 this.setTimeOutActive(false);
419
420 }
421 }
422
423
424 }
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449 public void end(Xid xid, int flags) throws XAException {
450 try {
451
452 LOG.debug("PhynixxXAResource:end");
453 LOG.debug(
454 "PhynixxXAResource[" + this.getId() + "]:end xid='" + xid + "' flags='" + ConstantsPrinter.getXAResourceMessage(flags) + "'");
455
456 if (xid == null) {
457 LOG.error("No XID");
458 throw new XAException(XAException.XAER_INVAL);
459 }
460
461 XATransactionalBranch<C> transactionalBranch = this.xaConnectionHandle.toGlobalTransactionBranch();
462 if (transactionalBranch == null) {
463 LOG.error("XAConnection is not associated to a global Transaction");
464 throw new XAException(XAException.XAER_PROTO);
465 }
466
467
468 if (!transactionalBranch.getXid().equals(xid)) {
469 LOG.error("XAResource " + this + " isnt't active for XID=" + xid);
470 throw new XAException(XAException.XAER_PROTO);
471 }
472
473 if (flags == TMSUSPEND) {
474 this.xaConnectionHandle.suspendTransactionalBranch(xid);
475 } else if (flags == TMSUCCESS) {
476
477
478 if (transactionalBranch.isXAProtocolFinished()) {
479 transactionalBranch.close();
480 LOG.debug("XAResource " + this + " closed gracefully ");
481 }
482 } else if (flags == TMFAIL) {
483 transactionalBranch.setRollbackOnly(true);
484 }
485
486 } catch (XAException xaExc) {
487 LOG.error("PhynixxXAResource[" + this.getId() + "]:end xid='"
488 + xid
489 + "' flags='"
490 + ConstantsPrinter.getXAResourceMessage(flags)
491 + "'"
492 + " ERROR " + ConstantsPrinter.getXAErrorCode(xaExc.errorCode));
493 throw xaExc;
494 } catch (Exception ex) {
495 LOG.error("PhynixxXAResource.end(" + xid + "," + flags + ") on XAResourceProgressState " + this.xaId + " :: " + ex + "\n" + ExceptionUtils.getStackTrace(ex));
496 throw new DelegatedRuntimeException("end(" + xid + "," + flags + ") on XAResourceProgressState " + this.xaId, ex);
497 }
498 }
499
500
501
502
503
504
505
506 public void forget(Xid xid) throws XAException {
507 try {
508 LOG.debug("PhynixxXAResource[" + this.getId() + "]:forget forget with Xid");
509 if (xid == null)
510 throw new XAException(XAException.XAER_INVAL);
511
512 XATransactionalBranch<C> transactionalBranch = this.xaConnectionHandle.toGlobalTransactionBranch();
513
514 if (transactionalBranch == null) {
515 return;
516 }
517 this.xaConnectionHandle.closeTransactionalBranch(xid);
518
519 } finally {
520
521 this.setTimeOutActive(false);
522
523 }
524 }
525
526 public int getTransactionTimeout() throws XAException {
527 return (int) (this.timeoutCondition.getTimeout()) * 1000;
528 }
529
530
531
532
533
534
535
536
537
538
539
540
541 public boolean isSameRM(XAResource xaResource) throws XAException {
542 if (this.equals(xaResource)) {
543 LOG.debug("PhynixxXAResource[" + this.getId() + "]:isSameRM isSameRM");
544 return true;
545 }
546 if (!(xaResource instanceof PhynixxXAResource)) {
547
548 LOG.debug("PhynixxXAResource[" + this.getId() + "]:isSameRM not isSameRM");
549 return false;
550 }
551 PhynixxXAResource sampleXARes = (PhynixxXAResource) xaResource;
552
553 try {
554
555 if (xaResourceFactory.equals(sampleXARes.xaResourceFactory)) {
556
557 LOG.debug("PhynixxXAResource[" + this.getId() + "]:isSameRM isSameRM (equal XAResourceFactory)");
558 return true;
559 } else {
560 LOG.debug("PhynixxXAResource[" + this.getId() + "]:isSameRM not isSameRM (not equal XAResourceFactory)");
561 return false;
562 }
563 } catch (Exception ex) {
564 LOG.error("PhynixxXAResource.isSameRM(" + sampleXARes.xaId + ") on XAResourceProgressState " + this.xaId + " :: " + ex + "\n" + ExceptionUtils.getStackTrace(ex));
565 throw new DelegatedRuntimeException("isSameRM(" + sampleXARes.xaId + ") on XAResourceProgressState " + this.xaId, ex);
566
567 }
568 }
569
570
571
572
573
574
575
576
577 public void close() {
578
579 if (this.xaConnectionHandle != null) {
580 XATransactionalBranch<C> transactionalBranch = this.xaConnectionHandle.toGlobalTransactionBranch();
581 if (transactionalBranch != null) {
582 transactionalBranch.close();
583 }
584 }
585 this.closed = true;
586 this.notifyClosed();
587
588 LOG.debug("PhynixxXAResource[" + this.getId() + "]:closed ");
589 }
590
591
592
593
594 public Xid[] recover(int flags) throws XAException {
595 LOG.info("PhynixxXAResource[" + this.getId() + "]:recover recover flags=" + ConstantsPrinter.getXAResourceMessage(flags));
596 if (flags != TMSTARTRSCAN && flags != TMENDRSCAN && flags != TMNOFLAGS) {
597 throw new XAException(XAException.XAER_INVAL);
598 }
599
600 Xid[] retval = null;
601 retval = this.xaResourceFactory.recover();
602 return retval;
603 }
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625 public boolean setTransactionTimeout(int seconds) throws XAException {
626
627 return false;
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646 }
647
648
649
650 public final boolean equals(Object obj) {
651 return super.equals(obj);
652 }
653
654
655 public final int hashCode() {
656 return super.hashCode();
657 }
658
659 public Object getId() {
660 return this.xaId;
661 }
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677 public String toString() {
678 return this.xaResourceFactory.getId().toString() + "." + this.xaId.toString();
679 }
680
681
682 private List<IPhynixxXAResourceListener<C>> listeners = new ArrayList();
683
684 public void addXAResourceListener(IPhynixxXAResourceListener listener) {
685 if (!listeners.contains(listener)) {
686 this.listeners.add(listener);
687 }
688 }
689
690 public void removeXAResourceListener(IPhynixxXAResourceListener<C> listener) {
691
692 this.listeners.remove(listener);
693 }
694
695 private void notifyClosed() {
696 IPhynixxXAResourceEvent<C> event = new PhynixxXAResourceEvent(this);
697 for (int i = 0; i < listeners.size(); i++) {
698 IPhynixxXAResourceListener<C> listener = listeners.get(i);
699 listener.closed(event);
700 }
701
702 }
703
704
705 }