View Javadoc
1   package org.argeo.transaction.simple;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   
6   import javax.transaction.HeuristicMixedException;
7   import javax.transaction.HeuristicRollbackException;
8   import javax.transaction.RollbackException;
9   import javax.transaction.Status;
10  import javax.transaction.Synchronization;
11  import javax.transaction.SystemException;
12  import javax.transaction.Transaction;
13  import javax.transaction.xa.XAException;
14  import javax.transaction.xa.XAResource;
15  import javax.transaction.xa.Xid;
16  
17  /** Simple implementation of an XA {@link Transaction}. */
18  class SimpleTransaction implements Transaction, Status {
19  	private final Xid xid;
20  	private int status = Status.STATUS_ACTIVE;
21  	private final List<XAResource> xaResources = new ArrayList<XAResource>();
22  
23  	private final SimpleTransactionManager transactionManager;
24  
25  	public SimpleTransaction(SimpleTransactionManager transactionManager) {
26  		this.xid = new UuidXid();
27  		this.transactionManager = transactionManager;
28  	}
29  
30  	@Override
31  	public synchronized void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException,
32  			SecurityException, IllegalStateException, SystemException {
33  		status = STATUS_PREPARING;
34  		for (XAResource xaRes : xaResources) {
35  			if (status == STATUS_MARKED_ROLLBACK)
36  				break;
37  			try {
38  				xaRes.prepare(xid);
39  			} catch (XAException e) {
40  				status = STATUS_MARKED_ROLLBACK;
41  				error("Cannot prepare " + xaRes + " for " + xid, e);
42  			}
43  		}
44  		if (status == STATUS_MARKED_ROLLBACK) {
45  			rollback();
46  			throw new RollbackException();
47  		}
48  		status = STATUS_PREPARED;
49  
50  		status = STATUS_COMMITTING;
51  		for (XAResource xaRes : xaResources) {
52  			if (status == STATUS_MARKED_ROLLBACK)
53  				break;
54  			try {
55  				xaRes.commit(xid, false);
56  			} catch (XAException e) {
57  				status = STATUS_MARKED_ROLLBACK;
58  				error("Cannot prepare " + xaRes + " for " + xid, e);
59  			}
60  		}
61  		if (status == STATUS_MARKED_ROLLBACK) {
62  			rollback();
63  			throw new RollbackException();
64  		}
65  
66  		// complete
67  		status = STATUS_COMMITTED;
68  		clearResources(XAResource.TMSUCCESS);
69  		transactionManager.unregister(xid);
70  	}
71  
72  	@Override
73  	public synchronized void rollback() throws IllegalStateException, SystemException {
74  		status = STATUS_ROLLING_BACK;
75  		for (XAResource xaRes : xaResources) {
76  			try {
77  				xaRes.rollback(xid);
78  			} catch (XAException e) {
79  				error("Cannot rollback " + xaRes + " for " + xid, e);
80  			}
81  		}
82  
83  		// complete
84  		status = STATUS_ROLLEDBACK;
85  		clearResources(XAResource.TMFAIL);
86  		transactionManager.unregister(xid);
87  	}
88  
89  	@Override
90  	public synchronized boolean enlistResource(XAResource xaRes)
91  			throws RollbackException, IllegalStateException, SystemException {
92  		if (xaResources.add(xaRes)) {
93  			try {
94  				xaRes.start(getXid(), XAResource.TMNOFLAGS);
95  				return true;
96  			} catch (XAException e) {
97  				error("Cannot enlist " + xaRes, e);
98  				return false;
99  			}
100 		} else
101 			return false;
102 	}
103 
104 	@Override
105 	public synchronized boolean delistResource(XAResource xaRes, int flag)
106 			throws IllegalStateException, SystemException {
107 		if (xaResources.remove(xaRes)) {
108 			try {
109 				xaRes.end(getXid(), flag);
110 			} catch (XAException e) {
111 				error("Cannot delist " + xaRes, e);
112 				return false;
113 			}
114 			return true;
115 		} else
116 			return false;
117 	}
118 
119 	protected void clearResources(int flag) {
120 		for (XAResource xaRes : xaResources)
121 			try {
122 				xaRes.end(getXid(), flag);
123 			} catch (XAException e) {
124 				error("Cannot end " + xaRes, e);
125 			}
126 		xaResources.clear();
127 	}
128 
129 	protected void error(Object obj, Exception e) {
130 		System.err.println(obj);
131 		e.printStackTrace();
132 	}
133 
134 	@Override
135 	public synchronized int getStatus() throws SystemException {
136 		return status;
137 	}
138 
139 	@Override
140 	public void registerSynchronization(Synchronization sync)
141 			throws RollbackException, IllegalStateException, SystemException {
142 		throw new UnsupportedOperationException();
143 	}
144 
145 	@Override
146 	public void setRollbackOnly() throws IllegalStateException, SystemException {
147 		status = STATUS_MARKED_ROLLBACK;
148 	}
149 
150 	@Override
151 	public int hashCode() {
152 		return xid.hashCode();
153 	}
154 
155 	Xid getXid() {
156 		return xid;
157 	}
158 
159 }