Bug #69038 Dynamic redirection of connection
Submitted: 23 Apr 2013 7:09 Modified: 20 Apr 2017 23:15
Reporter: Todd Farmer (OCA) Email Updates:
Status: Won't fix Impact on me:
None 
Category:Connector / J Severity:S4 (Feature request)
Version: OS:Any
Assigned to: Filipe Silva CPU Architecture:Any

[23 Apr 2013 7:09] Todd Farmer
Description:
Connector/Java supports connection lifetime interceptors, but the interception point for creation of new connections (init() method) is called after the connection is established (post-handshake).  Users who have external mapping in a sharded environment may need to look up the location using some external logic, and direct the connection to that location.  With the current interception hooks, this is not possible.

A viable workaround is to define a custom Driver ("com.mycompany.jdbc.Driver") which mirrors com.mysql.jdbc.Driver and extends com.mysql.jdbc.NonRegisteringDriver, overriding the connect() method to manipulate the URL and properties before delegating to super.connect():

public class Driver extends com.mysql.jdbc.NonRegisteringDriver {
 static {
  try {
   java.sql.DriverManager.registerDriver(new Driver());
  } catch (SQLException E) {
   throw new RuntimeException("Can't register driver!");
  }
 }

 public Driver() throws SQLException {
  // Required for Class.forName().newInstance()
 }

 @Override
 public Connection connect(String url, Properties info) throws SQLException {
  // Manipulate url and info here:
  return super.connect(url, info);
 }
}

How to repeat:
See above

Suggested fix:
Provide mechanism to intercept and manipulate connection properties (including URL) before a connection attempt is made.
[20 May 2015 18:18] Filipe Silva
Posted by developer:
 
Hi,

Connector/J provides the Connection property 'propertiesTransform' which allows to identify "An implementation of com.mysql.jdbc.ConnectionPropertiesTransform that the driver will use to modify URL properties passed to the driver before attempting a connection".

Any changes in the properties map, including host and port details, will affect next connection initialization. Does this work work for you?

Thank you,
[20 Apr 2017 16:27] Filipe Silva
Posted by developer:
 
Using the 'propertiesTransform' feature should be an alternative. Here's an example:

public class Bug69038 {
    public static void main(String[] args) throws Exception {
        Class.forName(Driver.class.getName());

        Connection conn = DriverManager.getConnection(
                "jdbc:mysql://fakehost:0000/fakedb?propertiesTransform=" + Bug69038HostAndDatabaseSelector.class.getName(), "user", "password");
        DatabaseMetaData dbmd = conn.getMetaData();
        System.out.println(dbmd.getDatabaseProductName() + " " + dbmd.getDatabaseProductVersion());
        conn.close();
    }

    public static class Bug69038HostAndDatabaseSelector implements ConnectionPropertiesTransform {
        @Override
        public Properties transformProperties(Properties props) throws SQLException {
            // Some logic to infer the host, port and database

            System.out.println("Original:");
            System.out.println("------------------------------");
            for (Object k : props.keySet()) {
                System.out.println(k + " --> " + props.getProperty((String) k));
            }

            props.setProperty("HOST", "localhost");
            props.setProperty("PORT", "5718");
            props.setProperty("DBNAME", "test");

            System.out.println("Changed:");
            System.out.println("------------------------------");
            for (Object k : props.keySet()) {
                System.out.println(k + " --> " + props.getProperty((String) k));
            }
            return props;
        }
    }
}

I hope that helps.