UnpooledDataSource.java

  1. /*
  2.  *    Copyright 2009-2023 the original author or authors.
  3.  *
  4.  *    Licensed under the Apache License, Version 2.0 (the "License");
  5.  *    you may not use this file except in compliance with the License.
  6.  *    You may obtain a copy of the License at
  7.  *
  8.  *       https://www.apache.org/licenses/LICENSE-2.0
  9.  *
  10.  *    Unless required by applicable law or agreed to in writing, software
  11.  *    distributed under the License is distributed on an "AS IS" BASIS,
  12.  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  *    See the License for the specific language governing permissions and
  14.  *    limitations under the License.
  15.  */
  16. package org.apache.ibatis.datasource.unpooled;

  17. import java.io.PrintWriter;
  18. import java.sql.Connection;
  19. import java.sql.Driver;
  20. import java.sql.DriverManager;
  21. import java.sql.DriverPropertyInfo;
  22. import java.sql.SQLException;
  23. import java.util.Enumeration;
  24. import java.util.Map;
  25. import java.util.Properties;
  26. import java.util.concurrent.ConcurrentHashMap;
  27. import java.util.concurrent.Executors;
  28. import java.util.logging.Logger;

  29. import javax.sql.DataSource;

  30. import org.apache.ibatis.io.Resources;

  31. /**
  32.  * @author Clinton Begin
  33.  * @author Eduardo Macarron
  34.  */
  35. public class UnpooledDataSource implements DataSource {

  36.   private ClassLoader driverClassLoader;
  37.   private Properties driverProperties;
  38.   private static final Map<String, Driver> registeredDrivers = new ConcurrentHashMap<>();

  39.   private String driver;
  40.   private String url;
  41.   private String username;
  42.   private String password;

  43.   private Boolean autoCommit;
  44.   private Integer defaultTransactionIsolationLevel;
  45.   private Integer defaultNetworkTimeout;

  46.   static {
  47.     Enumeration<Driver> drivers = DriverManager.getDrivers();
  48.     while (drivers.hasMoreElements()) {
  49.       Driver driver = drivers.nextElement();
  50.       registeredDrivers.put(driver.getClass().getName(), driver);
  51.     }
  52.   }

  53.   public UnpooledDataSource() {
  54.   }

  55.   public UnpooledDataSource(String driver, String url, String username, String password) {
  56.     this.driver = driver;
  57.     this.url = url;
  58.     this.username = username;
  59.     this.password = password;
  60.   }

  61.   public UnpooledDataSource(String driver, String url, Properties driverProperties) {
  62.     this.driver = driver;
  63.     this.url = url;
  64.     this.driverProperties = driverProperties;
  65.   }

  66.   public UnpooledDataSource(ClassLoader driverClassLoader, String driver, String url, String username,
  67.       String password) {
  68.     this.driverClassLoader = driverClassLoader;
  69.     this.driver = driver;
  70.     this.url = url;
  71.     this.username = username;
  72.     this.password = password;
  73.   }

  74.   public UnpooledDataSource(ClassLoader driverClassLoader, String driver, String url, Properties driverProperties) {
  75.     this.driverClassLoader = driverClassLoader;
  76.     this.driver = driver;
  77.     this.url = url;
  78.     this.driverProperties = driverProperties;
  79.   }

  80.   @Override
  81.   public Connection getConnection() throws SQLException {
  82.     return doGetConnection(username, password);
  83.   }

  84.   @Override
  85.   public Connection getConnection(String username, String password) throws SQLException {
  86.     return doGetConnection(username, password);
  87.   }

  88.   @Override
  89.   public void setLoginTimeout(int loginTimeout) {
  90.     DriverManager.setLoginTimeout(loginTimeout);
  91.   }

  92.   @Override
  93.   public int getLoginTimeout() {
  94.     return DriverManager.getLoginTimeout();
  95.   }

  96.   @Override
  97.   public void setLogWriter(PrintWriter logWriter) {
  98.     DriverManager.setLogWriter(logWriter);
  99.   }

  100.   @Override
  101.   public PrintWriter getLogWriter() {
  102.     return DriverManager.getLogWriter();
  103.   }

  104.   public ClassLoader getDriverClassLoader() {
  105.     return driverClassLoader;
  106.   }

  107.   public void setDriverClassLoader(ClassLoader driverClassLoader) {
  108.     this.driverClassLoader = driverClassLoader;
  109.   }

  110.   public Properties getDriverProperties() {
  111.     return driverProperties;
  112.   }

  113.   public void setDriverProperties(Properties driverProperties) {
  114.     this.driverProperties = driverProperties;
  115.   }

  116.   public synchronized String getDriver() {
  117.     return driver;
  118.   }

  119.   public synchronized void setDriver(String driver) {
  120.     this.driver = driver;
  121.   }

  122.   public String getUrl() {
  123.     return url;
  124.   }

  125.   public void setUrl(String url) {
  126.     this.url = url;
  127.   }

  128.   public String getUsername() {
  129.     return username;
  130.   }

  131.   public void setUsername(String username) {
  132.     this.username = username;
  133.   }

  134.   public String getPassword() {
  135.     return password;
  136.   }

  137.   public void setPassword(String password) {
  138.     this.password = password;
  139.   }

  140.   public Boolean isAutoCommit() {
  141.     return autoCommit;
  142.   }

  143.   public void setAutoCommit(Boolean autoCommit) {
  144.     this.autoCommit = autoCommit;
  145.   }

  146.   public Integer getDefaultTransactionIsolationLevel() {
  147.     return defaultTransactionIsolationLevel;
  148.   }

  149.   public void setDefaultTransactionIsolationLevel(Integer defaultTransactionIsolationLevel) {
  150.     this.defaultTransactionIsolationLevel = defaultTransactionIsolationLevel;
  151.   }

  152.   /**
  153.    * Gets the default network timeout.
  154.    *
  155.    * @return the default network timeout
  156.    *
  157.    * @since 3.5.2
  158.    */
  159.   public Integer getDefaultNetworkTimeout() {
  160.     return defaultNetworkTimeout;
  161.   }

  162.   /**
  163.    * Sets the default network timeout value to wait for the database operation to complete. See
  164.    * {@link Connection#setNetworkTimeout(java.util.concurrent.Executor, int)}
  165.    *
  166.    * @param defaultNetworkTimeout
  167.    *          The time in milliseconds to wait for the database operation to complete.
  168.    *
  169.    * @since 3.5.2
  170.    */
  171.   public void setDefaultNetworkTimeout(Integer defaultNetworkTimeout) {
  172.     this.defaultNetworkTimeout = defaultNetworkTimeout;
  173.   }

  174.   private Connection doGetConnection(String username, String password) throws SQLException {
  175.     Properties props = new Properties();
  176.     if (driverProperties != null) {
  177.       props.putAll(driverProperties);
  178.     }
  179.     if (username != null) {
  180.       props.setProperty("user", username);
  181.     }
  182.     if (password != null) {
  183.       props.setProperty("password", password);
  184.     }
  185.     return doGetConnection(props);
  186.   }

  187.   private Connection doGetConnection(Properties properties) throws SQLException {
  188.     initializeDriver();
  189.     Connection connection = DriverManager.getConnection(url, properties);
  190.     configureConnection(connection);
  191.     return connection;
  192.   }

  193.   private synchronized void initializeDriver() throws SQLException {
  194.     if (!registeredDrivers.containsKey(driver)) {
  195.       Class<?> driverType;
  196.       try {
  197.         if (driverClassLoader != null) {
  198.           driverType = Class.forName(driver, true, driverClassLoader);
  199.         } else {
  200.           driverType = Resources.classForName(driver);
  201.         }
  202.         // DriverManager requires the driver to be loaded via the system ClassLoader.
  203.         // https://www.kfu.com/~nsayer/Java/dyn-jdbc.html
  204.         Driver driverInstance = (Driver) driverType.getDeclaredConstructor().newInstance();
  205.         DriverManager.registerDriver(new DriverProxy(driverInstance));
  206.         registeredDrivers.put(driver, driverInstance);
  207.       } catch (Exception e) {
  208.         throw new SQLException("Error setting driver on UnpooledDataSource. Cause: " + e);
  209.       }
  210.     }
  211.   }

  212.   private void configureConnection(Connection conn) throws SQLException {
  213.     if (defaultNetworkTimeout != null) {
  214.       conn.setNetworkTimeout(Executors.newSingleThreadExecutor(), defaultNetworkTimeout);
  215.     }
  216.     if (autoCommit != null && autoCommit != conn.getAutoCommit()) {
  217.       conn.setAutoCommit(autoCommit);
  218.     }
  219.     if (defaultTransactionIsolationLevel != null) {
  220.       conn.setTransactionIsolation(defaultTransactionIsolationLevel);
  221.     }
  222.   }

  223.   private static class DriverProxy implements Driver {
  224.     private final Driver driver;

  225.     DriverProxy(Driver d) {
  226.       this.driver = d;
  227.     }

  228.     @Override
  229.     public boolean acceptsURL(String u) throws SQLException {
  230.       return this.driver.acceptsURL(u);
  231.     }

  232.     @Override
  233.     public Connection connect(String u, Properties p) throws SQLException {
  234.       return this.driver.connect(u, p);
  235.     }

  236.     @Override
  237.     public int getMajorVersion() {
  238.       return this.driver.getMajorVersion();
  239.     }

  240.     @Override
  241.     public int getMinorVersion() {
  242.       return this.driver.getMinorVersion();
  243.     }

  244.     @Override
  245.     public DriverPropertyInfo[] getPropertyInfo(String u, Properties p) throws SQLException {
  246.       return this.driver.getPropertyInfo(u, p);
  247.     }

  248.     @Override
  249.     public boolean jdbcCompliant() {
  250.       return this.driver.jdbcCompliant();
  251.     }

  252.     @Override
  253.     public Logger getParentLogger() {
  254.       return Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
  255.     }
  256.   }

  257.   @Override
  258.   public <T> T unwrap(Class<T> iface) throws SQLException {
  259.     throw new SQLException(getClass().getName() + " is not a wrapper.");
  260.   }

  261.   @Override
  262.   public boolean isWrapperFor(Class<?> iface) throws SQLException {
  263.     return false;
  264.   }

  265.   @Override
  266.   public Logger getParentLogger() {
  267.     // requires JDK version 1.6
  268.     return Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
  269.   }

  270. }