You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by cl...@apache.org on 2020/02/20 19:30:52 UTC

[activemq-artemis] branch master updated: [ARTEMIS-2626]: Postgresql Journal implementation requires direct access to PostgeSQL driver internal classes.

This is an automated email from the ASF dual-hosted git repository.

clebertsuconic pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/activemq-artemis.git


The following commit(s) were added to refs/heads/master by this push:
     new ac98cda  [ARTEMIS-2626]: Postgresql Journal implementation requires direct access to PostgeSQL driver internal classes.
     new d3efc24  This closes #2987
ac98cda is described below

commit ac98cda22451f0aaf6e70ded9aca4e234449b0b7
Author: Emmanuel Hugonnet <eh...@redhat.com>
AuthorDate: Thu Feb 20 19:01:38 2020 +0100

    [ARTEMIS-2626]: Postgresql Journal implementation requires direct access to PostgeSQL driver internal classes.
    
    Issue: The BLOB manipulation is done using PostgreSQL internal classes starting from PGConnection.
    This leads to ClasCastExceptions if the connection is wrapped in a pool or if the driver is in a different classloader (WildFly).
    
    Fix: unwrap the connection and if the PostgreSQL classes are not directly available uses reflection to manipulate the BLOBs.
    
    Jira: https://issues.apache.org/jira/browse/ARTEMIS-2626
---
 .../store/file/PostgresLargeObjectManager.java     | 209 ++++++++++++
 .../PostgresSequentialSequentialFileDriver.java    |  46 ++-
 .../file/JDBCSequentialFileFactoryTest.java        |   4 +-
 .../store/file/PostgresLargeObjectManagerTest.java | 362 +++++++++++++++++++++
 4 files changed, 592 insertions(+), 29 deletions(-)

