
com.github.tomitakussaari.mysqlcluscon.MysclusconDriver Maven / Gradle / Ivy
The newest version!
package com.github.tomitakussaari.mysqlcluscon;
import com.github.tomitakussaari.mysqlcluscon.galera.GaleraClusterConnectionChecker;
import com.github.tomitakussaari.mysqlcluscon.read_cluster.ReadClusterConnectionChecker;
import java.lang.reflect.Proxy;
import java.net.URL;
import java.sql.*;
import java.util.*;
import java.util.logging.Logger;
public class MysclusconDriver implements Driver {
static final Logger LOGGER = Logger.getLogger(MysclusconDriver.class.getName());
static {
try {
DriverManager.registerDriver(new MysclusconDriver());
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public static final String mysqlReadClusterConnectorName = "jdbc:myscluscon:mysql:read_cluster";
public static final String galeraClusterConnectorName = "jdbc:myscluscon:galera:cluster";
@Override
public Connection connect(String jdbcUrl, Properties info) throws SQLException {
if(acceptsURL(jdbcUrl)) {
final Map> queryParameters = URLHelpers.getQueryParameters(jdbcUrl);
final ConnectionChecker connectionChecker = chooseConnectionChecker(jdbcUrl, queryParameters);
return createProxyConnection(connectionChecker, createActualConnection(jdbcUrl, connectionChecker, info));
} else {
return null;
}
}
@Override
public boolean acceptsURL(String url) throws SQLException {
return url.startsWith(mysqlReadClusterConnectorName) || url.startsWith(galeraClusterConnectorName);
}
@Override
public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {
return new DriverPropertyInfo[0];
}
@Override
public int getMajorVersion() {
return 1;
}
@Override
public int getMinorVersion() {
return 0;
}
@Override
public boolean jdbcCompliant() {
return false;
}
@Override
public Logger getParentLogger() {
return LOGGER;
}
private Connection createActualConnection(String jdbcUrl, ConnectionChecker connectionChecker, Properties info) throws SQLException {
final List hosts = URLHelpers.getHosts(jdbcUrl);
return tryToOpenConnectionToValidHost(hosts, connectionChecker, info, jdbcUrl)
.orElseThrow(() -> new SQLException("Unable to open connection, no valid host found from hosts: "+hosts));
}
private Optional tryToOpenConnectionToValidHost(List hosts, ConnectionChecker connectionChecker, Properties info, String jdbcUrl) throws SQLException {
LOGGER.fine("Trying to connect to hosts " + hosts + " from url " + jdbcUrl);
final List copyOfHosts = new ArrayList<>(hosts);
Collections.shuffle(copyOfHosts);
for (String host : copyOfHosts) {
Optional conn = tryConnectingToHost(host, connectionChecker, jdbcUrl, info);
if (conn.isPresent()) {
return conn;
}
}
return Optional.empty();
}
private Optional tryConnectingToHost(String host, ConnectionChecker connectionChecker, String jdbcUrl, Properties info) throws SQLException {
LOGGER.fine("Trying to connect to host " + host);
final URL originalUrl = URLHelpers.createConvertedUrl(jdbcUrl);
final String connectUrl = URLHelpers.constructMysqlConnectUrl(originalUrl, host);
Connection connection = null;
try {
LOGGER.fine("Connecting to " + connectUrl);
connection = openRealConnection(info, connectUrl);
if(connectionChecker.connectionOk(connection)) {
return Optional.of(connection);
} else {
connection.close();
}
} catch(Exception e) {
LOGGER.fine("Error while verifying connection " + connectUrl + " " + e.getMessage());
if(connection != null) {connection.close();}
}
return Optional.empty();
}
protected Connection openRealConnection(Properties info, String connectUrl) throws SQLException {
return DriverManager.getConnection(connectUrl, info);
}
private ConnectionChecker chooseConnectionChecker(String jdbcUrl, Map> queryParameters) {
String protocol = URLHelpers.getProtocol(jdbcUrl);
LOGGER.fine("Parsed Protocol: " + protocol + " from url" + jdbcUrl);
switch (protocol) {
case mysqlReadClusterConnectorName: return new ReadClusterConnectionChecker(queryParameters);
case galeraClusterConnectorName: return new GaleraClusterConnectionChecker();
default: throw new UnsupportedOperationException("Unsupported protocol: "+protocol);
}
}
protected Connection createProxyConnection(final ConnectionChecker connectionChecker, Connection actualConnection) {
return (Connection) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{Connection.class}, (proxy, method, args) -> {
if(method.getName().equals("isValid")) {
return connectionChecker.connectionOk(actualConnection);
}
return method.invoke(actualConnection, args);
});
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy