Changeset: 8e57d20b5e80 for monetdb-java
URL: http://dev.monetdb.org/hg/monetdb-java?cmd=changeset;node=8e57d20b5e80
Added Files:
        tests/Test_Wrapper.java
Modified Files:
        ChangeLog
        src/main/java/nl/cwi/monetdb/jdbc/MonetWrapper.java
        tests/build.xml
Branch: default
Log Message:

Corrected implementation of java.sql.Wrapper methods isWrapperFor() and 
unwrap().
They now properly return expected results instead of always return false or 
throw an SQLException.
Added test program Test_Wrapper.java


diffs (276 lines):

diff --git a/ChangeLog b/ChangeLog
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,11 @@
 # ChangeLog file for java
 # This file is updated with Maddlog
 
+* Thu Oct 13 2016 Martin van Dinther <martin.van.dint...@monetdbsolutions.com>
+- Corrected implementation of java.sql.Wrapper methods isWrapperFor()
+  and unwrap().  They now properly return expected results instead of
+  always return false or throw an SQLException.
+
 * Thu Oct  6 2016 Martin van Dinther <martin.van.dint...@monetdbsolutions.com>
 - Corrected return values of DatabaseMetaData methods nullsAreSortedHigh(),
   nullsAreSortedLow(), getMaxCursorNameLength(), getMaxProcedureNameLength(),
diff --git a/src/main/java/nl/cwi/monetdb/jdbc/MonetWrapper.java 
b/src/main/java/nl/cwi/monetdb/jdbc/MonetWrapper.java
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetWrapper.java
+++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetWrapper.java
@@ -8,66 +8,71 @@
 
 package nl.cwi.monetdb.jdbc;
 
-import java.sql.*;
+import java.sql.SQLException;
 
 /**
- * A Wrapper class that implements nothing.
- * 
- * This Class is used to simply provide JDBC4 Wrapper functions, for as
- * long as we don't really understand that they are for and what they
- * are supposed to do.  Hence the implementations are very stupid and
- * non-useful, ignoring any argument and claiming stuff doesn't work, or
- * won't work out.
+ * A Wrapper class which provide the ability to retrieve the delegate instance
+ * when the instance in question is in fact a proxy class.
  *
- * @author Fabian Groffen
- * @version 1.0
+ * The wrapper pattern is employed by many JDBC driver implementations to 
provide
+ * extensions beyond the traditional JDBC API that are specific to a data 
source.
+ * Developers may wish to gain access to these resources that are wrapped (the 
delegates)
+ * as proxy class instances representing the the actual resources.
+ * This class contains a standard mechanism to access these wrapped resources
+ * represented by their proxy, to permit direct access to the resource 
delegates.
+ *
+ * @author Fabian Groffen, Martin van Dinther
+ * @version 1.1
  */