diff --git a/artemis-jdbc-store/src/main/java/org/apache/activemq/artemis/jdbc/store/file/PostgresLargeObjectManager.java b/artemis-jdbc-store/src/main/java/org/apache/activemq/artemis/jdbc/store/file/PostgresLargeObjectManager.java
new file mode 100644
index 0000000..3167c54
--- /dev/null
+++ b/artemis-jdbc-store/src/main/java/org/apache/activemq/artemis/jdbc/store/file/PostgresLargeObjectManager.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2019 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq.artemis.jdbc.store.file;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.sql.Connection;
+import java.sql.SQLException;
+import org.postgresql.PGConnection;
+import org.postgresql.largeobject.LargeObject;
+
+/**
+ * Helper class for when the postresql driver is not directly availalbe.
+ */
+public class PostgresLargeObjectManager {
+
+   /**
+    * This mode indicates we want to write to an object
+    */
+   public static final int WRITE = 0x00020000;
+
+   /**
+    * This mode indicates we want to read an object
+    */
+   public static final int READ = 0x00040000;
+
+   /**
+    * This mode is the default. It indicates we want read and write access to
+    * a large object
+    */
+   public static final int READWRITE = READ | WRITE;
+
+   private final Connection realConnection;
+   private boolean shouldUseReflection;
+
+   public PostgresLargeObjectManager(Connection connection) throws SQLException {
+      this.realConnection = unwrap(connection);
+      try {
+         this.getClass().getClassLoader().loadClass("org.postgresql.PGConnection");
+         shouldUseReflection = false;
+      } catch (ClassNotFoundException ex) {
+         shouldUseReflection = true;
+      }
+   }
+
+   public final Long createLO() throws SQLException {
+      if (shouldUseReflection) {
+         Object largeObjectManager = getLargeObjectManager();
+         try {
+            Method method = largeObjectManager.getClass().getMethod("createLO");
+            return (Long) method.invoke(largeObjectManager);
+         } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
+            throw new SQLException("Couldn't access org.postgresql.largeobject.LargeObjectManager", ex);
+         }
+      } else {
+         return ((PGConnection) realConnection).getLargeObjectAPI().createLO();
+      }
+   }
+
+   public Object open(long oid, int mode) throws SQLException {
+      if (shouldUseReflection) {
+         Object largeObjectManager = getLargeObjectManager();
+         try {
+            Method method = largeObjectManager.getClass().getMethod("open", long.class, int.class);
+            return method.invoke(largeObjectManager, oid, mode);
+         } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
+            throw new SQLException("Couldn't access org.postgresql.largeobject.LargeObjectManager", ex);
+         }
+      } else {
+         return ((PGConnection) realConnection).getLargeObjectAPI().open(oid, mode);
+      }
+   }
+
+   public int size(Object largeObject) throws SQLException {
+      if (shouldUseReflection) {
+         try {
+            Method method = largeObject.getClass().getMethod("size");
+            return (int) method.invoke(largeObject);
+         } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
+            throw new SQLException("Couldn't access org.postgresql.largeobject.LargeObject", ex);
+         }
+      } else {
+         return ((LargeObject) largeObject).size();
+      }
+   }
+
+   public void close(Object largeObject) throws SQLException {
+      if (shouldUseReflection) {
+         try {
+            Method method = largeObject.getClass().getMethod("close");
+            method.invoke(largeObject);
+         } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
+            throw new SQLException("Couldn't access org.postgresql.largeobject.LargeObject", ex);
+         }
+      } else {
+         ((LargeObject) largeObject).close();
+      }
+   }
+
+   public byte[] read(Object largeObject, int length) throws SQLException {
+      if (shouldUseReflection) {
+         try {
+            Method method = largeObject.getClass().getMethod("read", int.class);
+            return (byte[]) method.invoke(largeObject, length);
+         } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
+            throw new SQLException("Couldn't access org.postgresql.largeobject.LargeObject", ex);
+         }
+      } else {
+         return ((LargeObject) largeObject).read(length);
+      }
+   }
+
+   public void write(Object largeObject, byte[] data) throws SQLException {
+      if (shouldUseReflection) {
+         try {
+            Method method = largeObject.getClass().getMethod("write", byte[].class);
+            method.invoke(largeObject, data);
+         } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
+            throw new SQLException("Couldn't access org.postgresql.largeobject.LargeObject", ex);
+         }
+      } else {
+         ((LargeObject) largeObject).write(data);
+      }
+   }
+
+   public void seek(Object largeObject, int position) throws SQLException {
+      if (shouldUseReflection) {
+         try {
+            Method method = largeObject.getClass().getMethod("seek", Integer.class);
+            method.invoke(largeObject, position);
+         } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
+            throw new SQLException("Couldn't access org.postgresql.largeobject.LargeObject", ex);
+         }
+      } else {
+         ((LargeObject) largeObject).seek(position);
+      }
+   }
+
+   public void truncate(Object largeObject, int position) throws SQLException {
+      if (shouldUseReflection) {
+         try {
+            Method method = largeObject.getClass().getMethod("truncate", Integer.class);
+            method.invoke(largeObject, position);
+         } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
+            throw new SQLException("Couldn't access org.postgresql.largeobject.LargeObject", ex);
+         }
+      } else {
+         ((LargeObject) largeObject).truncate(position);
+      }
+   }
+
+   private Object getLargeObjectManager() throws SQLException {
+      if (shouldUseReflection) {
+         try {
+            Method method = realConnection.getClass().getMethod("getLargeObjectAPI");
+            return method.invoke(realConnection);
+         } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
+            throw new SQLException("Couldn't access org.postgresql.largeobject.LargeObjectManager", ex);
+         }
+      } else {
+         return ((PGConnection) realConnection).getLargeObjectAPI();
+      }
+   }
+
+   public final Connection unwrap(Connection connection) throws SQLException {
+      Connection conn = connection.unwrap(Connection.class);
+      return unwrapIronJacamar(unwrapDbcp(unwrapSpring(conn)));
+   }
+
+   private Connection unwrapIronJacamar(Connection conn) {
+      try {
+         Method method = conn.getClass().getMethod("getUnderlyingConnection");
+         return (Connection) method.invoke(conn);
+      } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
+         return conn;
+      }
+   }
+
+   private Connection unwrapDbcp(Connection conn) {
+      try {
+         Method method = conn.getClass().getMethod("getDelegate");
+         return (Connection) method.invoke(conn);
+      } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
+         return conn;
+      }
+   }
+
+   private Connection unwrapSpring(Connection conn) {
+      try {
+         Method method = conn.getClass().getMethod("getTargetConnection");
+         return (Connection) method.invoke(conn);
+      } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
+         return conn;
+      }
+   }
+}
diff --git a/artemis-jdbc-store/src/main/java/org/apache/activemq/artemis/jdbc/store/file/PostgresSequentialSequentialFileDriver.java b/artemis-jdbc-store/src/main/java/org/apache/activemq/artemis/jdbc/store/file/PostgresSequentialSequentialFileDriver.java
index 3c68781..7d439da 100644
--- a/artemis-jdbc-store/src/main/java/org/apache/activemq/artemis/jdbc/store/file/PostgresSequentialSequentialFileDriver.java
+++ b/artemis-jdbc-store/src/main/java/org/apache/activemq/artemis/jdbc/store/file/PostgresSequentialSequentialFileDriver.java
@@ -23,9 +23,6 @@ import java.sql.SQLException;
 import java.sql.Statement;
 
 import org.apache.activemq.artemis.jdbc.store.sql.SQLProvider;
