001 package org.sonar.jpa.session; 002 003 import org.apache.commons.configuration.Configuration; 004 import org.apache.commons.lang.StringUtils; 005 import org.sonar.api.database.DatabaseProperties; 006 007 import java.sql.Connection; 008 import java.sql.Driver; 009 import java.sql.DriverManager; 010 import java.sql.SQLException; 011 import java.util.Properties; 012 013 public class DriverDatabaseConnector extends AbstractDatabaseConnector { 014 015 private ClassLoader classloader; 016 017 public DriverDatabaseConnector(Configuration configuration) { 018 super(configuration, true); 019 this.classloader = getClass().getClassLoader(); 020 } 021 022 public DriverDatabaseConnector(Configuration configuration, ClassLoader classloader) { 023 super(configuration, true); 024 this.classloader = classloader; 025 } 026 027 public String getDriver() { 028 String driver = getConfiguration().getString(DatabaseProperties.PROP_DRIVER); 029 if (driver == null) { 030 driver = getConfiguration().getString(DatabaseProperties.PROP_DRIVER_DEPRECATED); 031 } 032 if (driver == null) { 033 driver = DatabaseProperties.PROP_DRIVER_DEFAULT_VALUE; 034 } 035 return driver; 036 } 037 038 public String getUrl() { 039 return getConfiguration().getString(DatabaseProperties.PROP_URL, DatabaseProperties.PROP_URL_DEFAULT_VALUE); 040 } 041 042 public String getUsername() { 043 String username = getConfiguration().getString(DatabaseProperties.PROP_USER); 044 if (username == null) { 045 username = getConfiguration().getString(DatabaseProperties.PROP_USER_DEPRECATED); 046 } 047 if (username == null) { 048 username = DatabaseProperties.PROP_USER_DEFAULT_VALUE; 049 } 050 return username; 051 } 052 053 public String getPassword() { 054 return getConfiguration().getString(DatabaseProperties.PROP_PASSWORD, DatabaseProperties.PROP_PASSWORD_DEFAULT_VALUE); 055 } 056 057 public Connection getConnection() throws SQLException { 058 try { 059 /* 060 The sonar batch downloads the JDBC driver in a separated classloader. 061 This is a well-know problem of java.sql.DriverManager. The workaround 062 is to use a proxy. 063 See http://stackoverflow.com/questions/288828/how-to-use-a-jdbc-driver-from-an-arbitrary-location 064 */ 065 Driver driver = (Driver)classloader.loadClass(getDriver()).newInstance(); 066 DriverManager.registerDriver(new DriverProxy(driver)); 067 068 } catch (Exception e) { 069 SQLException ex = new SQLException("SQL driver not found " + getDriver()); 070 ex.initCause(e); 071 throw ex; 072 } 073 return DriverManager.getConnection(getUrl(), getUsername(), getPassword()); 074 } 075 076 @Override 077 public void setupEntityManagerFactory(Properties factoryProps) { 078 factoryProps.put("hibernate.connection.url", getUrl()); 079 factoryProps.put("hibernate.connection.driver_class", getDriver()); 080 factoryProps.put("hibernate.connection.username", getUsername()); 081 if (StringUtils.isNotEmpty(getPassword())) { 082 factoryProps.put("hibernate.connection.password", getPassword()); 083 } 084 } 085 } 086 087 /** 088 * A Driver that stands in for another Driver. 089 * This is necessary because java.sql.DriverManager 090 * examines the Driver class class loader. 091 */ 092 final class DriverProxy implements Driver { 093 private final Driver target; 094 095 DriverProxy(Driver target) { 096 if (target == null) { 097 throw new NullPointerException(); 098 } 099 this.target = target; 100 } 101 102 public Driver getTarget() { 103 return target; 104 } 105 106 public boolean acceptsURL(String url) throws SQLException { 107 return target.acceptsURL(url); 108 } 109 110 public Connection connect( 111 String url, Properties info 112 ) throws SQLException { 113 return target.connect(url, info); 114 } 115 116 public int getMajorVersion() { 117 return target.getMajorVersion(); 118 } 119 120 public int getMinorVersion() { 121 return target.getMinorVersion(); 122 } 123 124 public java.sql.DriverPropertyInfo[] getPropertyInfo( 125 String url, Properties info 126 ) throws SQLException { 127 return target.getPropertyInfo(url, info); 128 } 129 130 public boolean jdbcCompliant() { 131 return target.jdbcCompliant(); 132 } 133 134 @Override 135 public String toString() { 136 return "Proxy: " + target; 137 } 138 139 @Override 140 public int hashCode() { 141 return target.hashCode(); 142 } 143 144 @Override 145 public boolean equals(Object obj) { 146 if (!(obj instanceof org.sonar.jpa.session.DriverProxy)) { 147 return false; 148 } 149 org.sonar.jpa.session.DriverProxy other = (org.sonar.jpa.session.DriverProxy) obj; 150 return this.target.equals(other.target); 151 } 152 }