UnpooledDataSource.java

  1. /*
  2.  *    Copyright 2009-2024 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. import org.apache.ibatis.util.MapUtil;

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

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

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

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

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

  54.   public UnpooledDataSource() {
  55.   }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  194.   private void initializeDriver() throws SQLException {
  195.     try {
  196.       MapUtil.computeIfAbsent(registeredDrivers, driver, x -> {
  197.         Class<?> driverType;
  198.         try {
  199.           if (driverClassLoader != null) {
  200.             driverType = Class.forName(x, true, driverClassLoader);
  201.           } else {
  202.             driverType = Resources.classForName(x);
  203.           }
  204.           Driver driverInstance = (Driver) driverType.getDeclaredConstructor().newInstance();
  205.           DriverManager.registerDriver(new DriverProxy(driverInstance));
  206.           return driverInstance;
  207.         } catch (Exception e) {
  208.           throw new RuntimeException("Error setting driver on UnpooledDataSource.", e);
  209.         }
  210.       });
  211.     } catch (RuntimeException re) {
  212.       throw new SQLException("Error setting driver on UnpooledDataSource.", re.getCause());
  213.     }
  214.   }

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

  226.   private static class DriverProxy implements Driver {
  227.     private final Driver driver;

  228.     DriverProxy(Driver d) {
  229.       this.driver = d;
  230.     }

  231.     @Override
  232.     public boolean acceptsURL(String u) throws SQLException {
  233.       return this.driver.acceptsURL(u);
  234.     }

  235.     @Override
  236.     public Connection connect(String u, Properties p) throws SQLException {
  237.       return this.driver.connect(u, p);
  238.     }

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

  243.     @Override
  244.     public int getMinorVersion() {
  245.       return this.driver.getMinorVersion();
  246.     }

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

  251.     @Override
  252.     public boolean jdbcCompliant() {
  253.       return this.driver.jdbcCompliant();
  254.     }

  255.     @Override
  256.     public Logger getParentLogger() {
  257.       return Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
  258.     }
  259.   }

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

  264.   @Override
  265.   public boolean isWrapperFor(Class<?> iface) throws SQLException {
  266.     return false;
  267.   }

  268.   @Override
  269.   public Logger getParentLogger() {
  270.     // requires JDK version 1.6
  271.     return Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
  272.   }

  273. }