1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 package com.gargoylesoftware.base.resource.jdbc;
39
40 import com.gargoylesoftware.base.util.ProxyUtil;
41 import java.lang.reflect.InvocationHandler;
42 import java.lang.reflect.Method;
43 import java.lang.reflect.Proxy;
44 import java.sql.CallableStatement;
45 import java.sql.Connection;
46 import java.sql.DatabaseMetaData;
47 import java.sql.PreparedStatement;
48 import java.sql.SQLException;
49 import java.sql.Statement;
50 import java.util.ArrayList;
51 import java.util.List;
52 import junit.framework.Test;
53 import junit.framework.TestCase;
54 import junit.framework.TestSuite;
55
56 /***
57 * Tests for ConnectionWrapper
58 *
59 * @version $Revision: 1.5 $
60 * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
61 */
62 public class ConnectionWrapperTest extends TestCase {
63
64 /***
65 * Create a test
66 *
67 * @param name The name of the test
68 */
69 public ConnectionWrapperTest( final String name ) {
70 super( name );
71 }
72
73
74 /***
75 * Return a test suite containing all the tests for this class
76 *
77 * @return The test suite
78 */
79 public static Test suite() {
80 final String excludedMethods[] = {
81 "close", "isClosed", "getMetaData"
82 };
83 final String wrappedMethods[] = {
84 "createStatement", "prepareStatement", "prepareCall"
85 };
86 final TestSuite suite = WrapperTestCase.getWrapperTestSuite(
87 Connection.class, ConnectionWrapper.class, excludedMethods, wrappedMethods );
88
89 suite.addTest( new TestSuite( ConnectionWrapperTest.class ) );
90
91 return suite;
92 }
93
94
95 /***
96 * Try passing null into the constructor
97 */
98 public void testConstructor_Null() {
99 try {
100 new ConnectionWrapper( null );
101 fail( "Expected exception" );
102 }
103 catch( final NullPointerException e ) {
104
105 }
106 }
107
108
109 /***
110 * Test createStatement(). Make sure that it returns a wrapped statement.
111 * Then make sure that the statement is closed when the connection is
112 * closed.
113 *
114 * @exception SQLException If an error occurs
115 */
116 public void testCreateStatement()
117 throws SQLException {
118 final List list = new ArrayList();
119 final Statement statement = (Statement)createTracingProxy( Statement.class, list );
120 final Connection connection = (Connection)ProxyUtil.createProxy(
121 Connection.class, new Object[][]{{"createStatement", statement}} );
122
123 final ConnectionWrapper connectionWrapper = new ConnectionWrapper( connection );
124 final Statement wrappedStatement = connectionWrapper.createStatement();
125
126 assertTrue( "statement is wrapped", wrappedStatement instanceof StatementWrapper );
127 assertSame( "wrapped statement", statement, ( (StatementWrapper)wrappedStatement ).getDelegate() );
128
129 assertEquals( "list.size before close", 0, list.size() );
130 connectionWrapper.close();
131 assertEquals( "list.size after close", 1, list.size() );
132 assertEquals( "closeMethod", "close", ( (Method)list.get( 0 ) ).getName() );
133 }
134
135
136 /***
137 * Test createStatement(). Make sure that it returns a wrapped statement.
138 * Then make sure that the statement is closed when the connection is
139 * closed.
140 *
141 * @exception SQLException If an error occurs
142 */
143 public void testCreateStatement_intint()
144 throws SQLException {
145 final List list = new ArrayList();
146 final Statement statement = (Statement)createTracingProxy( Statement.class, list );
147 final Connection connection = (Connection)ProxyUtil.createProxy(
148 Connection.class, new Object[][]{{"createStatement", statement}} );
149
150 final ConnectionWrapper connectionWrapper = new ConnectionWrapper( connection );
151 final Statement wrappedStatement = connectionWrapper.createStatement( 1, 1 );
152
153 assertTrue( "statement is wrapped", wrappedStatement instanceof StatementWrapper );
154 assertSame( "wrapped statement", statement, ( (StatementWrapper)wrappedStatement ).getDelegate() );
155
156 assertEquals( "list.size before close", 0, list.size() );
157 connectionWrapper.close();
158 assertEquals( "list.size after close", 1, list.size() );
159 assertEquals( "closeMethod", "close", ( (Method)list.get( 0 ) ).getName() );
160 }
161
162
163 /***
164 * Test prepareStatement(). Make sure that it returns a wrapped statement.
165 * Then make sure that the statement is closed when the connection is
166 * closed.
167 *
168 * @exception SQLException If an error occurs
169 */
170 public void testPrepareStatement()
171 throws SQLException {
172 final List list = new ArrayList();
173 final PreparedStatement statement
174 = (PreparedStatement)createTracingProxy( PreparedStatement.class, list );
175 final Connection connection = (Connection)ProxyUtil.createProxy(
176 Connection.class, new Object[][]{{"prepareStatement", statement}} );
177
178 final ConnectionWrapper connectionWrapper = new ConnectionWrapper( connection );
179 final Statement wrappedStatement = connectionWrapper.prepareStatement( "foo" );
180
181 assertTrue( "statement is wrapped", wrappedStatement instanceof PreparedStatementWrapper );
182 assertSame( "wrapped statement", statement, ( (PreparedStatementWrapper)wrappedStatement ).getDelegate() );
183
184 assertEquals( "list.size before close", 0, list.size() );
185 connectionWrapper.close();
186 assertEquals( "list.size after close", 1, list.size() );
187 assertEquals( "closeMethod", "close", ( (Method)list.get( 0 ) ).getName() );
188 }
189
190
191 /***
192 * Test prepareStatement(). Make sure that it returns a wrapped statement.
193 * Then make sure that the statement is closed when the connection is
194 * closed.
195 *
196 * @exception SQLException If an error occurs
197 */
198 public void testPrepareStatement_StringIntInt()
199 throws SQLException {
200 final List list = new ArrayList();
201 final PreparedStatement statement
202 = (PreparedStatement)createTracingProxy( PreparedStatement.class, list );
203 final Connection connection = (Connection)ProxyUtil.createProxy(
204 Connection.class, new Object[][]{{"prepareStatement", statement}} );
205
206 final ConnectionWrapper connectionWrapper = new ConnectionWrapper( connection );
207 final Statement wrappedStatement = connectionWrapper.prepareStatement( "foo", 1, 1 );
208
209 assertTrue( "statement is wrapped", wrappedStatement instanceof PreparedStatementWrapper );
210 assertSame( "wrapped statement", statement, ( (PreparedStatementWrapper)wrappedStatement ).getDelegate() );
211
212 assertEquals( "list.size before close", 0, list.size() );
213 connectionWrapper.close();
214 assertEquals( "list.size after close", 1, list.size() );
215 assertEquals( "closeMethod", "close", ( (Method)list.get( 0 ) ).getName() );
216 }
217
218
219 /***
220 * Test prepareCall(). Make sure that it returns a wrapped statement. Then
221 * make sure that the statement is closed when the connection is closed.
222 *
223 * @exception SQLException If an error occurs
224 */
225 public void testPrepareCall_String()
226 throws SQLException {
227 final List list = new ArrayList();
228 final CallableStatement statement
229 = (CallableStatement)createTracingProxy( CallableStatement.class, list );
230 final Connection connection = (Connection)ProxyUtil.createProxy(
231 Connection.class, new Object[][]{{"prepareCall", statement}} );
232
233 final ConnectionWrapper connectionWrapper = new ConnectionWrapper( connection );
234 final Statement wrappedStatement = connectionWrapper.prepareCall( "foo" );
235
236 assertTrue( "statement is wrapped", wrappedStatement instanceof CallableStatementWrapper );
237 assertSame( "wrapped statement", statement, ( (CallableStatementWrapper)wrappedStatement ).getDelegate() );
238
239 assertEquals( "list.size before close", 0, list.size() );
240 connectionWrapper.close();
241 assertEquals( "list.size after close", 1, list.size() );
242 assertEquals( "closeMethod", "close", ( (Method)list.get( 0 ) ).getName() );
243 }
244
245
246 /***
247 * Test prepareCall(). Make sure that it returns a wrapped statement. Then
248 * make sure that the statement is closed when the connection is closed.
249 *
250 * @exception SQLException If an error occurs
251 */
252 public void testPrepareCall_StringIntInt()
253 throws SQLException {
254 final List list = new ArrayList();
255 final CallableStatement statement
256 = (CallableStatement)createTracingProxy( CallableStatement.class, list );
257 final Connection connection = (Connection)ProxyUtil.createProxy(
258 Connection.class, new Object[][]{{"prepareCall", statement}} );
259
260 final ConnectionWrapper connectionWrapper = new ConnectionWrapper( connection );
261 final Statement wrappedStatement = connectionWrapper.prepareCall( "foo", 1, 1 );
262
263 assertTrue( "statement is wrapped", wrappedStatement instanceof CallableStatementWrapper );
264 assertSame( "wrapped statement", statement, ( (CallableStatementWrapper)wrappedStatement ).getDelegate() );
265
266 assertEquals( "list.size before close", 0, list.size() );
267 connectionWrapper.close();
268 assertEquals( "list.size after close", 1, list.size() );
269 assertEquals( "closeMethod", "close", ( (Method)list.get( 0 ) ).getName() );
270 }
271
272
273 /***
274 * Test the getMetaData() method to ensure that:
275 * <ol>
276 * <li> The DatabaseMetaData object is wrapped
277 * <li> The DatabaseMetaData object returns the wrapped connection when
278 * getConnection is called on it.
279 * </ol>
280 *
281 *
282 * @exception Exception If an error occurs
283 */
284 public void testGetDatabaseMetaData()
285 throws Exception {
286 final DatabaseMetaData metaData
287 = (DatabaseMetaData)ProxyUtil.createProxy( DatabaseMetaData.class );
288 final Connection connection = (Connection)ProxyUtil.createProxy(
289 Connection.class, new Object[][]{{"getMetaData", metaData}} );
290
291 final ConnectionWrapper connectionWrapper = new ConnectionWrapper( connection );
292 final DatabaseMetaData wrappedMetaData = connectionWrapper.getMetaData();
293
294 assertTrue( "metadata is wrapped", wrappedMetaData instanceof DatabaseMetaDataWrapper );
295 assertSame( "wrapped metaData", metaData, ( (DatabaseMetaDataWrapper)wrappedMetaData ).getDelegate() );
296
297 assertEquals( "metaData.getConnection", connectionWrapper, wrappedMetaData.getConnection() );
298
299 connectionWrapper.close();
300
301 try {
302 wrappedMetaData.getConnection();
303 fail( "Expected exception" );
304 }
305 catch( final SQLException e ) {
306
307 }
308 }
309
310
311 /***
312 * Try closing the connection twice
313 *
314 * @exception Exception If an error occurs
315 */
316 public void testCloseTwice()
317 throws Exception {
318 final Connection connection = (Connection)ProxyUtil.createProxy( Connection.class );
319 final ConnectionWrapper wrapper = new ConnectionWrapper( connection );
320
321 wrapper.close();
322 try {
323 wrapper.close();
324 fail( "Expected exception when calling close() on a closed object" );
325 }
326 catch( final AlreadyClosedException e ) {
327
328 }
329 }
330
331
332 /***
333 * Regression test for bug where isClosed() would throw a
334 * NullPointerException if the connection was already closed
335 *
336 * @exception Exception If an error occurs
337 */
338 public void testIsClosedOnClosedConnection()
339 throws Exception {
340 final Connection connection = (Connection)ProxyUtil.createProxy( Connection.class );
341 final ConnectionWrapper wrapper = new ConnectionWrapper( connection );
342
343 wrapper.close();
344 assertTrue( wrapper.isClosed() );
345 }
346
347
348 /***
349 * Test releaseAll where one of the statements has already been closed
350 *
351 * @exception Exception If an error occurs
352 */
353 public void testCloseWhenStatementAlreadyClosed()
354 throws Exception {
355 final Statement statement
356 = (Statement)ProxyUtil.createProxy( Statement.class );
357
358 final Connection connection
359 = (Connection)ProxyUtil.createProxy( Connection.class,
360 new Object[][]{{"createStatement", new StatementWrapper( statement )}} );
361
362 final ConnectionWrapper connectionWrapper
363 = new ConnectionWrapper( connection );
364
365 final StatementWrapper statementWrapper
366 = (StatementWrapper)connectionWrapper.createStatement();
367 statementWrapper.close();
368
369 connectionWrapper.close();
370 }
371
372
373 /***
374 * Create a proxy object that tracks what methods were called
375 *
376 * @param clazz The interface used to create the proxy
377 * @param list The list that will contain all the method objects
378 * @return The new proxy object
379 */
380 private Object createTracingProxy( final Class clazz, final List list ) {
381 final InvocationHandler handler =
382 new InvocationHandler() {
383 public Object invoke( Object proxy, Method method, Object[] methodArgs ) {
384 list.add( method );
385 return null;
386 }
387 };
388 return Proxy.newProxyInstance(
389 clazz.getClassLoader(),
390 new Class[]{clazz},
391 handler );
392 }
393 }
394