-public class MonetWrapper implements Wrapper {
+public class MonetWrapper implements java.sql.Wrapper {
        /**
         * Returns true if this either implements the interface argument or
         * is directly or indirectly a wrapper for an object that does.
         * Returns false otherwise. If this implements the interface then
         * return true, else if this is a wrapper then return the result of
-        * recursively calling isWrapperFor on the wrapped object. If this
-        * does not implement the interface and is not a wrapper, return
+        * recursively calling <code>isWrapperFor</code> on the wrapped object.
+        * If this does not implement the interface and is not a wrapper, return
         * false. This method should be implemented as a low-cost operation
-        * compared to unwrap so that callers can use this method to avoid
-        * expensive unwrap calls that may fail. If this method returns true
-        * then calling unwrap with the same argument should succeed.
+        * compared to <code>unwrap</code> so that callers can use this method 
to avoid
+        * expensive <code>unwrap</code> calls that may fail.
+        * If this method returns true then calling <code>unwrap</code> with 
the same argument should succeed.
         *
         * @param iface a Class defining an interface.
-        * @return true if this implements the interface or directly or
-        *         indirectly wraps an object that does.
-        * @throws SQLException if an error occurs while determining
-        *         whether this is a wrapper for an object with the given
-        *         interface.
+        * @return true if this implements the interface or directly or 
indirectly wraps an object that does.
+        * @throws SQLException if an error occurs while determining whether 
this is a wrapper
+        *      for an object with the given interface.
+        * @since 1.6
         */
        @Override
        public boolean isWrapperFor(Class<?> iface) throws SQLException {
-               return false;
+               return iface != null && iface.isAssignableFrom(getClass());
        }
 
        /**
         * Returns an object that implements the given interface to allow
-        * access to non-standard methods, or standard methods not exposed
-        * by the proxy. If the receiver implements the interface then the
-        * result is the receiver or a proxy for the receiver. If the
-        * receiver is a wrapper and the wrapped object implements the
-        * interface then the result is the wrapped object or a proxy for
-        * the wrapped object. Otherwise return the the result of calling
-        * unwrap recursively on the wrapped object or a proxy for that
-        * result. If the receiver is not a wrapper and does not implement
-        * the interface, then an SQLException is thrown.
+        * access to non-standard methods, or standard methods not exposed by 
the proxy.
+        * The result may be either the object found to implement the interface
+        * or a proxy for that object.
+        * If the receiver implements the interface then the result is the 
receiver
+        * or a proxy for the receiver.
+        * If the receiver is a wrapper and the wrapped object implements the 
interface
+        * then the result is the wrapped object or a proxy for the wrapped 
object.
+        * Otherwise return the result of calling <code>unwrap</code> 
recursively on
+        * the wrapped object or a proxy for that result.
+        * If the receiver is not a wrapper and does not implement the 
interface,
+        * then an <code>SQLException</code> is thrown.
         *
-        * @param iface A Class defining an interface that the result must
-        *        implement.
-        * @return an object that implements the interface. May be a proxy
-        *         for the actual implementing object.
-        * @throws SQLException If no object found that implements the
-        *         interface
+        * @param iface A Class defining an interface that the result must 
implement.
+        * @return an object that implements the interface. May be a proxy for 
the actual implementing object.
+        * @throws SQLException If no object found that implements the interface
+        * @since 1.6
         */
        @Override
+       @SuppressWarnings("unchecked")
        public <T> T unwrap(Class<T> iface) throws SQLException {
-               throw new SQLException("No object found (not implemented)", 
"0A000");
+               if (isWrapperFor(iface)) {
+                       return (T) this;
+               }
+               throw new SQLException("Cannot unwrap to interface: " + (iface 
!= null ? iface.getName() : ""), "0A000");
        }
 }
diff --git a/tests/Test_Wrapper.java b/tests/Test_Wrapper.java
new file mode 100644
--- /dev/null
+++ b/tests/Test_Wrapper.java
@@ -0,0 +1,102 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0.  If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V.
+ */
+
+import java.sql.*;
+
+public class Test_Wrapper {
+       public static void main(String[] args) throws Exception {
+               // Class.forName("nl.cwi.monetdb.jdbc.MonetDriver");
+               final Connection con = DriverManager.getConnection(args[0]);
+               System.out.println("Connected. Auto commit is: " + 
con.getAutoCommit());
+
+               try {
+                       final String jdbc_pkg = "java.sql.";
+                       final String monetdb_jdbc_pkg = "nl.cwi.monetdb.jdbc.";
+
+                       checkIsWrapperFor("Connection", con, jdbc_pkg, 
"Connection");
+                       checkIsWrapperFor("Connection", con, monetdb_jdbc_pkg, 
"MonetConnection");
+                       checkIsWrapperFor("Connection", con, jdbc_pkg, 
"Statement");
+                       checkIsWrapperFor("Connection", con, monetdb_jdbc_pkg, 
"MonetStatement");
+
+                       DatabaseMetaData dbmd = con.getMetaData();
+                       checkIsWrapperFor("DatabaseMetaData", dbmd, jdbc_pkg, 
"DatabaseMetaData");
+                       checkIsWrapperFor("DatabaseMetaData", dbmd, 
monetdb_jdbc_pkg, "MonetDatabaseMetaData");
+                       checkIsWrapperFor("DatabaseMetaData", dbmd, jdbc_pkg, 
"Statement");
+                       checkIsWrapperFor("DatabaseMetaData", dbmd, 
monetdb_jdbc_pkg, "MonetStatement");
+
+                       ResultSet rs = dbmd.getSchemas();
+                       checkIsWrapperFor("ResultSet", rs, jdbc_pkg, 
"ResultSet");
+                       checkIsWrapperFor("ResultSet", rs, monetdb_jdbc_pkg, 
"MonetResultSet");
+                       checkIsWrapperFor("ResultSet", rs, jdbc_pkg, 
"Statement");
+                       checkIsWrapperFor("ResultSet", rs, monetdb_jdbc_pkg, 
"MonetStatement");
+
+                       ResultSetMetaData rsmd = rs.getMetaData();
+                       checkIsWrapperFor("ResultSetMetaData", rsmd, jdbc_pkg, 
"ResultSetMetaData");
+                       checkIsWrapperFor("ResultSetMetaData", rsmd, 
monetdb_jdbc_pkg, "MonetResultSet");
+                       checkIsWrapperFor("ResultSetMetaData", rsmd, 
monetdb_jdbc_pkg, "MonetResultSet$rsmdw");  // it is a private class of 
MonetResultSet
+                       checkIsWrapperFor("ResultSetMetaData", rsmd, jdbc_pkg, 
"Statement");
+                       checkIsWrapperFor("ResultSetMetaData", rsmd, 
monetdb_jdbc_pkg, "MonetStatement");
+
+                       rs.close();
+
+                       Statement stmt = con.createStatement();
+                       checkIsWrapperFor("Statement", stmt, jdbc_pkg, 
"Statement");
+                       checkIsWrapperFor("Statement", stmt, monetdb_jdbc_pkg, 
"MonetStatement");
+                       checkIsWrapperFor("Statement", stmt, jdbc_pkg, 
"Connection");
+                       checkIsWrapperFor("Statement", stmt, monetdb_jdbc_pkg, 
"MonetConnection");
+
+                       stmt.close();
+
+                       PreparedStatement pstmt = con.prepareStatement("SELECT 
name FROM sys.tables WHERE system AND name like ?");
+                       checkIsWrapperFor("PreparedStatement", pstmt, jdbc_pkg, 
"PreparedStatement");
+                       checkIsWrapperFor("PreparedStatement", pstmt, 
monetdb_jdbc_pkg, "MonetPreparedStatement");
+                       checkIsWrapperFor("PreparedStatement", pstmt, jdbc_pkg, 
"Statement");
+                       checkIsWrapperFor("PreparedStatement", pstmt, 
monetdb_jdbc_pkg, "MonetStatement");
+                       checkIsWrapperFor("PreparedStatement", pstmt, jdbc_pkg, 
"Connection");
+                       checkIsWrapperFor("PreparedStatement", pstmt, 
monetdb_jdbc_pkg, "MonetConnection");
+
+                       ParameterMetaData pmd = pstmt.getParameterMetaData();
+                       checkIsWrapperFor("ParameterMetaData", pmd, jdbc_pkg, 
"ParameterMetaData");
+                       checkIsWrapperFor("ParameterMetaData", pmd, 
monetdb_jdbc_pkg, "MonetPreparedStatement");
+                       checkIsWrapperFor("ParameterMetaData", pmd, 
monetdb_jdbc_pkg, "MonetPreparedStatement$pmdw");  // it is a private class of 
MonetPreparedStatement
+                       checkIsWrapperFor("ParameterMetaData", pmd, jdbc_pkg, 
"Connection");
+                       checkIsWrapperFor("ParameterMetaData", pmd, 
monetdb_jdbc_pkg, "MonetConnection");
+
+                       ResultSetMetaData psrsmd = pstmt.getMetaData();
+                       checkIsWrapperFor("PrepStmt ResultSetMetaData", psrsmd, 
jdbc_pkg, "ResultSetMetaData");
+                       checkIsWrapperFor("PrepStmt ResultSetMetaData", psrsmd, 
monetdb_jdbc_pkg, "MonetPreparedStatement");
+                       checkIsWrapperFor("PrepStmt ResultSetMetaData", psrsmd, 
monetdb_jdbc_pkg, "MonetPreparedStatement$rsmdw");  // it is a private class of 
MonetPreparedStatement
+                       checkIsWrapperFor("PrepStmt ResultSetMetaData", psrsmd, 
jdbc_pkg, "Connection");
+                       checkIsWrapperFor("PrepStmt ResultSetMetaData", psrsmd, 
monetdb_jdbc_pkg, "MonetConnection");
+
+                       pstmt.close();
+
+               } catch (SQLException e) {
+                       while ((e = e.getNextException()) != null)
+                               System.out.println("FAILED :( " + 
e.getMessage());
+               }
+               con.close();
+       }
+
+       private static void checkIsWrapperFor(String objnm, Wrapper obj, String 
pkgnm, String classnm) {
+               try {
+                       Class<?> clazz = Class.forName(pkgnm + classnm);
+                       boolean isWrapper = obj.isWrapperFor(clazz);
+                       System.out.print(objnm + ". isWrapperFor(" + classnm + 
") returns: " + isWrapper);
+                       if (isWrapper) {
+                               Object wobj = obj.unwrap(clazz);
+                               System.out.print("\tCalled unwrap(). Returned 
object is " + (wobj != null ? "not null, so oke" : "null !!"));
+                       }
+                       System.out.println();
+               } catch (ClassNotFoundException cnfe) {
+                       System.out.println(cnfe.toString());
+               } catch (SQLException se) {
+                       System.out.println(se.getMessage());
+               }
+       }
+}
diff --git a/tests/build.xml b/tests/build.xml
--- a/tests/build.xml
+++ b/tests/build.xml
@@ -125,6 +125,7 @@ Copyright 1997 - July 2008 CWI, August 2
     <antcall target="Test_Smoreresults" />
     <antcall target="Test_Int128" />
     <antcall target="Test_FetchSize" />
+    <antcall target="Test_Wrapper" />
     <antcall target="BugConcurrent_clients_SF_1504657" />
     <antcall target="BugConcurrent_sequences" />
     <antcall target="BugDatabaseMetaData_Bug_3356" />
@@ -142,7 +143,6 @@ Copyright 1997 - July 2008 CWI, August 2
       <arg value="${jdbc_url}" />
     </java>
   </target>
-  
 
   <!-- convenience targets for the outside caller to specify which
   test(s) should be run -->
@@ -319,13 +319,19 @@ Copyright 1997 - July 2008 CWI, August 2
       <param name="test.class" value="Test_Int128" />
     </antcall>
   </target>
-  
+
   <target name="Test_FetchSize">
     <antcall target="test_class">
       <param name="test.class" value="Test_FetchSize" />
     </antcall>
   </target>
-  
+
+  <target name="Test_Wrapper">
+    <antcall target="test_class">
+      <param name="test.class" value="Test_Wrapper" />
+    </antcall>
+  </target>
+
   <target name="BugConcurrent_clients_SF_1504657">
     <antcall target="test_class">
       <param name="test.class" value="BugConcurrent_clients_SF_1504657" />
_______________________________________________
checkin-list mailing list
checkin-list@monetdb.org
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to