blob: 98dcd7068bdd5cb2f98bfc80607800af066e532b [file] [log] [blame]
/*******************************************************************************
* Copyright (C) 2007 The University of Manchester
*
* Modifications to the initial code base are copyright of their
* respective authors, or their employers as appropriate.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
******************************************************************************/
package net.sf.taverna.platform.spring.jdbc;
import static net.sf.taverna.platform.spring.PropertyInterpolator.interpolate;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
import net.sf.taverna.raven.repository.Artifact;
import net.sf.taverna.raven.repository.BasicArtifact;
import net.sf.taverna.raven.repository.Repository;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.util.ClassUtils;
/**
* Subclass of the DriverManagerDataSource so we can use interpolated properties
* in e.g. database URLs from the spring configuration. Interpolation is applied
* to all set-able string properties.
* <p>
* In addition this class can be used to register JDBC drivers loaded from Raven
* artifacts. If the optional 'repository' and 'driverArtifact' properties are
* injected (of type Repository and String respectively) the specified driver
* will be loaded from the artifact, including any download or other activity
* needed to resolve it properly. The driver will be loaded in a temporary
* classloader and a proxy to it loaded in the platform classloader, making it
* visible to systems which can't see inside the artifact class loaders such as
* Hibernate. If these properties are undefined the data source reverts to
* default behaviour for a DriverManagerDataSource
*
* @author Tom Oinn
*
*/
public class InterpolatingDriverManagerDataSource extends
DriverManagerDataSource {
private Log log = LogFactory
.getLog(InterpolatingDriverManagerDataSource.class);
@Override
public void setUrl(String newUrl) {
super.setUrl(interpolate(newUrl));
}
@Override
public void setUsername(String newUsername) {
super.setUsername(interpolate(newUsername));
}
@Override
public void setPassword(String newPassword) {
super.setPassword(interpolate(newPassword));
}
private String myDriverClassName = null;
@Override
public void setDriverClassName(String newDriverClassName) {
this.myDriverClassName = newDriverClassName.trim();
}
/**
* Prevent automatic registration of class on load, defer until asked for so
* we know whether we have an artifact specifier or not
*/
@Override
public String getDriverClassName() {
return this.myDriverClassName;
}
private Repository repository = null;
private Artifact driverArtifact = null;
/**
* Inject a raven repository object to fetch the driver artifact from if
* specified
*
* @param rep
*/
public void setRepository(Repository rep) {
this.repository = rep;
}
/**
* Inject a driver artifact specification, used if not null and as long as
* there is an appropriate repository also injected.
*
* @param a
*/
public void setDriverArtifact(String a) {
String[] parts = a.split(":");
driverArtifact = new BasicArtifact(parts[0], parts[1], parts[2]);
}
private boolean initialized = false;
@Override
protected synchronized Connection getConnectionFromDriverManager(
String url, Properties props) throws SQLException {
if (!initialized) {
if (repository == null || driverArtifact == null) {
// Perform regular style initialization through loading the
// class by name
try {
Class.forName(getDriverClassName(), true, ClassUtils
.getDefaultClassLoader());
} catch (ClassNotFoundException cnfe) {
log.error(
"Can't fine the regular (non raven) JDBC driver class "
+ getDriverClassName(), cnfe);
IllegalStateException ise = new IllegalStateException(
"Could not load JDBC driver class ["
+ getDriverClassName() + "]");
ise.initCause(cnfe);
throw ise;
}
logger.info("Loaded non raven JDBC driver: "
+ getDriverClassName());
} else {
// Loading through raven using the funky proxied drivers
ProxyDriverManager.registerDriver(repository, driverArtifact,
getDriverClassName());
}
initialized = true;
}
return DriverManager.getConnection(url, props);
}
}