11package org .postgresql .jdbc2 .optional ;
22
33import javax .sql .*;
4- import java .sql .SQLException ;
5- import java .sql .Connection ;
4+ import java .sql .*;
65import java .util .*;
76import java .lang .reflect .*;
87
1312 * @see ConnectionPool
1413 *
1514 * @author Aaron Mulder (ammulder@chariotsolutions.com)
16- * @version $Revision: 1.3 $
15+ * @version $Revision: 1.4 $
1716 */
1817public class PooledConnectionImpl implements PooledConnection
1918{
@@ -115,7 +114,9 @@ public Connection getConnection() throws SQLException
115114 con .setAutoCommit (autoCommit );
116115 ConnectionHandler handler = new ConnectionHandler (con );
117116 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 ;
119120 }
120121
121122 /**
@@ -166,6 +167,7 @@ void fireConnectionFatalError(SQLException e)
166167 private class ConnectionHandler implements InvocationHandler
167168 {
168169 private Connection con ;
170+ private Connection proxy ; // the Connection the client is currently using, which is a proxy
169171 private boolean automatic = false ;
170172
171173 public ConnectionHandler (Connection con )
@@ -229,6 +231,7 @@ public Object invoke(Object proxy, Method method, Object[] args)
229231 }
230232 con .clearWarnings ();
231233 con = null ;
234+ proxy = null ;
232235 last = null ;
233236 fireConnectionClosed ();
234237 if (ex != null )
@@ -237,20 +240,123 @@ public Object invoke(Object proxy, Method method, Object[] args)
237240 }
238241 return null ;
239242 }
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+ }
240258 else
241259 {
242260 return method .invoke (con , args );
243261 }
244262 }
245263
264+ Connection getProxy () {
265+ return proxy ;
266+ }
267+
268+ void setProxy (Connection proxy ) {
269+ this .proxy = proxy ;
270+ }
271+
246272 public void close ()
247273 {
248274 if (con != null )
249275 {
250276 automatic = true ;
251277 }
252278 con = null ;
279+ proxy = null ;
253280 // No close event fired here: see JDBC 2.0 Optional Package spec section 6.3
254281 }
282+
283+ public boolean isClosed () {
284+ return con == null ;
285+ }
255286 }
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+ }
256362}
0 commit comments