1
1
package org .postgresql .jdbc2 .optional ;
2
2
3
3
import javax .sql .*;
4
- import java .sql .SQLException ;
5
- import java .sql .Connection ;
4
+ import java .sql .*;
6
5
import java .util .*;
7
6
import java .lang .reflect .*;
8
7
13
12
* @see ConnectionPool
14
13
*
15
14
* @author Aaron Mulder (ammulder@chariotsolutions.com)
16
- * @version $Revision: 1.3 $
15
+ * @version $Revision: 1.4 $
17
16
*/
18
17
public class PooledConnectionImpl implements PooledConnection
19
18
{
@@ -115,7 +114,9 @@ public Connection getConnection() throws SQLException
115
114
con .setAutoCommit (autoCommit );
116
115
ConnectionHandler handler = new ConnectionHandler (con );
117
116
last = handler ;
118
- return (Connection )Proxy .newProxyInstance (getClass ().getClassLoader (), new Class []{Connection .class }, handler );
117
+ Connection con = (Connection )Proxy .newProxyInstance (getClass ().getClassLoader (), new Class []{Connection .class }, handler );
118
+ last .setProxy (con );
119
+ return con ;
119
120
}
120
121
121
122
/**
@@ -166,6 +167,7 @@ void fireConnectionFatalError(SQLException e)
166
167
private class ConnectionHandler implements InvocationHandler
167
168
{
168
169
private Connection con ;
170
+ private Connection proxy ; // the Connection the client is currently using, which is a proxy
169
171
private boolean automatic = false ;
170
172
171
173
public ConnectionHandler (Connection con )
@@ -229,6 +231,7 @@ public Object invoke(Object proxy, Method method, Object[] args)
229
231
}
230
232
con .clearWarnings ();
231
233
con = null ;
234
+ proxy = null ;
232
235
last = null ;
233
236
fireConnectionClosed ();
234
237
if (ex != null )
@@ -237,20 +240,123 @@ public Object invoke(Object proxy, Method method, Object[] args)
237
240
}
238
241
return null ;
239
242
}
243
+ else if (method .getName ().equals ("createStatement" ))
244
+ {
245
+ Statement st = (Statement )method .invoke (con , args );
246
+ return Proxy .newProxyInstance (getClass ().getClassLoader (), new Class []{Statement .class }, new StatementHandler (this , st ));
247
+ }
248
+ else if (method .getName ().equals ("prepareCall" ))
249
+ {
250
+ Statement st = (Statement )method .invoke (con , args );
251
+ return Proxy .newProxyInstance (getClass ().getClassLoader (), new Class []{CallableStatement .class }, new StatementHandler (this , st ));
252
+ }
253
+ else if (method .getName ().equals ("prepareStatement" ))
254
+ {
255
+ Statement st = (Statement )method .invoke (con , args );
256
+ return Proxy .newProxyInstance (getClass ().getClassLoader (), new Class []{PreparedStatement .class }, new StatementHandler (this , st ));
257
+ }
240
258
else
241
259
{
242
260
return method .invoke (con , args );
243
261
}
244
262
}
245
263
264
+ Connection getProxy () {
265
+ return proxy ;
266
+ }
267
+
268
+ void setProxy (Connection proxy ) {
269
+ this .proxy = proxy ;
270
+ }
271
+
246
272
public void close ()
247
273
{
248
274
if (con != null )
249
275
{
250
276
automatic = true ;
251
277
}
252
278
con = null ;
279
+ proxy = null ;
253
280
// No close event fired here: see JDBC 2.0 Optional Package spec section 6.3
254
281
}
282
+
283
+ public boolean isClosed () {
284
+ return con == null ;
285
+ }
255
286
}
287
+
288
+ /**
289
+ * Instead of declaring classes implementing Statement, PreparedStatement,
290
+ * and CallableStatement, which would have to be updated for every JDK rev,
291
+ * use a dynamic proxy to handle all calls through the Statement
292
+ * interfaces. This is the part that requires JDK 1.3 or higher, though
293
+ * JDK 1.2 could be supported with a 3rd-party proxy package.
294
+ *
295
+ * The StatementHandler is required in order to return the proper
296
+ * Connection proxy for the getConnection method.
297
+ */
298
+ private static class StatementHandler implements InvocationHandler {
299
+ private ConnectionHandler con ;
300
+ private Statement st ;
301
+
302
+ public StatementHandler (ConnectionHandler con , Statement st ) {
303
+ this .con = con ;
304
+ this .st = st ;
305
+ }
306
+ public Object invoke (Object proxy , Method method , Object [] args )
307
+ throws Throwable
308
+ {
309
+ // From Object
310
+ if (method .getDeclaringClass ().getName ().equals ("java.lang.Object" ))
311
+ {
312
+ if (method .getName ().equals ("toString" ))
313
+ {
314
+ return "Pooled statement wrapping physical statement " + st ;
315
+ }
316
+ if (method .getName ().equals ("hashCode" ))
317
+ {
318
+ return new Integer (st .hashCode ());
319
+ }
320
+ if (method .getName ().equals ("equals" ))
321
+ {
322
+ if (args [0 ] == null )
323
+ {
324
+ return Boolean .FALSE ;
325
+ }
326
+ try
327
+ {
328
+ return Proxy .isProxyClass (args [0 ].getClass ()) && ((StatementHandler ) Proxy .getInvocationHandler (args [0 ])).st == st ? Boolean .TRUE : Boolean .FALSE ;
329
+ }
330
+ catch (ClassCastException e )
331
+ {
332
+ return Boolean .FALSE ;
333
+ }
334
+ }
335
+ return method .invoke (st , args );
336
+ }
337
+ // All the rest is from the Statement interface
338
+ if (st == null || con .isClosed ())
339
+ {
340
+ throw new SQLException ("Statement has been closed" );
341
+ }
342
+ if (method .getName ().equals ("close" ))
343
+ {
344
+ try {
345
+ st .close ();
346
+ } finally {
347
+ con = null ;
348
+ st = null ;
349
+ return null ;
350
+ }
351
+ }
352
+ else if (method .getName ().equals ("getConnection" ))
353
+ {
354
+ return con .getProxy (); // the proxied connection, not a physical connection
355
+ }
356
+ else
357
+ {
358
+ return method .invoke (st , args );
359
+ }
360
+ }
361
+ }
256
362
}
0 commit comments