1 /**
2 *
3 * Copyright 2006 The Apache Software Foundation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.geronimo.transaction.manager;
18
19 import java.util.Collection;
20 import java.util.HashMap;
21 import java.util.Iterator;
22 import java.util.Map;
23 import javax.resource.spi.XATerminator;
24 import javax.transaction.InvalidTransactionException;
25 import javax.transaction.Status;
26 import javax.transaction.SystemException;
27 import javax.transaction.Transaction;
28 import javax.transaction.xa.XAException;
29 import javax.transaction.xa.XAResource;
30 import javax.transaction.xa.Xid;
31
32 /**
33 * @version $Rev: 437254 $ $Date: 2006-08-26 17:07:55 -0700 (Sat, 26 Aug 2006) $
34 */
35 public class GeronimoTransactionManager extends TransactionManagerImpl implements XATerminator, XAWork {
36 private final Map importedTransactions = new HashMap();
37 private boolean isInRecovery = false;
38
39 public GeronimoTransactionManager() throws XAException {
40 }
41
42 public GeronimoTransactionManager(int defaultTransactionTimeoutSeconds) throws XAException {
43 super(defaultTransactionTimeoutSeconds);
44 }
45
46 public GeronimoTransactionManager(int defaultTransactionTimeoutSeconds, TransactionLog transactionLog) throws XAException {
47 super(defaultTransactionTimeoutSeconds, transactionLog);
48 }
49
50 public GeronimoTransactionManager(int defaultTransactionTimeoutSeconds, XidFactory xidFactory, TransactionLog transactionLog, Collection resourceManagers) throws XAException {
51 super(defaultTransactionTimeoutSeconds, xidFactory, transactionLog, resourceManagers);
52 }
53
54 /**
55 * @see javax.resource.spi.XATerminator#commit(javax.transaction.xa.Xid, boolean)
56 */
57 public void commit(Xid xid, boolean onePhase) throws XAException {
58 Transaction importedTransaction;
59 synchronized (importedTransactions) {
60 importedTransaction = (Transaction) importedTransactions.remove(xid);
61 }
62 if (importedTransaction == null) {
63 throw new XAException("No imported transaction for xid: " + xid);
64 }
65
66 try {
67 int status = importedTransaction.getStatus();
68 assert status == Status.STATUS_ACTIVE || status == Status.STATUS_PREPARED: "invalid status: " + status;
69 } catch (SystemException e) {
70 throw new XAException();
71 }
72 commit(importedTransaction, onePhase);
73 }
74
75 /**
76 * @see javax.resource.spi.XATerminator#forget(javax.transaction.xa.Xid)
77 */
78 public void forget(Xid xid) throws XAException {
79 Transaction importedTransaction;
80 synchronized (importedTransactions) {
81 importedTransaction = (Transaction) importedTransactions.remove(xid);
82 }
83 if (importedTransaction == null) {
84 throw new XAException("No imported transaction for xid: " + xid);
85 }
86
87
88
89
90
91
92
93 forget(importedTransaction);
94 }
95
96 /**
97 * @see javax.resource.spi.XATerminator#prepare(javax.transaction.xa.Xid)
98 */
99 public int prepare(Xid xid) throws XAException {
100 Transaction importedTransaction;
101 synchronized (importedTransactions) {
102 importedTransaction = (Transaction) importedTransactions.get(xid);
103 }
104 if (importedTransaction == null) {
105 throw new XAException("No imported transaction for xid: " + xid);
106 }
107 try {
108 int status = importedTransaction.getStatus();
109 assert status == Status.STATUS_ACTIVE;
110 } catch (SystemException e) {
111 throw new XAException();
112 }
113 return prepare(importedTransaction);
114 }
115
116 /**
117 * @see javax.resource.spi.XATerminator#recover(int)
118 */
119 public Xid[] recover(int flag) throws XAException {
120 if (!isInRecovery) {
121 if ((flag & XAResource.TMSTARTRSCAN) == 0) {
122 throw new XAException(XAException.XAER_PROTO);
123 }
124 isInRecovery = true;
125 }
126 if ((flag & XAResource.TMENDRSCAN) != 0) {
127 isInRecovery = false;
128 }
129
130
131 if ((flag & XAResource.TMSTARTRSCAN) != 0) {
132 Map recoveredXidMap = getExternalXids();
133 Xid[] recoveredXids = new Xid[recoveredXidMap.size()];
134 int i = 0;
135 synchronized (importedTransactions) {
136 for (Iterator iterator = recoveredXidMap.entrySet().iterator(); iterator.hasNext();) {
137 Map.Entry entry = (Map.Entry) iterator.next();
138 Xid xid = (Xid) entry.getKey();
139 recoveredXids[i++] = xid;
140 Transaction transaction = (Transaction) entry.getValue();
141 importedTransactions.put(xid, transaction);
142 }
143 }
144 return recoveredXids;
145 } else {
146 return new Xid[0];
147 }
148 }
149
150 /**
151 * @see javax.resource.spi.XATerminator#rollback(javax.transaction.xa.Xid)
152 */
153 public void rollback(Xid xid) throws XAException {
154 Transaction importedTransaction;
155 synchronized (importedTransactions) {
156 importedTransaction = (Transaction) importedTransactions.remove(xid);
157 }
158 if (importedTransaction == null) {
159 throw new XAException("No imported transaction for xid: " + xid);
160 }
161 try {
162 int status = importedTransaction.getStatus();
163 assert status == Status.STATUS_ACTIVE || status == Status.STATUS_PREPARED;
164 } catch (SystemException e) {
165 throw new XAException();
166 }
167 rollback(importedTransaction);
168 }
169
170
171
172 public void begin(Xid xid, long txTimeoutMillis) throws XAException, InvalidTransactionException, SystemException, ImportedTransactionActiveException {
173 Transaction importedTransaction;
174 synchronized (importedTransactions) {
175 importedTransaction = (Transaction) importedTransactions.get(xid);
176 if (importedTransaction == null) {
177
178 importedTransaction = importXid(xid, txTimeoutMillis);
179 importedTransactions.put(xid, importedTransaction);
180 }
181
182 try {
183 resume(importedTransaction);
184 } catch (InvalidTransactionException e) {
185
186 throw new ImportedTransactionActiveException(xid);
187 }
188 }
189 }
190
191 public void end(Xid xid) throws XAException, SystemException {
192 synchronized (importedTransactions) {
193 Transaction importedTransaction = (Transaction) importedTransactions.get(xid);
194 if (importedTransaction == null) {
195 throw new XAException("No imported transaction for xid: " + xid);
196 }
197 if (importedTransaction != getTransaction()) {
198 throw new XAException("Imported transaction is not associated with the curren thread xid: " + xid);
199 }
200 suspend();
201 }
202 }
203 }