001 /*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2009 SonarSource SA
004 * mailto:contact AT sonarsource DOT com
005 *
006 * Sonar is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * Sonar is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public
017 * License along with Sonar; if not, write to the Free Software
018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
019 */
020 package org.sonar.api.database;
021
022 import org.apache.commons.configuration.Configuration;
023 import org.apache.commons.lang.StringUtils;
024
025 import java.sql.Connection;
026 import java.sql.Driver;
027 import java.sql.DriverManager;
028 import java.sql.SQLException;
029 import java.util.Properties;
030
031 public class DriverDatabaseConnector extends AbstractDatabaseConnector {
032
033 private ClassLoader classloader;
034
035 public DriverDatabaseConnector(Configuration configuration) {
036 super(configuration, true);
037 this.classloader = getClass().getClassLoader();
038 }
039
040 public DriverDatabaseConnector(Configuration configuration, ClassLoader classloader) {
041 super(configuration, true);
042 this.classloader = classloader;
043 }
044
045 public String getDriver() {
046 String driver = getConfiguration().getString(DatabaseProperties.PROP_DRIVER);
047 if (driver == null) {
048 driver = getConfiguration().getString(DatabaseProperties.PROP_DRIVER_DEPRECATED);
049 }
050 if (driver == null) {
051 driver = DatabaseProperties.PROP_DRIVER_DEFAULT_VALUE;
052 }
053 return driver;
054 }
055
056 public String getUrl() {
057 return getConfiguration().getString(DatabaseProperties.PROP_URL, DatabaseProperties.PROP_URL_DEFAULT_VALUE);
058 }
059
060 public String getUsername() {
061 String username = getConfiguration().getString(DatabaseProperties.PROP_USER);
062 if (username == null) {
063 username = getConfiguration().getString(DatabaseProperties.PROP_USER_DEPRECATED);
064 }
065 if (username == null) {
066 username = DatabaseProperties.PROP_USER_DEFAULT_VALUE;
067 }
068 return username;
069 }
070
071 public String getPassword() {
072 return getConfiguration().getString(DatabaseProperties.PROP_PASSWORD, DatabaseProperties.PROP_PASSWORD_DEFAULT_VALUE);
073 }
074
075 public Connection getConnection() throws SQLException {
076 try {
077 /*
078 The sonar batch downloads the JDBC driver in a separated classloader.
079 This is a well-know problem of java.sql.DriverManager. The workaround
080 is to use a proxy.
081 See http://stackoverflow.com/questions/288828/how-to-use-a-jdbc-driver-from-an-arbitrary-location
082 */
083 Driver driver = (Driver)classloader.loadClass(getDriver()).newInstance();
084 DriverManager.registerDriver(new DriverProxy(driver));
085
086 } catch (Exception e) {
087 SQLException ex = new SQLException("SQL driver not found " + getDriver());
088 ex.initCause(e);
089 throw ex;
090 }
091 return DriverManager.getConnection(getUrl(), getUsername(), getPassword());
092 }
093
094 @Override
095 public void setupEntityManagerFactory(Properties factoryProps) {
096 factoryProps.put("hibernate.connection.url", getUrl());
097 factoryProps.put("hibernate.connection.driver_class", getDriver());
098 factoryProps.put("hibernate.connection.username", getUsername());
099 if (StringUtils.isNotEmpty(getPassword())) {
100 factoryProps.put("hibernate.connection.password", getPassword());
101 }
102 }
103 }
104
105 /**
106 * A Driver that stands in for another Driver.
107 * This is necessary because java.sql.DriverManager
108 * examines the Driver class class loader.
109 */
110 final class DriverProxy implements Driver {
111 private final Driver target;
112
113 DriverProxy(java.sql.Driver target) {
114 if (target == null) {
115 throw new NullPointerException();
116 }
117 this.target = target;
118 }
119
120 public java.sql.Driver getTarget() {
121 return target;
122 }
123
124 public boolean acceptsURL(String url) throws SQLException {
125 return target.acceptsURL(url);
126 }
127
128 public java.sql.Connection connect(
129 String url, java.util.Properties info
130 ) throws SQLException {
131 return target.connect(url, info);
132 }
133
134 public int getMajorVersion() {
135 return target.getMajorVersion();
136 }
137
138 public int getMinorVersion() {
139 return target.getMinorVersion();
140 }
141
142 public java.sql.DriverPropertyInfo[] getPropertyInfo(
143 String url, java.util.Properties info
144 ) throws SQLException {
145 return target.getPropertyInfo(url, info);
146 }
147
148 public boolean jdbcCompliant() {
149 return target.jdbcCompliant();
150 }
151
152 @Override
153 public String toString() {
154 return "Proxy: " + target;
155 }
156
157 @Override
158 public int hashCode() {
159 return target.hashCode();
160 }
161
162 @Override
163 public boolean equals(Object obj) {
164 if (!(obj instanceof DriverProxy)) {
165 return false;
166 }
167 DriverProxy other = (DriverProxy) obj;
168 return this.target.equals(other.target);
169 }
170 }