Skip to content

Commit 971c8a7

Browse files
committed
Merge pull request #1574 from nlivens/mysql_driver_issue
Make sure that the DB drivers are loaded before creating connectionsI've digged deeper, and found out that Tomcat is really specific in how it loads the JDBC drivers apparently. If we would be using the standard JDBC connection pooling of Tomcat (tomcat-jdbc) instead of commons-dbcp, we would have the option to specify a "driverClassName" when creating our connection. This is not the case for commons-dbcp, which we are using within ACS. If you check an official example of Tomcat : https://tomcat.apache.org/tomcat-7.0-doc/jdbc-pool.html#Plain_Ol'_Java or https://tomcat.apache.org/tomcat-7.0-doc/jdbc-pool.html#As_a_Resource As you can see in the above examples, both of them specify the driverClassName. In the underlying implementation of Tomcat, Tomcat will do ```Class.forName(driverClassName)``` which will trigger the auto-registration of the Driver. Tomcat code : ```java if (driver==null) { if (log.isDebugEnabled()) { log.debug("Instantiating driver using class: "+poolProperties.getDriverClassName()+" [url="+poolProperties.getUrl()+"]"); } driver = (java.sql.Driver) Class.forName(poolProperties.getDriverClassName(), true, PooledConnection.class.getClassLoader() ).newInstance(); } ``` * pr/1574: Make sure that the DB drivers are loaded before initiating connections Signed-off-by: Will Stevens <williamstevens@gmail.com>
2 parents bb9148b + c956749 commit 971c8a7

2 files changed

Lines changed: 72 additions & 15 deletions

File tree

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package com.cloud.utils.db;
18+
19+
import com.cloud.utils.exception.CloudRuntimeException;
20+
import org.apache.log4j.Logger;
21+
22+
import java.util.ArrayList;
23+
import java.util.HashMap;
24+
import java.util.List;
25+
import java.util.Map;
26+
27+
public class DriverLoader {
28+
29+
private static final Logger LOGGER = Logger.getLogger(DriverLoader.class.getName());
30+
private static final List<String> LOADED_DRIVERS;
31+
private static final Map<String, String> DRIVERS;
32+
33+
static {
34+
DRIVERS = new HashMap<String, String>();
35+
DRIVERS.put("jdbc:mysql", "com.mysql.jdbc.Driver");
36+
DRIVERS.put("jdbc:postgresql", "org.postgresql.Driver");
37+
DRIVERS.put("jdbc:h2", "org.h2.Driver");
38+
39+
LOADED_DRIVERS = new ArrayList<String>();
40+
}
41+
42+
43+
public static void loadDriver(String dbDriver) {
44+
String driverClass = DRIVERS.get(dbDriver);
45+
if (driverClass == null) {
46+
LOGGER.error("DB driver type " + dbDriver + " is not supported!");
47+
throw new CloudRuntimeException("DB driver type " + dbDriver + " is not supported!");
48+
}
49+
50+
if (LOADED_DRIVERS.contains(dbDriver)) {
51+
if (LOGGER.isDebugEnabled()) {
52+
LOGGER.debug("DB driver " + driverClass + " was already loaded.");
53+
}
54+
return;
55+
}
56+
57+
try {
58+
Class.forName(driverClass).newInstance();
59+
LOADED_DRIVERS.add(dbDriver);
60+
if (LOGGER.isDebugEnabled()) {
61+
LOGGER.debug("Successfully loaded DB driver " + driverClass);
62+
}
63+
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
64+
LOGGER.error("Failed to load DB driver " + driverClass);
65+
throw new CloudRuntimeException("Failed to load DB driver " + driverClass, e);
66+
}
67+
}
68+
69+
}

framework/db/src/com/cloud/utils/db/TransactionLegacy.java

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@
2020
import java.io.File;
2121
import java.io.IOException;
2222
import java.sql.Connection;
23-
import java.sql.Driver;
24-
import java.sql.DriverManager;
2523
import java.sql.PreparedStatement;
2624
import java.sql.ResultSet;
2725
import java.sql.SQLException;
@@ -1078,7 +1076,7 @@ public static void initDataSource(Properties dbProps) {
10781076
final String cloudConnectionUri = cloudDriver + "://" + cloudHost + (s_dbHAEnabled ? "," + cloudSlaves : "") + ":" + cloudPort + "/" + cloudDbName +
10791077
"?autoReconnect=" + cloudAutoReconnect + (url != null ? "&" + url : "") + (useSSL ? "&useSSL=true" : "") +
10801078
(s_dbHAEnabled ? "&" + cloudDbHAParams : "") + (s_dbHAEnabled ? "&loadBalanceStrategy=" + loadBalanceStrategy : "");
1081-
loadDbDriver(cloudConnectionUri);
1079+
DriverLoader.loadDriver(cloudDriver);
10821080

10831081
final ConnectionFactory cloudConnectionFactory = new DriverManagerConnectionFactory(cloudConnectionUri, cloudUsername, cloudPassword);
10841082

@@ -1109,7 +1107,7 @@ public static void initDataSource(Properties dbProps) {
11091107
final String usageConnectionUri = usageDriver + "://" + usageHost + (s_dbHAEnabled ? "," + dbProps.getProperty("db.cloud.slaves") : "") + ":" + usagePort +
11101108
"/" + usageDbName + "?autoReconnect=" + usageAutoReconnect + (usageUrl != null ? "&" + usageUrl : "") +
11111109
(s_dbHAEnabled ? "&" + getDBHAParams("usage", dbProps) : "") + (s_dbHAEnabled ? "&loadBalanceStrategy=" + loadBalanceStrategy : "");
1112-
loadDbDriver(usageConnectionUri);
1110+
DriverLoader.loadDriver(usageDriver);
11131111

11141112
final ConnectionFactory usageConnectionFactory = new DriverManagerConnectionFactory(usageConnectionUri, usageUsername, usagePassword);
11151113

@@ -1137,7 +1135,7 @@ public static void initDataSource(Properties dbProps) {
11371135

11381136
final String simulatorConnectionUri = simulatorDriver + "://" + simulatorHost + ":" + simulatorPort + "/" + simulatorDbName + "?autoReconnect=" +
11391137
simulatorAutoReconnect;
1140-
loadDbDriver(simulatorConnectionUri);
1138+
DriverLoader.loadDriver(simulatorDriver);
11411139

11421140
final ConnectionFactory simulatorConnectionFactory = new DriverManagerConnectionFactory(simulatorConnectionUri, simulatorUsername, simulatorPassword);
11431141

@@ -1157,16 +1155,6 @@ public static void initDataSource(Properties dbProps) {
11571155
}
11581156
}
11591157

1160-
private static void loadDbDriver(String dbConnectionUri) {
1161-
try {
1162-
Driver driver = DriverManager.getDriver(dbConnectionUri);
1163-
s_logger.debug("Successfully loaded DB driver " + driver.getClass().getName() + " for connection " + dbConnectionUri);
1164-
} catch (SQLException e) {
1165-
s_logger.error("Failed to load DB driver for connection " + dbConnectionUri, e);
1166-
throw new CloudRuntimeException("Failed to load DB driver for connection " + dbConnectionUri, e);
1167-
}
1168-
}
1169-
11701158
private static String getDBHAParams(String dbName, Properties dbProps) {
11711159
StringBuilder sb = new StringBuilder();
11721160
sb.append("failOverReadOnly=" + dbProps.getProperty("db." + dbName + ".failOverReadOnly"));

0 commit comments

Comments
 (0)