KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derbyTesting > functionTests > tests > jdbc4 > VerifySignatures


1 /*
2  * Derby - org.apache.derbyTesting.functionTests.tests.jdbc4.VerifySignatures
3  *
4    Licensed to the Apache Software Foundation (ASF) under one or more
5    contributor license agreements. See the NOTICE file distributed with
6    this work for additional information regarding copyright ownership.
7    The ASF licenses this file to You under the Apache License, Version 2.0
8    (the "License"); you may not use this file except in compliance with
9    the License. You may obtain a copy of the License at
10
11       http://www.apache.org/licenses/LICENSE-2.0
12
13    Unless required by applicable law or agreed to in writing, software
14    distributed under the License is distributed on an "AS IS" BASIS,
15    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16    See the License for the specific language governing permissions and
17    limitations under the License.
18  *
19  */

20
21 package org.apache.derbyTesting.functionTests.tests.jdbc4;
22
23 import java.sql.*;
24 import javax.sql.*;
25
26 import java.lang.reflect.Method JavaDoc;
27 import java.lang.reflect.Modifier JavaDoc;
28 import java.util.Arrays JavaDoc;
29 import java.util.HashSet JavaDoc;
30 import java.util.Set JavaDoc;
31 import junit.framework.Test;
32 import junit.framework.TestCase;
33 import junit.framework.TestSuite;
34 import org.apache.derbyTesting.functionTests.util.TestUtil;
35 import org.apache.derbyTesting.functionTests.util.TestDataSourceFactory;
36 import org.apache.derbyTesting.junit.BaseJDBCTestCase;
37 import org.apache.derbyTesting.junit.TestConfiguration;
38
39 /**
40  * JUnit test which checks that all methods specified by the
41  * interfaces in JDBC 4.0 are implemented. The test requires JVM 1.6
42  * to run.
43  */

