1
16 package com.zaxxer.hikari.util;
17
18 import java.io.PrintWriter;
19 import java.sql.Connection;
20 import java.sql.Driver;
21 import java.sql.DriverManager;
22 import java.sql.SQLException;
23 import java.sql.SQLFeatureNotSupportedException;
24 import java.util.Enumeration;
25 import java.util.Map.Entry;
26 import java.util.Properties;
27
28 import javax.sql.DataSource;
29
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 public final class DriverDataSource implements DataSource
34 {
35 private static final Logger LOGGER = LoggerFactory.getLogger(DriverDataSource.class);
36 private static final String PASSWORD = "password";
37 private static final String USER = "user";
38
39 private final String jdbcUrl;
40 private final Properties driverProperties;
41 private Driver driver;
42
43 public DriverDataSource(String jdbcUrl, String driverClassName, Properties properties, String username, String password)
44 {
45 this.jdbcUrl = jdbcUrl;
46 this.driverProperties = new Properties();
47
48 for (Entry<Object, Object> entry : properties.entrySet()) {
49 driverProperties.setProperty(entry.getKey().toString(), entry.getValue().toString());
50 }
51
52 if (username != null) {
53 driverProperties.put(USER, driverProperties.getProperty("user", username));
54 }
55 if (password != null) {
56 driverProperties.put(PASSWORD, driverProperties.getProperty("password", password));
57 }
58
59 if (driverClassName != null) {
60 Enumeration<Driver> drivers = DriverManager.getDrivers();
61 while (drivers.hasMoreElements()) {
62 Driver d = drivers.nextElement();
63 if (d.getClass().getName().equals(driverClassName)) {
64 driver = d;
65 break;
66 }
67 }
68
69 if (driver == null) {
70 LOGGER.warn("Registered driver with driverClassName={} was not found, trying direct instantiation.", driverClassName);
71 Class<?> driverClass = null;
72 ClassLoader threadContextClassLoader = Thread.currentThread().getContextClassLoader();
73 try {
74 if (threadContextClassLoader != null) {
75 try {
76 driverClass = threadContextClassLoader.loadClass(driverClassName);
77 LOGGER.debug("Driver class {} found in Thread context class loader {}", driverClassName, threadContextClassLoader);
78 }
79 catch (ClassNotFoundException e) {
80 LOGGER.debug("Driver class {} not found in Thread context class loader {}, trying classloader {}",
81 driverClassName, threadContextClassLoader, this.getClass().getClassLoader());
82 }
83 }
84
85 if (driverClass == null) {
86 driverClass = this.getClass().getClassLoader().loadClass(driverClassName);
87 LOGGER.debug("Driver class {} found in the HikariConfig class classloader {}", driverClassName, this.getClass().getClassLoader());
88 }
89 } catch (ClassNotFoundException e) {
90 LOGGER.debug("Failed to load driver class {} from HikariConfig class classloader {}", driverClassName, this.getClass().getClassLoader());
91 }
92
93 if (driverClass != null) {
94 try {
95 driver = (Driver) driverClass.newInstance();
96 } catch (Exception e) {
97 LOGGER.warn("Failed to create instance of driver class {}, trying jdbcUrl resolution", driverClassName, e);
98 }
99 }
100 }
101 }
102
103 final String sanitizedUrl = jdbcUrl.replaceAll("([?&;]password=)[^&#;]*(.*)", "$1<masked>$2");
104 try {
105 if (driver == null) {
106 driver = DriverManager.getDriver(jdbcUrl);
107 LOGGER.debug("Loaded driver with class name {} for jdbcUrl={}", driver.getClass().getName(), sanitizedUrl);
108 }
109 else if (!driver.acceptsURL(jdbcUrl)) {
110 throw new RuntimeException("Driver " + driverClassName + " claims to not accept jdbcUrl, " + sanitizedUrl);
111 }
112 }
113 catch (SQLException e) {
114 throw new RuntimeException("Failed to get driver instance for jdbcUrl=" + sanitizedUrl, e);
115 }
116 }
117
118 @Override
119 public Connection getConnection() throws SQLException
120 {
121 return driver.connect(jdbcUrl, driverProperties);
122 }
123
124 @Override
125 public Connection getConnection(final String username, final String password) throws SQLException
126 {
127 final Properties cloned = (Properties) driverProperties.clone();
128 if (username != null) {
129 cloned.put("user", username);
130 if (cloned.containsKey("username")) {
131 cloned.put("username", username);
132 }
133 }
134 if (password != null) {
135 cloned.put("password", password);
136 }
137
138 return driver.connect(jdbcUrl, cloned);
139 }
140
141 @Override
142 public PrintWriter getLogWriter() throws SQLException
143 {
144 throw new SQLFeatureNotSupportedException();
145 }
146
147 @Override
148 public void setLogWriter(PrintWriter logWriter) throws SQLException
149 {
150 throw new SQLFeatureNotSupportedException();
151 }
152
153 @Override
154 public void setLoginTimeout(int seconds) throws SQLException
155 {
156 DriverManager.setLoginTimeout(seconds);
157 }
158
159 @Override
160 public int getLoginTimeout() throws SQLException
161 {
162 return DriverManager.getLoginTimeout();
163 }
164
165 @Override
166 public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException
167 {
168 return driver.getParentLogger();
169 }
170
171 @Override
172 public <T> T unwrap(Class<T> iface) throws SQLException
173 {
174 throw new SQLFeatureNotSupportedException();
175 }
176
177 @Override
178 public boolean isWrapperFor(Class<?> iface) throws SQLException
179 {
180 return false;
181 }
182 }
183