-import org.postgresql.PGConnection;
-import org.postgresql.largeobject.LargeObject;
-import org.postgresql.largeobject.LargeObjectManager;
 
 import javax.sql.DataSource;
 
@@ -33,6 +30,7 @@ import javax.sql.DataSource;
 public final class PostgresSequentialSequentialFileDriver extends JDBCSequentialFileFactoryDriver {
 
    private static final String POSTGRES_OID_KEY = "POSTGRES_OID_KEY";
+   private PostgresLargeObjectManager largeObjectManager;
 
    public PostgresSequentialSequentialFileDriver() throws SQLException {
       super();
@@ -52,6 +50,7 @@ public final class PostgresSequentialSequentialFileDriver extends JDBCSequential
 
    @Override
    protected void prepareStatements() throws SQLException {
+      this.largeObjectManager = new PostgresLargeObjectManager(connection);
       this.deleteFile = connection.prepareStatement(sqlProvider.getDeleteFileSQL());
       this.createFile = connection.prepareStatement(sqlProvider.getInsertFileSQL(), Statement.RETURN_GENERATED_KEYS);
       this.selectFileByFileName = connection.prepareStatement(sqlProvider.getSelectFileByFileName());
@@ -67,9 +66,7 @@ public final class PostgresSequentialSequentialFileDriver extends JDBCSequential
       synchronized (connection) {
          try {
             connection.setAutoCommit(false);
-
-            LargeObjectManager lobjManager = ((PGConnection) connection).getLargeObjectAPI();
-            long oid = lobjManager.createLO();
+            Long oid = largeObjectManager.createLO();
 
             createFile.setString(1, file.getFileName());
             createFile.setString(2, file.getExtension());
@@ -109,20 +106,19 @@ public final class PostgresSequentialSequentialFileDriver extends JDBCSequential
    @Override
    public int writeToFile(JDBCSequentialFile file, byte[] data, boolean append) throws SQLException {
       synchronized (connection) {
-         LargeObjectManager lobjManager = ((PGConnection) connection).getLargeObjectAPI();
-         LargeObject largeObject = null;
+         Object largeObject = null;
 
          Long oid = getOID(file);
          try {
             connection.setAutoCommit(false);
-            largeObject = lobjManager.open(oid, LargeObjectManager.WRITE);
+            largeObject = largeObjectManager.open(oid, PostgresLargeObjectManager.WRITE);
             if (append) {
-               largeObject.seek(largeObject.size());
+               largeObjectManager.seek(largeObject, largeObjectManager.size(largeObject));
             } else {
-               largeObject.truncate(0);
+               largeObjectManager.truncate(largeObject, 0);
             }
-            largeObject.write(data);
-            largeObject.close();
+            largeObjectManager.write(largeObject, data);
+            largeObjectManager.close(largeObject);
             connection.commit();
          } catch (Exception e) {
             connection.rollback();
@@ -134,23 +130,23 @@ public final class PostgresSequentialSequentialFileDriver extends JDBCSequential
 
    @Override
    public int readFromFile(JDBCSequentialFile file, ByteBuffer bytes) throws SQLException {
-      LargeObjectManager lobjManager = ((PGConnection) connection).getLargeObjectAPI();
-      LargeObject largeObject = null;
+      Object largeObject = null;
       long oid = getOID(file);
       synchronized (connection) {
          try {
             connection.setAutoCommit(false);
-            largeObject = lobjManager.open(oid, LargeObjectManager.READ);
-            int readLength = (int) calculateReadLength(largeObject.size(), bytes.remaining(), file.position());
+            largeObject = largeObjectManager.open(oid, PostgresLargeObjectManager.READ);
+            int readLength = (int) calculateReadLength(largeObjectManager.size(largeObject), bytes.remaining(), file.position());
 
             if (readLength > 0) {
-               if (file.position() > 0)
-                  largeObject.seek((int) file.position());
-               byte[] data = largeObject.read(readLength);
+               if (file.position() > 0) {
+                  largeObjectManager.seek(largeObject, (int) file.position());
+               }
+               byte[] data = largeObjectManager.read(largeObject, readLength);
                bytes.put(data);
             }
 
-            largeObject.close();
+            largeObjectManager.close(largeObject);
             connection.commit();
 
             return readLength;
@@ -185,17 +181,15 @@ public final class PostgresSequentialSequentialFileDriver extends JDBCSequential
    }
 
    private int getPostGresLargeObjectSize(JDBCSequentialFile file) throws SQLException {
-      LargeObjectManager lobjManager = ((PGConnection) connection).getLargeObjectAPI();
-
       int size = 0;
       Long oid = getOID(file);
       if (oid != null) {
          synchronized (connection) {
             try {
                connection.setAutoCommit(false);
-               LargeObject largeObject = lobjManager.open(oid, LargeObjectManager.READ);
-               size = largeObject.size();
-               largeObject.close();
+               Object largeObject = largeObjectManager.open(oid, PostgresLargeObjectManager.READ);
+               size = largeObjectManager.size(largeObject);
+               largeObjectManager.close(largeObject);
                connection.commit();
             } catch (SQLException e) {
                connection.rollback();
diff --git a/artemis-jdbc-store/src/test/java/org/apache/activemq/artemis/jdbc/file/JDBCSequentialFileFactoryTest.java b/artemis-jdbc-store/src/test/java/org/apache/activemq/artemis/jdbc/store/file/JDBCSequentialFileFactoryTest.java
similarity index 98%
rename from artemis-jdbc-store/src/test/java/org/apache/activemq/artemis/jdbc/file/JDBCSequentialFileFactoryTest.java
rename to artemis-jdbc-store/src/test/java/org/apache/activemq/artemis/jdbc/store/file/JDBCSequentialFileFactoryTest.java
index d74a76c..fef665c 100644
--- a/artemis-jdbc-store/src/test/java/org/apache/activemq/artemis/jdbc/file/JDBCSequentialFileFactoryTest.java
+++ b/artemis-jdbc-store/src/test/java/org/apache/activemq/artemis/jdbc/store/file/JDBCSequentialFileFactoryTest.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.activemq.artemis.jdbc.file;
+package org.apache.activemq.artemis.jdbc.store.file;
 
 import java.nio.ByteBuffer;
 import java.sql.DriverManager;
@@ -37,8 +37,6 @@ import org.apache.activemq.artemis.core.io.IOCallback;
 import org.apache.activemq.artemis.core.io.IOCriticalErrorListener;
 import org.apache.activemq.artemis.core.io.SequentialFile;
 import org.apache.activemq.artemis.jdbc.store.drivers.JDBCUtils;
-import org.apache.activemq.artemis.jdbc.store.file.JDBCSequentialFile;
-import org.apache.activemq.artemis.jdbc.store.file.JDBCSequentialFileFactory;
 import org.apache.activemq.artemis.jdbc.store.sql.SQLProvider;
 import org.apache.activemq.artemis.utils.ActiveMQThreadFactory;
 import org.apache.activemq.artemis.utils.ThreadLeakCheckRule;
diff --git a/artemis-jdbc-store/src/test/java/org/apache/activemq/artemis/jdbc/store/file/PostgresLargeObjectManagerTest.java b/artemis-jdbc-store/src/test/java/org/apache/activemq/artemis/jdbc/store/file/PostgresLargeObjectManagerTest.java
new file mode 100644
index 0000000..886ce10
--- /dev/null
+++ b/artemis-jdbc-store/src/test/java/org/apache/activemq/artemis/jdbc/store/file/PostgresLargeObjectManagerTest.java
@@ -0,0 +1,362 @@
+/*
+ * Copyright 2020 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq.artemis.jdbc.store.file;
+
+import java.lang.reflect.InvocationTargetException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.CallableStatement;
+import java.sql.Clob;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.NClob;
+import java.sql.PreparedStatement;
+import java.sql.SQLClientInfoException;
+import java.sql.SQLException;
+import java.sql.SQLWarning;
+import java.sql.SQLXML;
+import java.sql.Savepoint;
+import java.sql.Statement;
+import java.sql.Struct;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.Executor;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import org.junit.Test;
+
+public class PostgresLargeObjectManagerTest {
+
+   @Test
+   public void testShouldNotUseReflection() throws SQLException {
+      PostgresLargeObjectManager manager = new PostgresLargeObjectManager(new MockConnection());
+      try {
+         manager.createLO();
+         fail("Shouldn't be using reflection");
+      } catch (ClassCastException ex) {
+      }
+   }
+
+   @Test
+   public void testShouldUseReflection() throws SQLException, ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
+      ClassLoader loader = new FunkyClassLoader();
+      Class funkyClass = loader.loadClass("org.apache.activemq.artemis.jdbc.store.file.PostgresLargeObjectManager");
+      Object manager = funkyClass.getConstructor(Connection.class).newInstance(new MockConnection());
+      try {
+         funkyClass.getMethod("createLO").invoke(manager);
+         fail("Shouldn't be using reflection");
+      } catch (java.lang.reflect.InvocationTargetException ex) {
+         assertEquals("Couldn't access org.postgresql.largeobject.LargeObjectManager", ex.getCause().getMessage());
+      }
+   }
+
+   private static final class FunkyClassLoader extends URLClassLoader {
+
+      private FunkyClassLoader() {
+         super(new URL[]{
+            FunkyClassLoader.class.getProtectionDomain().getCodeSource().getLocation(),
+            PostgresLargeObjectManager.class.getProtectionDomain().getCodeSource().getLocation()
+         },
+              ClassLoader.getSystemClassLoader());
+      }
+
+      @Override
+      public Class<?> loadClass(String name) throws ClassNotFoundException {
+         if ("org.postgresql.PGConnection".equals(name)) {
+            throw new ClassNotFoundException(name);
+         }
+         if ("org.apache.activemq.artemis.jdbc.store.file.PostgresLargeObjectManager".equals(name)) {
+            return this.findClass(name);
+         }
+         return super.loadClass(name);
+      }
+   }
+
+   private static final class MockConnection implements Connection {
+
+      @Override
+      public Statement createStatement() throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public PreparedStatement prepareStatement(String sql) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public CallableStatement prepareCall(String sql) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public String nativeSQL(String sql) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public void setAutoCommit(boolean autoCommit) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public boolean getAutoCommit() throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public void commit() throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public void rollback() throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public void close() throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public boolean isClosed() throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public DatabaseMetaData getMetaData() throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public void setReadOnly(boolean readOnly) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public boolean isReadOnly() throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public void setCatalog(String catalog) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public String getCatalog() throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public void setTransactionIsolation(int level) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public int getTransactionIsolation() throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public SQLWarning getWarnings() throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public void clearWarnings() throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public Map<String, Class<?>> getTypeMap() throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public void setHoldability(int holdability) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public int getHoldability() throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public Savepoint setSavepoint() throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public Savepoint setSavepoint(String name) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public void rollback(Savepoint savepoint) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public void releaseSavepoint(Savepoint savepoint) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public Clob createClob() throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public Blob createBlob() throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public NClob createNClob() throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public SQLXML createSQLXML() throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public boolean isValid(int timeout) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public void setClientInfo(String name, String value) throws SQLClientInfoException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public void setClientInfo(Properties properties) throws SQLClientInfoException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public String getClientInfo(String name) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public Properties getClientInfo() throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public void setSchema(String schema) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public String getSchema() throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public void abort(Executor executor) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public int getNetworkTimeout() throws SQLException {
+         throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+      }
+
+      @Override
+      public <T> T unwrap(Class<T> iface) throws SQLException {
+         return (T) this;
+      }
+
+      @Override
+      public boolean isWrapperFor(Class<?> iface) throws SQLException {
+         return false;
+      }
+   }
+}