1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.ibatis.datasource.pooled;
17
18 import java.lang.reflect.InvocationHandler;
19 import java.lang.reflect.Method;
20 import java.lang.reflect.Proxy;
21 import java.sql.Connection;
22 import java.sql.SQLException;
23
24 import org.apache.ibatis.reflection.ExceptionUtil;
25
26
27
28
29 class PooledConnection implements InvocationHandler {
30
31 private static final String CLOSE = "close";
32 private static final Class<?>[] IFACES = new Class<?>[] { Connection.class };
33
34 private final int hashCode;
35 private final PooledDataSource dataSource;
36 private final Connection realConnection;
37 private final Connection proxyConnection;
38 private long checkoutTimestamp;
39 private long createdTimestamp;
40 private long lastUsedTimestamp;
41 private int connectionTypeCode;
42 private boolean valid;
43
44
45
46
47
48
49
50
51
52 public PooledConnection(Connection connection, PooledDataSource dataSource) {
53 this.hashCode = connection.hashCode();
54 this.realConnection = connection;
55 this.dataSource = dataSource;
56 this.createdTimestamp = System.currentTimeMillis();
57 this.lastUsedTimestamp = System.currentTimeMillis();
58 this.valid = true;
59 this.proxyConnection = (Connection) Proxy.newProxyInstance(Connection.class.getClassLoader(), IFACES, this);
60 }
61
62
63
64
65 public void invalidate() {
66 valid = false;
67 }
68
69
70
71
72
73
74 public boolean isValid() {
75 return valid && realConnection != null && dataSource.pingConnection(this);
76 }
77
78
79
80
81
82
83 public Connection getRealConnection() {
84 return realConnection;
85 }
86
87
88
89
90
91
92 public Connection getProxyConnection() {
93 return proxyConnection;
94 }
95
96
97
98
99
100
101 public int getRealHashCode() {
102 return realConnection == null ? 0 : realConnection.hashCode();
103 }
104
105
106
107
108
109
110 public int getConnectionTypeCode() {
111 return connectionTypeCode;
112 }
113
114
115
116
117
118
119
120 public void setConnectionTypeCode(int connectionTypeCode) {
121 this.connectionTypeCode = connectionTypeCode;
122 }
123
124
125
126
127
128
129 public long getCreatedTimestamp() {
130 return createdTimestamp;
131 }
132
133
134
135
136
137
138
139 public void setCreatedTimestamp(long createdTimestamp) {
140 this.createdTimestamp = createdTimestamp;
141 }
142
143
144
145
146
147
148 public long getLastUsedTimestamp() {
149 return lastUsedTimestamp;
150 }
151
152
153
154
155
156
157
158 public void setLastUsedTimestamp(long lastUsedTimestamp) {
159 this.lastUsedTimestamp = lastUsedTimestamp;
160 }
161
162
163
164
165
166
167 public long getTimeElapsedSinceLastUse() {
168 return System.currentTimeMillis() - lastUsedTimestamp;
169 }
170
171
172
173
174
175
176 public long getAge() {
177 return System.currentTimeMillis() - createdTimestamp;
178 }
179
180
181
182
183
184
185 public long getCheckoutTimestamp() {
186 return checkoutTimestamp;
187 }
188
189
190
191
192
193
194
195 public void setCheckoutTimestamp(long timestamp) {
196 this.checkoutTimestamp = timestamp;
197 }
198
199
200
201
202
203
204 public long getCheckoutTime() {
205 return System.currentTimeMillis() - checkoutTimestamp;
206 }
207
208 @Override
209 public int hashCode() {
210 return hashCode;
211 }
212
213
214
215
216
217
218
219
220 @Override
221 public boolean equals(Object obj) {
222 if (obj instanceof PooledConnection) {
223 return realConnection.hashCode() == ((PooledConnection) obj).realConnection.hashCode();
224 } else if (obj instanceof Connection) {
225 return hashCode == obj.hashCode();
226 } else {
227 return false;
228 }
229 }
230
231
232
233
234
235
236
237
238
239
240
241
242 @Override
243 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
244 String methodName = method.getName();
245 if (CLOSE.equals(methodName)) {
246 dataSource.pushConnection(this);
247 return null;
248 }
249 try {
250 if (!Object.class.equals(method.getDeclaringClass())) {
251
252
253 checkConnection();
254 }
255 return method.invoke(realConnection, args);
256 } catch (Throwable t) {
257 throw ExceptionUtil.unwrapThrowable(t);
258 }
259
260 }
261
262 private void checkConnection() throws SQLException {
263 if (!valid) {
264 throw new SQLException("Error accessing PooledConnection. Connection is invalid.");
265 }
266 }
267
268 }