revised embedded database support
This commit is contained in:
parent
3ac3a72e91
commit
e9823b57b4
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.core.io;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link ResourceLoader} implementation that interprets plain resource paths
|
||||
* as relative to a given <code>java.lang.Class</code>.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
* @see java.lang.Class#getResource(String)
|
||||
* @see ClassPathResource#ClassPathResource(String, Class)
|
||||
*/
|
||||
public class ClassRelativeResourceLoader extends DefaultResourceLoader {
|
||||
|
||||
private final Class clazz;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ClassRelativeResourceLoader for the given class.
|
||||
* @param clazz the class to load resources through
|
||||
*/
|
||||
public ClassRelativeResourceLoader(Class clazz) {
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
this.clazz = clazz;
|
||||
setClassLoader(clazz.getClassLoader());
|
||||
}
|
||||
|
||||
protected Resource getResourceByPath(String path) {
|
||||
return new ClassRelativeContextResource(path, this.clazz);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ClassPathResource that explicitly expresses a context-relative path
|
||||
* through implementing the ContextResource interface.
|
||||
*/
|
||||
private static class ClassRelativeContextResource extends ClassPathResource implements ContextResource {
|
||||
|
||||
private final Class clazz;
|
||||
|
||||
public ClassRelativeContextResource(String path, Class clazz) {
|
||||
super(path, clazz);
|
||||
this.clazz = clazz;
|
||||
}
|
||||
|
||||
public String getPathWithinContext() {
|
||||
return getPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource createRelative(String relativePath) {
|
||||
String pathToUse = StringUtils.applyRelativePath(getPath(), relativePath);
|
||||
return new ClassRelativeContextResource(pathToUse, this.clazz);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -107,8 +107,8 @@ public class SimpleDriverDataSource extends AbstractDriverBasedDataSource {
|
|||
* within the SimpleDriverDataSource.
|
||||
* @see #setDriver
|
||||
*/
|
||||
public void setDriverClass(Class driverClass) {
|
||||
this.driver = (Driver) BeanUtils.instantiateClass(driverClass);
|
||||
public void setDriverClass(Class<? extends Driver> driverClass) {
|
||||
this.driver = BeanUtils.instantiateClass(driverClass);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -13,38 +13,39 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.datasource.embedded;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Base class for {@link EmbeddedDatabaseConfigurer} implementations providing common shutdown behaviour.
|
||||
* Base class for {@link EmbeddedDatabaseConfigurer} implementations providing common shutdown behavior.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
*/
|
||||
abstract class AbstractEmbeddedDatabaseConfigurer implements EmbeddedDatabaseConfigurer {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AbstractEmbeddedDatabaseConfigurer.class);
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
public void shutdown(DataSource dataSource, String databaseName) {
|
||||
Connection connection = JdbcUtils.getConnection(dataSource);
|
||||
Statement stmt = null;
|
||||
try {
|
||||
stmt = connection.createStatement();
|
||||
Connection connection = dataSource.getConnection();
|
||||
Statement stmt = connection.createStatement();
|
||||
stmt.execute("SHUTDOWN");
|
||||
} catch (SQLException e) {
|
||||
}
|
||||
catch (SQLException ex) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Could not shutdown embedded database", e);
|
||||
logger.warn("Could not shutdown embedded database", ex);
|
||||
}
|
||||
} finally {
|
||||
JdbcUtils.closeStatement(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.datasource.embedded;
|
||||
|
||||
import org.springframework.core.io.support.EncodedResource;
|
||||
|
|
@ -20,19 +21,19 @@ import org.springframework.core.io.support.EncodedResource;
|
|||
/**
|
||||
* Thrown by {@link ResourceDatabasePopulator} if one of its SQL scripts could
|
||||
* not be read during population.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @since 3.0
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class CannotReadScriptException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Creates a new cannot read script exception.
|
||||
*
|
||||
* Constructor a new CannotReadScriptException.
|
||||
* @param resource the resource that could not be read from
|
||||
* @param cause the underlying cause of the resource access failure
|
||||
*/
|
||||
public CannotReadScriptException(EncodedResource resource, Throwable cause) {
|
||||
super("Cannot read SQL script from " + resource, cause);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,38 +13,43 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.datasource.embedded;
|
||||
|
||||
import java.sql.Driver;
|
||||
|
||||
/**
|
||||
* DataSourceFactory helper that allows essential JDBC connection properties to be configured consistently,
|
||||
* independent of the actual DataSource implementation.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @since 3.0
|
||||
* @see DataSourceFactory
|
||||
*/
|
||||
public interface ConnectionProperties {
|
||||
|
||||
|
||||
/**
|
||||
* Set the JDBC driver to use to connect to the database.
|
||||
* @param driverClass the jdbc driver class
|
||||
*/
|
||||
void setDriverClass(Class<?> driverClass);
|
||||
|
||||
void setDriverClass(Class driverClass);
|
||||
|
||||
/**
|
||||
* Sets the JDBC connection URL of the database.
|
||||
* @param url the connection url
|
||||
*/
|
||||
void setUrl(String url);
|
||||
|
||||
|
||||
/**
|
||||
* Sets the username to use to connect to the database.
|
||||
* @param username the username
|
||||
*/
|
||||
void setUsername(String username);
|
||||
|
||||
|
||||
/**
|
||||
* Sets the password to use to connect to the database.
|
||||
* @param password the password
|
||||
*/
|
||||
void setPassword(String password);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.datasource.embedded;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
|
@ -20,21 +21,25 @@ import javax.sql.DataSource;
|
|||
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
|
||||
|
||||
/**
|
||||
* Encapsulates the creation of a particular DataSource implementation, such as a {@link SimpleDriverDataSource} or connection pool such as Apache DBCP or c3p0.
|
||||
* Call {@link #getConnectionProperties()} to configure normalized DataSource properties before calling {@link #getDataSource()} to actually get the configured DataSource instance.
|
||||
* Encapsulates the creation of a particular DataSource implementation, such as a
|
||||
* {@link SimpleDriverDataSource} or connection pool such as Apache DBCP or C3P0.
|
||||
*
|
||||
* <p>Call {@link #getConnectionProperties()} to configure normalized DataSource properties
|
||||
* before calling {@link #getDataSource()} to actually get the configured DataSource instance.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface DataSourceFactory {
|
||||
|
||||
|
||||
/**
|
||||
* Allows properties of the DataSource to be configured.
|
||||
*/
|
||||
ConnectionProperties getConnectionProperties();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the DataSource with the connection properties applied.
|
||||
*/
|
||||
DataSource getDataSource();
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.datasource.embedded;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
|
@ -20,6 +21,7 @@ import java.sql.SQLException;
|
|||
|
||||
/**
|
||||
* Strategy used to populate an embedded database during initialization.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @since 3.0
|
||||
* @see ResourceDatabasePopulator
|
||||
|
|
@ -32,4 +34,5 @@ public interface DatabasePopulator {
|
|||
* @throws SQLException if an unrecoverable data access exception occurs during database population
|
||||
*/
|
||||
void populate(Connection connection) throws SQLException;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,26 +13,26 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.datasource.embedded;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import java.util.Properties;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.derby.impl.io.VFMemoryStorageFactory;
|
||||
import org.apache.derby.jdbc.EmbeddedDriver;
|
||||
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* {@link EmbeddedDatabaseConfigurer} for the Apache Derby database.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
*/
|
||||
final class DerbyEmbeddedDatabaseConfigurer implements EmbeddedDatabaseConfigurer {
|
||||
|
|
@ -46,9 +46,6 @@ final class DerbyEmbeddedDatabaseConfigurer implements EmbeddedDatabaseConfigure
|
|||
|
||||
private static DerbyEmbeddedDatabaseConfigurer INSTANCE;
|
||||
|
||||
private DerbyEmbeddedDatabaseConfigurer() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the singleton {@link DerbyEmbeddedDatabaseConfigurer} instance.
|
||||
* @return the configurer
|
||||
|
|
@ -59,50 +56,48 @@ final class DerbyEmbeddedDatabaseConfigurer implements EmbeddedDatabaseConfigure
|
|||
// disable log file
|
||||
System.setProperty("derby.stream.error.method",
|
||||
DerbyEmbeddedDatabaseConfigurer.class.getName() + ".getNoopOutputStream");
|
||||
ClassUtils.forName("org.apache.derby.jdbc.EmbeddedDriver", DerbyEmbeddedDatabaseConfigurer.class
|
||||
.getClassLoader());
|
||||
INSTANCE = new DerbyEmbeddedDatabaseConfigurer();
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private DerbyEmbeddedDatabaseConfigurer() {
|
||||
}
|
||||
|
||||
public void configureConnectionProperties(ConnectionProperties properties, String databaseName) {
|
||||
properties.setDriverClass(org.apache.derby.jdbc.EmbeddedDriver.class);
|
||||
properties.setDriverClass(EmbeddedDriver.class);
|
||||
properties.setUrl(String.format(URL_TEMPLATE, databaseName, "create=true"));
|
||||
properties.setUsername("sa");
|
||||
properties.setPassword("");
|
||||
}
|
||||
|
||||
public void shutdown(DataSource dataSource, String databaseName) {
|
||||
Connection connection = null;
|
||||
try {
|
||||
SimpleDriverDataSource shutdownDataSource = new SimpleDriverDataSource();
|
||||
shutdownDataSource.setDriverClass(EmbeddedDriver.class);
|
||||
shutdownDataSource.setUrl(String.format(URL_TEMPLATE, databaseName, "shutdown=true"));
|
||||
connection = shutdownDataSource.getConnection();
|
||||
} catch (SQLException e) {
|
||||
if (SHUTDOWN_CODE.equals(e.getSQLState())) {
|
||||
new EmbeddedDriver().connect(
|
||||
String.format(URL_TEMPLATE, databaseName, "shutdown=true"), new Properties());
|
||||
}
|
||||
catch (SQLException ex) {
|
||||
if (SHUTDOWN_CODE.equals(ex.getSQLState())) {
|
||||
purgeDatabase(databaseName);
|
||||
} else {
|
||||
logger.warn("Could not shutdown in-memory Derby database", e);
|
||||
}
|
||||
} finally {
|
||||
JdbcUtils.closeConnection(connection);
|
||||
else {
|
||||
logger.warn("Could not shutdown in-memory Derby database", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Purges the in-memory database, to prevent it from hanging around after
|
||||
* being shut down
|
||||
* @param databaseName
|
||||
* Purge the in-memory database, to prevent it from hanging around after
|
||||
* being shut down.
|
||||
*/
|
||||
private void purgeDatabase(String databaseName) {
|
||||
// TODO: update this code once Derby adds a proper way to remove an in-memory db
|
||||
// (see http://wiki.apache.org/db-derby/InMemoryBackEndPrimer for details)
|
||||
try {
|
||||
VFMemoryStorageFactory.purgeDatabase(new File(databaseName).getCanonicalPath());
|
||||
} catch (IOException ioe) {
|
||||
logger.warn("Could not purge in-memory Derby database", ioe);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
logger.warn("Could not purge in-memory Derby database", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -114,9 +109,9 @@ final class DerbyEmbeddedDatabaseConfigurer implements EmbeddedDatabaseConfigure
|
|||
static OutputStream getNoopOutputStream() {
|
||||
return new OutputStream() {
|
||||
public void write(int b) throws IOException {
|
||||
// ignore the input
|
||||
// ignore the output
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.datasource.embedded;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
|
@ -21,13 +22,15 @@ import javax.sql.DataSource;
|
|||
* A handle to an EmbeddedDatabase instance.
|
||||
* Is a {@link DataSource}.
|
||||
* Adds a shutdown operation so the embedded database instance can be shutdown.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface EmbeddedDatabase extends DataSource {
|
||||
|
||||
|
||||
/**
|
||||
* Shutdown this embedded database.
|
||||
*/
|
||||
void shutdown();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,39 +13,55 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.datasource.embedded;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.ClassRelativeResourceLoader;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
|
||||
/**
|
||||
* A builder that provides a fluent API for constructing an embedded database.
|
||||
* Usage example:
|
||||
*
|
||||
* <p>Usage example:
|
||||
* <pre>
|
||||
* EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
|
||||
* EmbeddedDatabase db = builder.script("schema.sql").script("test-data.sql").build();
|
||||
* db.shutdown();
|
||||
* </pre>
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
*/
|
||||
public class EmbeddedDatabaseBuilder {
|
||||
|
||||
private EmbeddedDatabaseFactory databaseFactory;
|
||||
private final EmbeddedDatabaseFactory databaseFactory;
|
||||
|
||||
private ResourceDatabasePopulator databasePopulator;
|
||||
private final ResourceDatabasePopulator databasePopulator;
|
||||
|
||||
private final ResourceLoader resourceLoader;
|
||||
|
||||
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
/**
|
||||
* Creates a new embedded database builder.
|
||||
* Create a new embedded database builder.
|
||||
*/
|
||||
public EmbeddedDatabaseBuilder() {
|
||||
init(new DefaultResourceLoader());
|
||||
this(new DefaultResourceLoader());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new embedded database builder withfor the given ResourceLoader.
|
||||
* @param resourceLoader the ResourceLoader to delegate to
|
||||
*/
|
||||
public EmbeddedDatabaseBuilder(ResourceLoader resourceLoader) {
|
||||
this.databaseFactory = new EmbeddedDatabaseFactory();
|
||||
this.databasePopulator = new ResourceDatabasePopulator();
|
||||
this.databaseFactory.setDatabasePopulator(this.databasePopulator);
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the name of the embedded database
|
||||
* Defaults to 'testdb' if not called.
|
||||
|
|
@ -53,7 +69,7 @@ public class EmbeddedDatabaseBuilder {
|
|||
* @return this, for fluent call chaining
|
||||
*/
|
||||
public EmbeddedDatabaseBuilder name(String databaseName) {
|
||||
databaseFactory.setDatabaseName(databaseName);
|
||||
this.databaseFactory.setDatabaseName(databaseName);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -64,7 +80,7 @@ public class EmbeddedDatabaseBuilder {
|
|||
* @return this, for fluent call chaining
|
||||
*/
|
||||
public EmbeddedDatabaseBuilder type(EmbeddedDatabaseType databaseType) {
|
||||
databaseFactory.setDatabaseType(databaseType);
|
||||
this.databaseFactory.setDatabaseType(databaseType);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -74,7 +90,7 @@ public class EmbeddedDatabaseBuilder {
|
|||
* @return this, for fluent call chaining
|
||||
*/
|
||||
public EmbeddedDatabaseBuilder script(String sqlResource) {
|
||||
databasePopulator.addScript(resourceLoader.getResource(sqlResource));
|
||||
this.databasePopulator.addScript(resourceLoader.getResource(sqlResource));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -83,45 +99,28 @@ public class EmbeddedDatabaseBuilder {
|
|||
* @return the embedded database
|
||||
*/
|
||||
public EmbeddedDatabase build() {
|
||||
return databaseFactory.getDatabase();
|
||||
return this.databaseFactory.getDatabase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method that creates a EmbeddedDatabaseBuilder that loads SQL resources relative to the provided class.
|
||||
* @param clazz the class to load relative to
|
||||
* @return the embedded database builder
|
||||
*/
|
||||
public static EmbeddedDatabaseBuilder relativeTo(final Class<?> clazz) {
|
||||
ResourceLoader loader = new ResourceLoader() {
|
||||
public ClassLoader getClassLoader() {
|
||||
return getClass().getClassLoader();
|
||||
}
|
||||
|
||||
public Resource getResource(String location) {
|
||||
return new ClassPathResource(location, clazz);
|
||||
}
|
||||
};
|
||||
return new EmbeddedDatabaseBuilder(loader);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Factory method that builds a default EmbeddedDatabase instance.
|
||||
* The default instance is HSQL with a schema created from classpath:schema.sql and test-data loaded from classpath:test-data.sql.
|
||||
* The default instance is HSQL with a schema created from "classpath:schema.sql"
|
||||
* and test-data loaded from "classpath:test-data.sql".
|
||||
* @return an embedded database
|
||||
*/
|
||||
public static EmbeddedDatabase buildDefault() {
|
||||
return new EmbeddedDatabaseBuilder().script("schema.sql").script("test-data.sql").build();
|
||||
}
|
||||
|
||||
private EmbeddedDatabaseBuilder(ResourceLoader loader) {
|
||||
init(loader);
|
||||
}
|
||||
|
||||
private void init(ResourceLoader loader) {
|
||||
databaseFactory = new EmbeddedDatabaseFactory();
|
||||
databasePopulator = new ResourceDatabasePopulator();
|
||||
databaseFactory.setDatabasePopulator(databasePopulator);
|
||||
resourceLoader = loader;
|
||||
|
||||
/**
|
||||
* Factory method that creates a EmbeddedDatabaseBuilder that loads SQL resources
|
||||
* relative to the provided class.
|
||||
* @param clazz the class to load relative to
|
||||
* @return the embedded database builder
|
||||
*/
|
||||
public static EmbeddedDatabaseBuilder relativeTo(Class clazz) {
|
||||
return new EmbeddedDatabaseBuilder(new ClassRelativeResourceLoader(clazz));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.datasource.embedded;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
|
@ -20,6 +21,7 @@ import javax.sql.DataSource;
|
|||
/**
|
||||
* Encapsulates the configuration required to create, connect to, and shutdown a specific type of embedded database such as HSQL or H2.
|
||||
* Create a implementation for each database type you wish to support; for example HSQL, H2, or some other type.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @since 3.0
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -13,13 +13,15 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.datasource.embedded;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Maps well-known {@link EmbeddedDatabaseType embedded database types} to {@link EmbeddedDatabaseConfigurer}
|
||||
* strategies.
|
||||
* Maps well-known {@link EmbeddedDatabaseType embedded database types} to
|
||||
* {@link EmbeddedDatabaseConfigurer} strategies.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Oliver Gierke
|
||||
* @since 3.0
|
||||
|
|
@ -27,25 +29,26 @@ import org.springframework.util.Assert;
|
|||
final class EmbeddedDatabaseConfigurerFactory {
|
||||
|
||||
public static EmbeddedDatabaseConfigurer getConfigurer(EmbeddedDatabaseType type) throws IllegalStateException {
|
||||
Assert.notNull(type, "The EmbeddedDatabaseType is required");
|
||||
Assert.notNull(type, "EmbeddedDatabaseType is required");
|
||||
try {
|
||||
switch (type) {
|
||||
case HSQL:
|
||||
return HsqlEmbeddedDatabaseConfigurer.getInstance();
|
||||
case H2:
|
||||
return H2EmbeddedDatabaseConfigurer.getInstance();
|
||||
case DERBY:
|
||||
return DerbyEmbeddedDatabaseConfigurer.getInstance();
|
||||
default:
|
||||
throw new UnsupportedOperationException("Other embedded database types not yet supported");
|
||||
case HSQL:
|
||||
return HsqlEmbeddedDatabaseConfigurer.getInstance();
|
||||
case H2:
|
||||
return H2EmbeddedDatabaseConfigurer.getInstance();
|
||||
case DERBY:
|
||||
return DerbyEmbeddedDatabaseConfigurer.getInstance();
|
||||
default:
|
||||
throw new UnsupportedOperationException("Other embedded database types not yet supported");
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new IllegalStateException("Drivers for test database type [" + type
|
||||
+ "] are not available in the classpath", e);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
throw new IllegalStateException("Driver for test database type [" + type +
|
||||
"] is not available in the classpath", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private EmbeddedDatabaseConfigurerFactory() {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,39 +13,43 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.datasource.embedded;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Creates a {@link EmbeddedDatabase} instance. Callers are guaranteed that the returned database has been fully
|
||||
* initialized and populated.
|
||||
* <p>
|
||||
* Can be configured:<br>
|
||||
*
|
||||
* <p>Can be configured:<br>
|
||||
* Call {@link #setDatabaseName(String)} to change the name of the database.<br>
|
||||
* Call {@link #setDatabaseType(EmbeddedDatabaseType)} to set the database type if you wish to use one of the supported types.<br>
|
||||
* Call {@link #setDatabaseConfigurer(EmbeddedDatabaseConfigurer)} to configure support for your own embedded database type.<br>
|
||||
* Call {@link #setDatabasePopulator(DatabasePopulator)} to change the algorithm used to populate the database.<br>
|
||||
* Call {@link #setDataSourceFactory(DataSourceFactory)} to change the type of DataSource used to connect to the database.<br>
|
||||
* Call {@link #getDatabase()} to get the {@link EmbeddedDatabase} instance.<br>
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
*/
|
||||
public class EmbeddedDatabaseFactory {
|
||||
|
||||
private static Log logger = LogFactory.getLog(EmbeddedDatabaseFactory.class);
|
||||
|
||||
private String databaseName;
|
||||
private String databaseName = "testdb";
|
||||
|
||||
private DataSourceFactory dataSourceFactory;
|
||||
private DataSourceFactory dataSourceFactory = new SimpleDriverDataSourceFactory();
|
||||
|
||||
private EmbeddedDatabaseConfigurer databaseConfigurer;
|
||||
|
||||
|
|
@ -53,101 +57,114 @@ public class EmbeddedDatabaseFactory {
|
|||
|
||||
private DataSource dataSource;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a default {@link EmbeddedDatabaseFactory}.
|
||||
* Calling {@link #getDatabase()} will create a embedded HSQL database of name 'testdb'.
|
||||
* Set the name of the database. Defaults to "testdb".
|
||||
* @param databaseName name of the test database
|
||||
*/
|
||||
public EmbeddedDatabaseFactory() {
|
||||
setDatabaseName("testdb");
|
||||
setDatabaseType(EmbeddedDatabaseType.HSQL);
|
||||
setDataSourceFactory(new SimpleDriverDataSourceFactory());
|
||||
public void setDatabaseName(String databaseName) {
|
||||
Assert.notNull(databaseName, "Database name is required");
|
||||
this.databaseName = databaseName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the database. Defaults to 'testdb'.
|
||||
* @param name of the test database
|
||||
*/
|
||||
public void setDatabaseName(String name) {
|
||||
Assert.notNull(name, "The testDatabaseName is required");
|
||||
databaseName = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type of embedded database to use. Call this when you wish to configure one of the pre-supported types.
|
||||
* Defaults to HSQL.
|
||||
* Set the type of embedded database to use. Call this when you wish to configure
|
||||
* one of the pre-supported types. Defaults to HSQL.
|
||||
* @param type the test database type
|
||||
*/
|
||||
public void setDatabaseType(EmbeddedDatabaseType type) {
|
||||
setDatabaseConfigurer(EmbeddedDatabaseConfigurerFactory.getConfigurer(type));
|
||||
this.databaseConfigurer = EmbeddedDatabaseConfigurerFactory.getConfigurer(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the strategy that will be used to configure the embedded database instance.
|
||||
* Set the strategy that will be used to configure the embedded database instance.
|
||||
* Call this when you wish to use an embedded database type not already supported.
|
||||
* @param configurer the embedded database configurer
|
||||
*/
|
||||
public void setDatabaseConfigurer(EmbeddedDatabaseConfigurer configurer) {
|
||||
Assert.notNull(configurer, "EmbeddedDatabaseConfigurer is required");
|
||||
this.databaseConfigurer = configurer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the strategy that will be used to populate the embedded database. Defaults to null.
|
||||
* Set the strategy that will be used to populate the embedded database. Defaults to null.
|
||||
* @param populator the database populator
|
||||
*/
|
||||
public void setDatabasePopulator(DatabasePopulator populator) {
|
||||
Assert.notNull(populator, "The DatabasePopulator is required");
|
||||
databasePopulator = populator;
|
||||
Assert.notNull(populator, "DatabasePopulator is required");
|
||||
this.databasePopulator = populator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the factory to use to create the DataSource instance that connects to the embedded database
|
||||
* Set the factory to use to create the DataSource instance that connects to the embedded database.
|
||||
* Defaults to {@link SimpleDriverDataSourceFactory}.
|
||||
* @param dataSourceFactory the data source factory
|
||||
*/
|
||||
public void setDataSourceFactory(DataSourceFactory dataSourceFactory) {
|
||||
Assert.notNull(dataSourceFactory, "The DataSourceFactory is required");
|
||||
Assert.notNull(dataSourceFactory, "DataSourceFactory is required");
|
||||
this.dataSourceFactory = dataSourceFactory;
|
||||
}
|
||||
|
||||
// other public methods
|
||||
|
||||
/**
|
||||
* Factory method that returns the embedded database instance.
|
||||
*/
|
||||
public EmbeddedDatabase getDatabase() {
|
||||
if (dataSource == null) {
|
||||
if (this.dataSource == null) {
|
||||
initDatabase();
|
||||
}
|
||||
return new EmbeddedDataSourceProxy(dataSource);
|
||||
return new EmbeddedDataSourceProxy(this.dataSource);
|
||||
}
|
||||
|
||||
// subclassing hooks
|
||||
|
||||
/**
|
||||
* Hook to initialize the embedded database. Subclasses may call to force initialization. After calling this method,
|
||||
* {@link #getDataSource()} returns the DataSource providing connectivity to the db.
|
||||
*/
|
||||
protected void initDatabase() {
|
||||
// create the embedded database source first
|
||||
// Create the embedded database source first
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Created embedded database '" + databaseName + "'");
|
||||
logger.info("Creating embedded database '" + this.databaseName + "'");
|
||||
}
|
||||
databaseConfigurer.configureConnectionProperties(dataSourceFactory.getConnectionProperties(), databaseName);
|
||||
dataSource = dataSourceFactory.getDataSource();
|
||||
if (databasePopulator != null) {
|
||||
// now populate the database
|
||||
if (this.databaseConfigurer == null) {
|
||||
this.databaseConfigurer = EmbeddedDatabaseConfigurerFactory.getConfigurer(EmbeddedDatabaseType.HSQL);
|
||||
}
|
||||
this.databaseConfigurer.configureConnectionProperties(
|
||||
this.dataSourceFactory.getConnectionProperties(), this.databaseName);
|
||||
this.dataSource = this.dataSourceFactory.getDataSource();
|
||||
|
||||
// Now populate the database
|
||||
if (this.databasePopulator != null) {
|
||||
populateDatabase();
|
||||
}
|
||||
}
|
||||
|
||||
private void populateDatabase() {
|
||||
try {
|
||||
Connection connection = this.dataSource.getConnection();
|
||||
try {
|
||||
this.databasePopulator.populate(connection);
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
connection.close();
|
||||
}
|
||||
catch (SQLException ex) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SQLException ex) {
|
||||
throw new DataAccessResourceFailureException("Failed to populate database", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook that gets the datasource that provides the connectivity to the embedded database.
|
||||
* Returns null if the datasource has not been initialized or the database has been shutdown.
|
||||
* Hook that gets the DataSource that provides the connectivity to the embedded database.
|
||||
* <p>Returns null if the DataSource has not been initialized or the database has been shut down.
|
||||
* Subclasses may call to access the datasource instance directly.
|
||||
* @return the datasource
|
||||
*/
|
||||
protected DataSource getDataSource() {
|
||||
return dataSource;
|
||||
return this.dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -155,68 +172,56 @@ public class EmbeddedDatabaseFactory {
|
|||
* After calling, {@link #getDataSource()} returns null. Does nothing if no embedded database has been initialized.
|
||||
*/
|
||||
protected void shutdownDatabase() {
|
||||
if (dataSource != null) {
|
||||
databaseConfigurer.shutdown(dataSource, databaseName);
|
||||
dataSource = null;
|
||||
if (this.dataSource != null) {
|
||||
this.databaseConfigurer.shutdown(this.dataSource, this.databaseName);
|
||||
this.dataSource = null;
|
||||
}
|
||||
}
|
||||
|
||||
// internal helper methods
|
||||
|
||||
private void populateDatabase() {
|
||||
Connection connection = JdbcUtils.getConnection(dataSource);
|
||||
try {
|
||||
databasePopulator.populate(connection);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("SQLException occurred populating embedded database", e);
|
||||
} finally {
|
||||
JdbcUtils.closeConnection(connection);
|
||||
}
|
||||
}
|
||||
|
||||
private class EmbeddedDataSourceProxy implements EmbeddedDatabase {
|
||||
private DataSource dataSource;
|
||||
|
||||
private final DataSource dataSource;
|
||||
|
||||
public EmbeddedDataSourceProxy(DataSource dataSource) {
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
public Connection getConnection() throws SQLException {
|
||||
return dataSource.getConnection();
|
||||
return this.dataSource.getConnection();
|
||||
}
|
||||
|
||||
public Connection getConnection(String username, String password) throws SQLException {
|
||||
return dataSource.getConnection(username, password);
|
||||
return this.dataSource.getConnection(username, password);
|
||||
}
|
||||
|
||||
public int getLoginTimeout() throws SQLException {
|
||||
return dataSource.getLoginTimeout();
|
||||
return this.dataSource.getLoginTimeout();
|
||||
}
|
||||
|
||||
public PrintWriter getLogWriter() throws SQLException {
|
||||
return dataSource.getLogWriter();
|
||||
return this.dataSource.getLogWriter();
|
||||
}
|
||||
|
||||
public void setLoginTimeout(int seconds) throws SQLException {
|
||||
dataSource.setLoginTimeout(seconds);
|
||||
this.dataSource.setLoginTimeout(seconds);
|
||||
}
|
||||
|
||||
public void setLogWriter(PrintWriter out) throws SQLException {
|
||||
dataSource.setLogWriter(out);
|
||||
this.dataSource.setLogWriter(out);
|
||||
}
|
||||
|
||||
public boolean isWrapperFor(Class<?> iface) throws SQLException {
|
||||
return dataSource.isWrapperFor(iface);
|
||||
return this.dataSource.isWrapperFor(iface);
|
||||
}
|
||||
|
||||
public <T> T unwrap(Class<T> iface) throws SQLException {
|
||||
return dataSource.unwrap(iface);
|
||||
return this.dataSource.unwrap(iface);
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
shutdownDatabase();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.datasource.embedded;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
|
@ -24,18 +25,23 @@ import org.springframework.beans.factory.InitializingBean;
|
|||
/**
|
||||
* A subclass of {@link EmbeddedDatabaseFactory} that implements {@link FactoryBean} for registration as a Spring bean.
|
||||
* Returns the actual {@link DataSource} that provides connectivity to the embedded database to Spring.
|
||||
* The target DataSource is returned instead of a {@link EmbeddedDatabase} proxy since the FactoryBean will manage the initialization and destruction lifecycle of the database instance.
|
||||
* Implements DisposableBean to shutdown the embedded database when the managing Spring container is shutdown.
|
||||
*
|
||||
* <p>The target DataSource is returned instead of a {@link EmbeddedDatabase} proxy since the FactoryBean
|
||||
* will manage the initialization and destruction lifecycle of the database instance.
|
||||
*
|
||||
* <p>Implements DisposableBean to shutdown the embedded database when the managing Spring container is shutdown.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @since 3.0
|
||||
*/
|
||||
public class EmbeddedDatabaseFactoryBean extends EmbeddedDatabaseFactory implements FactoryBean<DataSource>, InitializingBean, DisposableBean {
|
||||
public class EmbeddedDatabaseFactoryBean extends EmbeddedDatabaseFactory
|
||||
implements FactoryBean<DataSource>, InitializingBean, DisposableBean {
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
public void afterPropertiesSet() {
|
||||
initDatabase();
|
||||
}
|
||||
|
||||
public DataSource getObject() throws Exception {
|
||||
public DataSource getObject() {
|
||||
return getDataSource();
|
||||
}
|
||||
|
||||
|
|
@ -47,7 +53,7 @@ public class EmbeddedDatabaseFactoryBean extends EmbeddedDatabaseFactory impleme
|
|||
return true;
|
||||
}
|
||||
|
||||
public void destroy() throws Exception {
|
||||
public void destroy() {
|
||||
shutdownDatabase();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,14 +13,18 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.datasource.embedded;
|
||||
|
||||
/**
|
||||
* A supported embedded database type.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Oliver Gierke
|
||||
* @since 3.0
|
||||
*/
|
||||
public enum EmbeddedDatabaseType {
|
||||
HSQL, H2, DERBY;
|
||||
|
||||
HSQL, H2, DERBY
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.datasource.embedded;
|
||||
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
|
@ -20,7 +21,9 @@ import org.springframework.util.ClassUtils;
|
|||
/**
|
||||
* Initializes an H2 embedded database instance.
|
||||
* Call {@link #getInstance()} to get the singleton instance of this class.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
*/
|
||||
final class H2EmbeddedDatabaseConfigurer extends AbstractEmbeddedDatabaseConfigurer {
|
||||
|
|
@ -42,15 +45,15 @@ final class H2EmbeddedDatabaseConfigurer extends AbstractEmbeddedDatabaseConfigu
|
|||
return INSTANCE;
|
||||
}
|
||||
|
||||
private H2EmbeddedDatabaseConfigurer(Class<?> driverClass) {
|
||||
this.driverClass = driverClass;
|
||||
}
|
||||
|
||||
public void configureConnectionProperties(ConnectionProperties properties, String databaseName) {
|
||||
properties.setDriverClass(driverClass);
|
||||
properties.setDriverClass(this.driverClass);
|
||||
properties.setUrl(String.format("jdbc:h2:mem:%s;DB_CLOSE_DELAY=-1", databaseName));
|
||||
properties.setUsername("sa");
|
||||
properties.setPassword("");
|
||||
}
|
||||
|
||||
private H2EmbeddedDatabaseConfigurer(Class<?> driverClass) {
|
||||
this.driverClass = driverClass;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.datasource.embedded;
|
||||
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
|
@ -20,6 +21,7 @@ import org.springframework.util.ClassUtils;
|
|||
/**
|
||||
* Initializes an HSQL embedded database instance.
|
||||
* Call {@link #getInstance()} to get the singleton instance of this class.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Oliver Gierke
|
||||
* @since 3.0
|
||||
|
|
@ -43,15 +45,15 @@ final class HsqlEmbeddedDatabaseConfigurer extends AbstractEmbeddedDatabaseConfi
|
|||
return INSTANCE;
|
||||
}
|
||||
|
||||
private HsqlEmbeddedDatabaseConfigurer(Class<?> driverClass) {
|
||||
this.driverClass = driverClass;
|
||||
}
|
||||
|
||||
public void configureConnectionProperties(ConnectionProperties properties, String databaseName) {
|
||||
properties.setDriverClass(driverClass);
|
||||
properties.setDriverClass(this.driverClass);
|
||||
properties.setUrl("jdbc:hsqldb:mem:" + databaseName);
|
||||
properties.setUsername("sa");
|
||||
properties.setPassword("");
|
||||
}
|
||||
|
||||
private HsqlEmbeddedDatabaseConfigurer(Class<?> driverClass) {
|
||||
this.driverClass = driverClass;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.jdbc.datasource.embedded;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.jdbc.CannotGetJdbcConnectionException;
|
||||
|
||||
/**
|
||||
* Helper JDBC utilities used by other classes in this package.
|
||||
* Note there is some duplication here with JdbcUtils in jdbc.support package.
|
||||
* We may want to consider simply using that at some point.
|
||||
* @author Keith Donald
|
||||
* @since 3.0
|
||||
*/
|
||||
final class JdbcUtils {
|
||||
|
||||
private static Log logger = LogFactory.getLog(EmbeddedDatabaseFactory.class);
|
||||
|
||||
private JdbcUtils() {
|
||||
|
||||
}
|
||||
|
||||
public static Connection getConnection(DataSource dataSource) {
|
||||
try {
|
||||
return dataSource.getConnection();
|
||||
} catch (SQLException ex) {
|
||||
throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static void closeConnection(Connection connection) {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException ex) {
|
||||
logger.debug("Could not close JDBC Connection", ex);
|
||||
} catch (Throwable ex) {
|
||||
// We don't trust the JDBC driver: It might throw RuntimeException or Error.
|
||||
logger.debug("Unexpected exception on closing JDBC Connection", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void closeStatement(Statement stmt) {
|
||||
if (stmt != null) {
|
||||
try {
|
||||
stmt.close();
|
||||
} catch (SQLException ex) {
|
||||
logger.debug("Could not close JDBC Statement", ex);
|
||||
} catch (Throwable ex) {
|
||||
// We don't trust the JDBC driver: It might throw RuntimeException or Error.
|
||||
logger.debug("Unexpected exception on closing JDBC Statement", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.datasource.embedded;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
@ -27,15 +28,17 @@ import java.util.List;
|
|||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.EncodedResource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Populates a database from SQL scripts defined in external resources.
|
||||
* <p>
|
||||
* Call {@link #addScript(Resource)} to add a SQL script location.<br>
|
||||
*
|
||||
* <p>Call {@link #addScript(Resource)} to add a SQL script location.<br>
|
||||
* Call {@link #setSqlScriptEncoding(String)} to set the encoding for all added scripts.<br>
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @since 3.0
|
||||
*/
|
||||
|
|
@ -47,6 +50,7 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
|
|||
|
||||
private String sqlScriptEncoding;
|
||||
|
||||
|
||||
/**
|
||||
* Add a script to execute to populate the database.
|
||||
* @param script the path to a SQL script
|
||||
|
|
@ -65,15 +69,17 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
|
|||
|
||||
/**
|
||||
* Specify the encoding for SQL scripts, if different from the platform encoding.
|
||||
* Note setting this property has no effect on added scripts that are already {@link EncodedResource encoded resources}.
|
||||
* Note setting this property has no effect on added scripts that are already
|
||||
* {@link EncodedResource encoded resources}.
|
||||
* @see #addScript(Resource)
|
||||
*/
|
||||
public void setSqlScriptEncoding(String sqlScriptEncoding) {
|
||||
this.sqlScriptEncoding = sqlScriptEncoding;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void populate(Connection connection) throws SQLException {
|
||||
for (Resource script : scripts) {
|
||||
for (Resource script : this.scripts) {
|
||||
executeSqlScript(connection, applyEncodingIfNecessary(script), false);
|
||||
}
|
||||
}
|
||||
|
|
@ -81,8 +87,9 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
|
|||
private EncodedResource applyEncodingIfNecessary(Resource script) {
|
||||
if (script instanceof EncodedResource) {
|
||||
return (EncodedResource) script;
|
||||
} else {
|
||||
return new EncodedResource(script, sqlScriptEncoding);
|
||||
}
|
||||
else {
|
||||
return new EncodedResource(script, this.sqlScriptEncoding);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -95,6 +102,7 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
|
|||
*/
|
||||
private void executeSqlScript(Connection connection, EncodedResource resource, boolean continueOnError)
|
||||
throws SQLException {
|
||||
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Executing SQL script from " + resource);
|
||||
}
|
||||
|
|
@ -112,25 +120,34 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
|
|||
}
|
||||
splitSqlScript(script, delimiter, statements);
|
||||
int lineNumber = 0;
|
||||
for (String statement : statements) {
|
||||
lineNumber++;
|
||||
Statement stmt = null;
|
||||
try {
|
||||
stmt = connection.createStatement();
|
||||
int rowsAffected = stmt.executeUpdate(statement);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(rowsAffected + " rows affected by SQL: " + statement);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
if (continueOnError) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Line " + lineNumber + " statement failed: " + statement, e);
|
||||
Statement stmt = connection.createStatement();
|
||||
try {
|
||||
for (String statement : statements) {
|
||||
lineNumber++;
|
||||
try {
|
||||
int rowsAffected = stmt.executeUpdate(statement);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(rowsAffected + " rows affected by SQL: " + statement);
|
||||
}
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
JdbcUtils.closeStatement(stmt);
|
||||
catch (SQLException ex) {
|
||||
if (continueOnError) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Line " + lineNumber + " statement failed: " + statement, ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
stmt.close();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.debug("Could not close JDBC Statement", ex);
|
||||
}
|
||||
}
|
||||
long elapsedTime = System.currentTimeMillis() - startTime;
|
||||
|
|
@ -209,4 +226,4 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,35 +13,39 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.datasource.embedded;
|
||||
|
||||
import java.sql.Driver;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Creates a {@link SimpleDriverDataSource}.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
*/
|
||||
final class SimpleDriverDataSourceFactory implements DataSourceFactory {
|
||||
|
||||
private SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
|
||||
private final SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
|
||||
|
||||
public ConnectionProperties getConnectionProperties() {
|
||||
return new ConnectionProperties() {
|
||||
public void setDriverClass(Class<?> driverClass) {
|
||||
dataSource.setDriverClass(driverClass);
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setDriverClass(Class driverClass) {
|
||||
Assert.isAssignable(Driver.class, driverClass);
|
||||
dataSource.setDriverClass((Class<? extends Driver>) driverClass);
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
dataSource.setUrl(url);
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
dataSource.setUsername(username);
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
dataSource.setPassword(password);
|
||||
}
|
||||
|
|
@ -49,7 +53,7 @@ final class SimpleDriverDataSourceFactory implements DataSourceFactory {
|
|||
}
|
||||
|
||||
public DataSource getDataSource() {
|
||||
return dataSource;
|
||||
return this.dataSource;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue