1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.dbcp2.managed;
19
20 import java.lang.reflect.InvocationHandler;
21 import java.lang.reflect.InvocationTargetException;
22 import java.lang.reflect.Method;
23 import java.lang.reflect.Proxy;
24 import java.sql.Connection;
25 import java.sql.SQLException;
26 import java.util.ArrayList;
27 import java.util.LinkedList;
28 import java.util.List;
29 import java.util.concurrent.atomic.AtomicInteger;
30
31 import javax.sql.ConnectionEvent;
32 import javax.sql.ConnectionEventListener;
33 import javax.sql.StatementEventListener;
34 import javax.sql.XAConnection;
35 import javax.transaction.xa.XAResource;
36
37
38
39
40
41
42
43 public class TesterBasicXAConnection implements XAConnection {
44
45
46
47
48
49 public static class ConnectionHandle implements InvocationHandler {
50
51 public Connection conn;
52
53 public final TesterBasicXAConnection xaconn;
54
55 public ConnectionHandle(final Connection conn, final TesterBasicXAConnection xaconn) {
56 this.conn = conn;
57 this.xaconn = xaconn;
58 }
59
60 protected Object close() throws SQLException {
61 if (conn != null) {
62 conn.clearWarnings();
63 conn = null;
64 xaconn.handle = null;
65 xaconn.notifyConnectionClosed();
66 }
67 return null;
68 }
69
70 public void closeHandle() {
71 conn = null;
72 }
73
74 @Override
75 public Object invoke(final Object proxy, final Method method, final Object[] args)
76 throws Throwable {
77 final String methodName = method.getName();
78 if (methodName.equals("hashCode")) {
79 return System.identityHashCode(proxy);
80 }
81 if (methodName.equals("equals")) {
82 return proxy == args[0];
83 }
84 if (methodName.equals("isClosed")) {
85 return conn == null;
86 }
87 if (methodName.equals("close")) {
88 return close();
89 }
90 if (conn == null) {
91 throw new SQLException("Connection closed");
92 }
93 try {
94 return method.invoke(conn, args);
95 } catch (final InvocationTargetException e) {
96 final Throwable te = e.getTargetException();
97 if (te instanceof SQLException) {
98 xaconn.notifyConnectionErrorOccurred((SQLException) te);
99 }
100 throw te;
101 }
102 }
103 }
104
105 public Connection conn;
106
107 public ConnectionHandle handle;
108
109 public final List<ConnectionEventListener> listeners = new LinkedList<>();
110
111 public final AtomicInteger closeCounter;
112
113 public TesterBasicXAConnection(final Connection conn) {
114 this(conn, null);
115 }
116
117 public TesterBasicXAConnection(final Connection conn, final AtomicInteger closeCounter) {
118 this.conn = conn;
119 this.closeCounter = closeCounter;
120 }
121
122 @Override
123 public void addConnectionEventListener(
124 final ConnectionEventListener connectionEventListener) {
125 listeners.add(connectionEventListener);
126 }
127
128 @Override
129 public void addStatementEventListener(final StatementEventListener listener) {
130 throw new UnsupportedOperationException();
131 }
132
133 @Override
134 public void close() throws SQLException {
135 if (handle != null) {
136 closeHandle();
137 }
138 try {
139 conn.close();
140 if (closeCounter != null) {
141 closeCounter.incrementAndGet();
142 }
143 } finally {
144 conn = null;
145 }
146 }
147
148 protected void closeHandle() throws SQLException {
149 handle.closeHandle();
150 if (!conn.getAutoCommit()) {
151 try {
152 conn.rollback();
153 } catch (final SQLException e) {
154 e.printStackTrace();
155 }
156 }
157 handle = null;
158 }
159
160 @Override
161 public Connection getConnection() throws SQLException {
162 if (conn == null) {
163 final SQLException e = new SQLException("XAConnection closed");
164 notifyConnectionErrorOccurred(e);
165 throw e;
166 }
167 try {
168 if (handle != null) {
169
170 closeHandle();
171 conn.clearWarnings();
172 }
173 } catch (final SQLException e) {
174 notifyConnectionErrorOccurred(e);
175 throw e;
176 }
177 handle = new ConnectionHandle(conn, this);
178 return (Connection) Proxy.newProxyInstance(
179 getClass().getClassLoader(), new Class[] { Connection.class },
180 handle);
181 }
182
183 @Override
184 public XAResource getXAResource() throws SQLException {
185 return new LocalXAConnectionFactory.LocalXAResource(conn);
186 }
187
188 protected void notifyConnectionClosed() {
189 final ConnectionEvent event = new ConnectionEvent(this);
190 final List<ConnectionEventListener> copy = new ArrayList<>(
191 listeners);
192 for (final ConnectionEventListener listener : copy) {
193 listener.connectionClosed(event);
194 }
195 }
196
197 protected void notifyConnectionErrorOccurred(final SQLException e) {
198 final ConnectionEvent event = new ConnectionEvent(this, e);
199 final List<ConnectionEventListener> copy = new ArrayList<>(
200 listeners);
201 for (final ConnectionEventListener listener : copy) {
202 listener.connectionErrorOccurred(event);
203 }
204 }
205
206 @Override
207 public void removeConnectionEventListener(
208 final ConnectionEventListener connectionEventListener) {
209 listeners.remove(connectionEventListener);
210 }
211
212 @Override
213 public void removeStatementEventListener(final StatementEventListener listener) {
214 throw new UnsupportedOperationException();
215 }
216 }
217