44 public class VerifySignatures extends BaseJDBCTestCase {
45
46     /**
47      * All the java.sql and javax.sql interfaces specified by JDBC 4.0.
48      */

49     private final static Class JavaDoc[] JDBC_INTERFACES = {
50         java.sql.Array JavaDoc.class,
51         java.sql.Blob JavaDoc.class,
52         java.sql.CallableStatement JavaDoc.class,
53         java.sql.Clob JavaDoc.class,
54         java.sql.Connection JavaDoc.class,
55         java.sql.DatabaseMetaData JavaDoc.class,
56         java.sql.Driver JavaDoc.class,
57         java.sql.NClob JavaDoc.class,
58         java.sql.ParameterMetaData JavaDoc.class,
59         java.sql.PreparedStatement JavaDoc.class,
60         java.sql.Ref JavaDoc.class,
61         java.sql.ResultSet JavaDoc.class,
62         java.sql.ResultSetMetaData JavaDoc.class,
63         java.sql.RowId JavaDoc.class,
64         java.sql.Savepoint JavaDoc.class,
65         java.sql.SQLData JavaDoc.class,
66         java.sql.SQLInput JavaDoc.class,
67         java.sql.SQLOutput JavaDoc.class,
68         java.sql.SQLXML JavaDoc.class,
69         java.sql.Statement JavaDoc.class,
70         java.sql.Struct JavaDoc.class,
71         java.sql.Wrapper JavaDoc.class,
72         javax.sql.CommonDataSource JavaDoc.class,
73         javax.sql.ConnectionEventListener JavaDoc.class,
74         javax.sql.ConnectionPoolDataSource JavaDoc.class,
75         javax.sql.DataSource JavaDoc.class,
76         javax.sql.PooledConnection JavaDoc.class,
77         javax.sql.RowSet JavaDoc.class,
78         javax.sql.RowSetInternal JavaDoc.class,
79         javax.sql.RowSetListener JavaDoc.class,
80         javax.sql.RowSetMetaData JavaDoc.class,
81         javax.sql.RowSetReader JavaDoc.class,
82         javax.sql.RowSetWriter JavaDoc.class,
83         javax.sql.StatementEventListener JavaDoc.class,
84         javax.sql.XAConnection JavaDoc.class,
85         javax.sql.XADataSource JavaDoc.class,
86     };
87
88     /**
89      * Creates a new instance.
90      */

91     public VerifySignatures() {
92         super("VerifySignatures");
93     }
94
95     /**
96      * Build a suite of tests to be run.
97      *
98      * @return a test suite
99      * @exception SQLException if a database error occurs
100      */

101     public static Test suite() throws SQLException {
102         // set of all implementation/interface pairs found
103
Set JavaDoc<ClassInfo> classes = new HashSet JavaDoc<ClassInfo>();
104
105         collectClassesFromDataSource(classes);
106         collectClassesFromConnectionPoolDataSource(classes);
107         collectClassesFromXADataSource(classes);
108         addClass(classes,
109                  DriverManager.getDriver(TestConfiguration.getCurrent().getJDBCUrl()).getClass(),
110                  java.sql.Driver JavaDoc.class);
111
112         TestSuite suite = new TestSuite();
113
114         // all interfaces for which tests have been generated
115
Set JavaDoc<Class JavaDoc> interfaces = new HashSet JavaDoc<Class JavaDoc>();
116
117         for (ClassInfo pair : classes) {
118             // some methods are defined in many interfaces, so collect
119
// them in a set first to avoid duplicates
120
Set JavaDoc<Method JavaDoc> methods = new HashSet JavaDoc<Method JavaDoc>();
121             for (Class JavaDoc iface : getAllInterfaces(pair.jdbcInterface)) {
122                 interfaces.add(iface);
123                 for (Method JavaDoc method : iface.getMethods()) {
124                     methods.add(method);
125                 }
126             }
127             for (Method JavaDoc method : methods) {
128                 suite.addTest(new MethodTestCase(pair.derbyImplementation,
129                                                  method));
130             }
131         }
132         suite.addTest(new InterfaceCoverageTestCase(interfaces));
133         return suite;
134     }
135
136     /**
137      * Obtain a connection from a <code>DataSource</code> object and
138      * perform JDBC operations on it. Collect the classes of all JDBC
139      * objects that are found.
140      *
141      * @param classes set into which classes are collected
142      * @exception SQLException if a database error occurs
143      */

144     private static void collectClassesFromDataSource(Set JavaDoc<ClassInfo> classes)
145         throws SQLException
146     {
147         DataSource ds = TestDataSourceFactory.getDataSource();
148         addClass(classes, ds.getClass(), javax.sql.DataSource JavaDoc.class);
149         collectClassesFromConnection(ds.getConnection
150                                      (TestConfiguration.getCurrent().getUserName(),
151                                              TestConfiguration.getCurrent().getUserPassword()),
152                                      classes);
153     }
154
155     /**
156      * Obtain a connection from a <code>ConnectionPoolDataSource</code>
157      * object and perform JDBC operations on it. Collect the classes
158      * of all JDBC objects that are found.
159      *
160      * @param classes set into which classes are collected
161      * @exception SQLException if a database error occurs
162      */

163     private static void
164         collectClassesFromConnectionPoolDataSource(Set JavaDoc<ClassInfo> classes)
165         throws SQLException
166     {
167         ConnectionPoolDataSource cpds = TestDataSourceFactory.getConnectionPoolDataSource();
168         addClass(classes,
169                  cpds.getClass(), javax.sql.ConnectionPoolDataSource JavaDoc.class);
170
171         PooledConnection pc =
172             cpds.getPooledConnection(TestConfiguration.getCurrent().getUserName(),
173                     TestConfiguration.getCurrent().getUserPassword());
174         addClass(classes, pc.getClass(), javax.sql.PooledConnection JavaDoc.class);
175
176         collectClassesFromConnection(pc.getConnection(), classes);
177
178         pc.close();
179     }
180
181     /**
182      * Obtain a connection from an <code>XADataSource</code> object
183      * and perform JDBC operations on it. Collect the classes of all
184      * JDBC objects that are found.
185      *
186      * @param classes set into which classes are collected
187      * @exception SQLException if a database error occurs
188      */

189     private static void collectClassesFromXADataSource(Set JavaDoc<ClassInfo> classes)
190         throws SQLException
191     {
192         XADataSource xads = TestDataSourceFactory.getXADataSource();
193         addClass(classes, xads.getClass(), javax.sql.XADataSource JavaDoc.class);
194
195         XAConnection xaconn = xads.getXAConnection(TestConfiguration.getCurrent().getUserName(),
196                 TestConfiguration.getCurrent().getUserPassword());
197         addClass(classes, xaconn.getClass(), javax.sql.XAConnection JavaDoc.class);
198
199         collectClassesFromConnection(xaconn.getConnection(), classes);
200     }
201
202     /**
203      * Perform JDBC operations on a <code>Connection</code>. Collect
204      * the classes of all JDBC objects that are found.
205      *
206      * @param conn connection to a database
207      * @param classes set into which classes are collected
208      * @exception SQLException if a database error occurs
209      */

210     private static void collectClassesFromConnection(Connection conn,
211                                                      Set JavaDoc<ClassInfo> classes)
212         throws SQLException
213     {
214         conn.setAutoCommit(false);
215         addClass(classes, conn.getClass(), java.sql.Connection JavaDoc.class);
216
217         Savepoint sp = conn.setSavepoint();
218         addClass(classes, sp.getClass(), java.sql.Savepoint JavaDoc.class);
219         conn.releaseSavepoint(sp);
220
221         DatabaseMetaData dmd = conn.getMetaData();
222         addClass(classes, dmd.getClass(), java.sql.DatabaseMetaData JavaDoc.class);
223
224         collectClassesFromStatement(conn, classes);
225         collectClassesFromPreparedStatement(conn, classes);
226         collectClassesFromCallableStatement(conn, classes);
227         conn.rollback();
228         conn.close();
229     }
230
231     /**
232      * Perform JDBC operations on a <code>Statement</code>. Collect
233      * the classes of all JDBC objects that are found.
234      *
235      * @param conn connection to a database
236      * @param classes set into which classes are collected
237      * @exception SQLException if a database error occurs
238      */

239     private static void
240         collectClassesFromStatement(Connection conn, Set JavaDoc<ClassInfo> classes)
241         throws SQLException
242     {
243         Statement stmt = conn.createStatement();
244         addClass(classes, stmt.getClass(), java.sql.Statement JavaDoc.class);
245
246         stmt.execute("CREATE TABLE t (id INT PRIMARY KEY, " +
247                      "b BLOB(10), c CLOB(10))");
248         stmt.execute("INSERT INTO t (id, b, c) VALUES (1, "+
249                      "CAST (" + TestUtil.stringToHexLiteral("101010001101") +
250                      "AS BLOB(10)), CAST ('hello' AS CLOB(10)))");
251
252         ResultSet rs = stmt.executeQuery("SELECT id, b, c FROM t");
253         addClass(classes, rs.getClass(), java.sql.ResultSet JavaDoc.class);
254         rs.next();
255         Blob b = rs.getBlob(2);
256         addClass(classes, b.getClass(), java.sql.Blob JavaDoc.class);
257         Clob c = rs.getClob(3);
258         addClass(classes, c.getClass(), java.sql.Clob JavaDoc.class);
259         ResultSetMetaData rsmd = rs.getMetaData();
260         addClass(classes, rsmd.getClass(), java.sql.ResultSetMetaData JavaDoc.class);
261         rs.close();
262
263         stmt.close();
264         conn.rollback();
265     }
266
267     /**
268      * Perform JDBC operations on a <code>PreparedStatement</code>.
269      * Collect the classes of all JDBC objects that are found.
270      *
271      * @param conn connection to a database
272      * @param classes set into which classes are collected
273      * @exception SQLException if a database error occurs
274      */

275     private static void
276         collectClassesFromPreparedStatement(Connection conn,
277                                             Set JavaDoc<ClassInfo> classes)
278         throws SQLException
279     {
280         PreparedStatement ps = conn.prepareStatement("VALUES(1)");
281         addClass(classes, ps.getClass(), java.sql.PreparedStatement JavaDoc.class);
282         ResultSet rs = ps.executeQuery();
283         addClass(classes, rs.getClass(), java.sql.ResultSet JavaDoc.class);
284         rs.close();
285
286         ParameterMetaData pmd = ps.getParameterMetaData();
287         addClass(classes, pmd.getClass(), java.sql.ParameterMetaData JavaDoc.class);
288
289         ps.close();
290     }
291
292     /**
293      * Perform JDBC operations on a <code>CallableStatement</code>.
294      * Collect the classes of all JDBC objects that are found.
295      *
296      * @param conn connection to a database
297      * @param classes set into which classes are collected
298      * @exception SQLException if a database error occurs
299      */

300     private static void
301         collectClassesFromCallableStatement(Connection conn,
302                                             Set JavaDoc<ClassInfo> classes)
303         throws SQLException
304     {
305         CallableStatement cs =
306             conn.prepareCall("CALL SYSCS_UTIL.SYSCS_SET_RUNTIMESTATISTICS(0)");
307         addClass(classes, cs.getClass(), java.sql.CallableStatement JavaDoc.class);
308
309         ParameterMetaData pmd = cs.getParameterMetaData();
310         addClass(classes, pmd.getClass(), java.sql.ParameterMetaData JavaDoc.class);
311
312         cs.close();
313     }
314
315     /**
316      * Adds a <code>ClassInfo</code> object to a set.
317      *
318      * @param classes set to which the class should be added
319      * @param implementation Derby implementation class
320      * @param iface JDBC interface supposed to be implemented
321      */

322     private static void addClass(Set JavaDoc<ClassInfo> classes,
323                                  Class JavaDoc implementation, Class JavaDoc iface) {
324         classes.add(new ClassInfo(implementation, iface));
325     }
326
327     /**
328      * Get the set consisting of an interface and all its
329      * super-interfaces.
330      *
331      * @param iface an interface
332      * @return the set consisting of <code>iface</code> and all its
333      * super-interfaces
334      */

335     private static Set JavaDoc<Class JavaDoc> getAllInterfaces(Class JavaDoc iface) {
336         Set JavaDoc<Class JavaDoc> set = new HashSet JavaDoc<Class JavaDoc>();
337         set.add(iface);
338         for (Class JavaDoc superIface : iface.getInterfaces()) {
339             set.add(superIface);
340             set.addAll(getAllInterfaces(superIface));
341         }
342         return set;
343     }
344
345     /**
346      * Test case which checks that a class implements a specific
347      * method.
348      */

349     private static class MethodTestCase extends TestCase {
350         /** The Derby implementation class which is tested. */
351         private final Class JavaDoc derbyImplementation;
352         /** The method that should be implemented. */
353         private final Method JavaDoc ifaceMethod;
354
355         /**
356          * Creates a new <code>MethodTestCase</code> instance.
357          *
358          * @param imp the class to test
359          * @param method the method to look for
360          */

361         private MethodTestCase(Class JavaDoc imp, Method JavaDoc method) {
362             super("MethodTestCase{Class=" + imp.getName() +
363                   ",Method=" + method + "}");
364             derbyImplementation = imp;
365             ifaceMethod = method;
366         }
367
368         /**
369          * Run the test. Check that the method is implemented and that
370          * its signature is correct.
371          *
372          * @exception NoSuchMethodException if the method is not found
373          */

374         public void runTest() throws NoSuchMethodException JavaDoc {
375             assertFalse("Implementation class is interface",
376                         derbyImplementation.isInterface());
377
378             Method JavaDoc impMethod =
379                 derbyImplementation.getMethod(ifaceMethod.getName(),
380                                               ifaceMethod.getParameterTypes());
381
382             assertEquals("Incorrect return type",
383                          ifaceMethod.getReturnType(),
384                          impMethod.getReturnType());
385
386             int modifiers = impMethod.getModifiers();
387             assertTrue("Non-public method", Modifier.isPublic(modifiers));
388             assertFalse("Abstract method", Modifier.isAbstract(modifiers));
389             assertFalse("Static method", Modifier.isStatic(modifiers));
390
391             Class JavaDoc[] declaredExceptions = ifaceMethod.getExceptionTypes();
392             for (Class JavaDoc exception : impMethod.getExceptionTypes()) {
393                 if (RuntimeException JavaDoc.class.isAssignableFrom(exception)) {
394                     continue;
395                 }
396                 assertNotNull("Incompatible throws clause",
397                               findCompatibleClass(exception,
398                                                   declaredExceptions));
399             }
400         }
401
402         /**
403          * Search an array of classes for a class that is identical to
404          * or a super-class of the specified exception class.
405          *
406          * @param exception an exception class
407          * @param declared an array of exception classes declared to
408          * be thrown by a method
409          * @return a class that is compatible with the specified
410          * exception class, or <code>null</code> if no compatible
411          * class is found
412          */

413         private Class JavaDoc findCompatibleClass(Class JavaDoc exception, Class JavaDoc[] declared)
414         {
415             for (Class JavaDoc<?> dec : declared) {
416                 if (dec.isAssignableFrom(exception)) {
417                     return dec;
418                 }
419             }
420             return null;
421         }
422     }
423
424     /**
425      * Test case which checks that all relevant JDBC interfaces are
426      * covered by the test.
427      */

428     private static class InterfaceCoverageTestCase extends TestCase {
429
430         /** The interfaces that have been tested by
431          * <code>MethodTestCase</code>. */

432         private final Set JavaDoc<Class JavaDoc> checkedInterfaces;
433         /** All JDBC interfaces whose implementations are relevant to
434          * test. */

435         private final Set JavaDoc<Class JavaDoc> jdbcInterfaces;
436
437         /**
438          * Creates a new <code>InterfaceCoverageTestCase</code> instance.
439          *
440          * @param interfaces the interfaces that have been tested
441          */

442         private InterfaceCoverageTestCase(Set JavaDoc<Class JavaDoc> interfaces) {
443             super("InterfaceCoverageTestCase");
444             checkedInterfaces = interfaces;
445             jdbcInterfaces = new HashSet JavaDoc<Class JavaDoc>(Arrays.asList(JDBC_INTERFACES));
446
447             // Remove the interfaces that we know we haven't checked.
448

449             // Interfaces that Derby doesn't implement:
450
jdbcInterfaces.remove(java.sql.Array JavaDoc.class);
451             jdbcInterfaces.remove(java.sql.NClob JavaDoc.class);
452             jdbcInterfaces.remove(java.sql.Ref JavaDoc.class);
453             jdbcInterfaces.remove(java.sql.SQLData JavaDoc.class);
454             jdbcInterfaces.remove(java.sql.SQLInput JavaDoc.class);
455             jdbcInterfaces.remove(java.sql.SQLOutput JavaDoc.class);
456             jdbcInterfaces.remove(java.sql.SQLXML JavaDoc.class);
457             jdbcInterfaces.remove(java.sql.Struct JavaDoc.class);
458             jdbcInterfaces.remove(javax.sql.RowSet JavaDoc.class);
459             jdbcInterfaces.remove(javax.sql.RowSetInternal JavaDoc.class);
460             jdbcInterfaces.remove(javax.sql.RowSetListener JavaDoc.class);
461             jdbcInterfaces.remove(javax.sql.RowSetMetaData JavaDoc.class);
462             jdbcInterfaces.remove(javax.sql.RowSetReader JavaDoc.class);
463             jdbcInterfaces.remove(javax.sql.RowSetWriter JavaDoc.class);
464
465             // Derby implements RowId classes, but has no way to
466
// obtain an object of that type.
467
jdbcInterfaces.remove(java.sql.RowId JavaDoc.class);
468
469             // The event listener interfaces are implemented in
470
// application code, not in Derby code.
471
jdbcInterfaces.remove(javax.sql.ConnectionEventListener JavaDoc.class);
472             jdbcInterfaces.remove(javax.sql.StatementEventListener JavaDoc.class);
473         }
474
475         /**
476          * Run the test. Check that all relevant interfaces have been
477          * tested.
478          */

479         public void runTest() {
480             jdbcInterfaces.removeAll(checkedInterfaces);
481             assertTrue("Unchecked interfaces: " + jdbcInterfaces,
482                        jdbcInterfaces.isEmpty());
483         }
484     }
485
486     /**
487      * Data structure holding a Derby implementation class and the
488      * JDBC interface it is supposed to implement.
489      */

490     private static class ClassInfo {
491         /** Derby implementation class. */
492         Class JavaDoc derbyImplementation;
493         /** JDBC interface which should be implemented. */
494         Class JavaDoc jdbcInterface;
495
496         /**
497          * Creates a new <code>ClassInfo</code> instance.
498          *
499          * @param imp the Derby implementation class
500          * @param iface the JDBC interface
501          */

502         ClassInfo(Class JavaDoc imp, Class JavaDoc iface) {
503             derbyImplementation = imp;
504             jdbcInterface = iface;
505         }
506
507         /**
508          * Checks whether this object is equal to another object.
509          *
510          * @param x another object
511          * @return <code>true</code> if the objects are equal,
512          * <code>false</code> otherwise
513          */

514         public boolean equals(Object JavaDoc x) {
515             if (x instanceof ClassInfo) {
516                 ClassInfo ci = (ClassInfo) x;
517                 return
518                     derbyImplementation.equals(ci.derbyImplementation) &&
519                     jdbcInterface.equals(ci.jdbcInterface);
520             }
521             return false;
522         }
523
524         /**
525          * Calculate hash code.
526          *
527          * @return hash code
528          */

529         public int hashCode() {
530             return derbyImplementation.hashCode() ^ jdbcInterface.hashCode();
531         }
532     }
533 }
534
Popular Tags