1 | package com.mysql.jdbc.jdbc2.optional; |
2 | |
3 | |
4 | import java.sql.SQLException; |
5 | import java.util.HashMap; |
6 | import java.util.Map; |
7 | |
8 | import javax.sql.XAConnection; |
9 | import javax.transaction.xa.XAException; |
10 | import javax.transaction.xa.XAResource; |
11 | import javax.transaction.xa.Xid; |
12 | |
13 | import com.mysql.jdbc.Connection; |
14 | |
15 | public class SuspendableXAConnection extends MysqlPooledConnection implements |
16 | XAConnection, XAResource { |
17 | |
18 | public SuspendableXAConnection(Connection connection) { |
19 | super(connection); |
20 | this.underlyingConnection = connection; |
21 | } |
22 | |
23 | private static final Map XIDS_TO_PHYSICAL_CONNECTIONS = |
24 | new HashMap(); |
25 | |
26 | private Xid currentXid; |
27 | |
28 | private XAConnection currentXAConnection; |
29 | private XAResource currentXAResource; |
30 | |
31 | private Connection underlyingConnection; |
32 | |
33 | private static synchronized XAConnection findConnectionForXid(Connection connectionToWrap, Xid xid) |
34 | throws SQLException { |
35 | // TODO: check for same GTRID, but different BQUALs...MySQL doesn't allow this yet |
36 | |
37 | // Note, we don't need to check for XIDs here, because MySQL itself will complain |
38 | // with a XAER_NOTA if need be. |
39 | |
40 | XAConnection conn = (XAConnection)XIDS_TO_PHYSICAL_CONNECTIONS.get(xid); |
41 | |
42 | if (conn == null) { |
43 | conn = new MysqlXAConnection(connectionToWrap); |
44 | } |
45 | |
46 | return conn; |
47 | } |
48 | |
49 | private static synchronized void removeXAConnectionMapping(Xid xid) { |
50 | XIDS_TO_PHYSICAL_CONNECTIONS.remove(xid); |
51 | } |
52 | |
53 | private synchronized void switchToXid(Xid xid) throws XAException { |
54 | if (xid == null) { |
55 | throw new XAException(); |
56 | } |
57 | |
58 | try { |
59 | if (!xid.equals(this.currentXid)) { |
60 | XAConnection toSwitchTo = findConnectionForXid(this.underlyingConnection, xid); |
61 | this.currentXAConnection = toSwitchTo; |
62 | this.currentXid = xid; |
63 | this.currentXAResource = toSwitchTo.getXAResource(); |
64 | } |
65 | } catch (SQLException sqlEx) { |
66 | throw new XAException(); |
67 | } |
68 | } |
69 | |
70 | public XAResource getXAResource() throws SQLException { |
71 | return this; |
72 | } |
73 | |
74 | public void commit(Xid xid, boolean arg1) throws XAException { |
75 | switchToXid(xid); |
76 | this.currentXAResource.commit(xid, arg1); |
77 | removeXAConnectionMapping(xid); |
78 | } |
79 | |
80 | public void end(Xid xid, int arg1) throws XAException { |
81 | switchToXid(xid); |
82 | this.currentXAResource.end(xid, arg1); |
83 | } |
84 | |
85 | public void forget(Xid xid) throws XAException { |
86 | switchToXid(xid); |
87 | this.currentXAResource.forget(xid); |
88 | // remove? |
89 | removeXAConnectionMapping(xid); |
90 | } |
91 | |
92 | public int getTransactionTimeout() throws XAException { |
93 | // TODO Auto-generated method stub |
94 | return 0; |
95 | } |
96 | |
97 | public boolean isSameRM(XAResource xaRes) throws XAException { |
98 | return xaRes == this; |
99 | } |
100 | |
101 | public int prepare(Xid xid) throws XAException { |
102 | switchToXid(xid); |
103 | return this.currentXAResource.prepare(xid); |
104 | } |
105 | |
106 | public Xid[] recover(int flag) throws XAException { |
107 | return MysqlXAConnection.recover(this.underlyingConnection, flag); |
108 | } |
109 | |
110 | public void rollback(Xid xid) throws XAException { |
111 | switchToXid(xid); |
112 | this.currentXAResource.rollback(xid); |
113 | removeXAConnectionMapping(xid); |
114 | } |
115 | |
116 | public boolean setTransactionTimeout(int arg0) throws XAException { |
117 | // TODO Auto-generated method stub |
118 | return false; |
119 | } |
120 | |
121 | public void start(Xid xid, int arg1) throws XAException { |
122 | switchToXid(xid); |
123 | |
124 | if (arg1 != XAResource.TMJOIN) { |
125 | this.currentXAResource.start(xid, arg1); |
126 | |
127 | return; |
128 | } |
129 | |
130 | // |
131 | // Emulate join, by using resume on the same physical connection |
132 | // |
133 | |
134 | this.currentXAResource.start(xid, XAResource.TMRESUME); |
135 | } |
136 | |
137 | public synchronized java.sql.Connection getConnection() throws SQLException { |
138 | if (this.currentXAConnection == null) { |
139 | return getConnection(false, true); |
140 | } |
141 | |
142 | return this.currentXAConnection.getConnection(); |
143 | } |
144 | |
145 | public void close() throws SQLException { |
146 | if (this.currentXAConnection == null) { |
147 | super.close(); |
148 | } else { |
149 | removeXAConnectionMapping(this.currentXid); |
150 | this.currentXAConnection.close(); |
151 | } |
152 | } |
153 | } |