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