diff --git a/spring-boot-devtools/pom.xml b/spring-boot-devtools/pom.xml index 8c274f5957..53a73f6509 100644 --- a/spring-boot-devtools/pom.xml +++ b/spring-boot-devtools/pom.xml @@ -112,6 +112,17 @@ spring-webmvc test + + org.apache.derby + derby + test + + + org.apache.derby + derbyclient + ${derby.version} + test + org.apache.tomcat.embed tomcat-embed-core @@ -122,6 +133,11 @@ websocket-client test + + org.hsqldb + hsqldb + test + org.postgresql postgresql diff --git a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsDataSourceAutoConfiguration.java b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsDataSourceAutoConfiguration.java index 2c867b5013..6ca4905fbc 100644 --- a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsDataSourceAutoConfiguration.java +++ b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/autoconfigure/DevToolsDataSourceAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-2017 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. @@ -42,7 +42,6 @@ import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.ConfigurationCondition; import org.springframework.core.type.AnnotatedTypeMetadata; -import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase; import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; @@ -85,12 +84,6 @@ public class DevToolsDataSourceAutoConfiguration { static final class NonEmbeddedInMemoryDatabaseShutdownExecutor implements DisposableBean { - private static final Set IN_MEMORY_DRIVER_CLASS_NAMES = new HashSet( - Arrays.asList("org.apache.derby.jdbc.EmbeddedDriver", "org.h2.Driver", - "org.h2.jdbcx.JdbcDataSource", "org.hsqldb.jdbcDriver", - "org.hsqldb.jdbc.JDBCDriver", - "org.hsqldb.jdbc.pool.JDBCXADataSource")); - private final DataSource dataSource; private final DataSourceProperties dataSourceProperties; @@ -109,9 +102,42 @@ public class DevToolsDataSourceAutoConfiguration { } private boolean dataSourceRequiresShutdown() { - return IN_MEMORY_DRIVER_CLASS_NAMES - .contains(this.dataSourceProperties.determineDriverClassName()) - && (!(this.dataSource instanceof EmbeddedDatabase)); + for (InMemoryDatabase inMemoryDatabase : InMemoryDatabase.values()) { + if (inMemoryDatabase.matches(this.dataSourceProperties)) { + return true; + } + } + return false; + } + + private static enum InMemoryDatabase { + + DERBY(null, "org.apache.derby.jdbc.EmbeddedDriver"), + + H2("jdbc:h2:mem:", "org.h2.Driver", "org.h2.jdbcx.JdbcDataSource"), + + HQSQLDB("jdbc:hsqldb:mem:", "org.hsqldb.jdbcDriver", + "org.hsqldb.jdbc.JDBCDriver", + "org.hsqldb.jdbc.pool.JDBCXADataSource"); + + private final String urlPrefix; + + private final Set driverClassNames; + + InMemoryDatabase(String urlPrefix, String... driverClassNames) { + this.urlPrefix = urlPrefix; + this.driverClassNames = new HashSet( + Arrays.asList(driverClassNames)); + } + + boolean matches(DataSourceProperties properties) { + String url = properties.getUrl(); + return (url == null || this.urlPrefix == null + || url.startsWith(this.urlPrefix)) + && this.driverClassNames + .contains(properties.determineDriverClassName()); + } + } } diff --git a/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/AbstractDevToolsDataSourceAutoConfigurationTests.java b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/AbstractDevToolsDataSourceAutoConfigurationTests.java index 2c7b86aece..33b0bff999 100644 --- a/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/AbstractDevToolsDataSourceAutoConfigurationTests.java +++ b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/AbstractDevToolsDataSourceAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-2017 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. @@ -95,8 +95,17 @@ public abstract class AbstractDevToolsDataSourceAutoConfigurationTests { return statement; } + protected final ConfigurableApplicationContext createContext(Class... classes) { + return this.createContext(null, classes); + } + protected final ConfigurableApplicationContext createContext(String driverClassName, Class... classes) { + return this.createContext(driverClassName, null, classes); + } + + protected final ConfigurableApplicationContext createContext(String driverClassName, + String url, Class... classes) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(classes); context.register(DevToolsDataSourceAutoConfiguration.class); @@ -104,14 +113,13 @@ public abstract class AbstractDevToolsDataSourceAutoConfigurationTests { EnvironmentTestUtils.addEnvironment(context, "spring.datasource.driver-class-name:" + driverClassName); } + if (url != null) { + EnvironmentTestUtils.addEnvironment(context, "spring.datasource.url:" + url); + } context.refresh(); return context; } - protected final ConfigurableApplicationContext createContext(Class... classes) { - return this.createContext(null, classes); - } - @Configuration static class SingleDataSourceConfiguration { diff --git a/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsPooledDataSourceAutoConfigurationTests.java b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsPooledDataSourceAutoConfigurationTests.java index 8d109951c3..043c6b237f 100644 --- a/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsPooledDataSourceAutoConfigurationTests.java +++ b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/autoconfigure/DevToolsPooledDataSourceAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-2017 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. @@ -57,4 +57,70 @@ public class DevToolsPooledDataSourceAutoConfigurationTests verify(statement, times(0)).execute("SHUTDOWN"); } + @Test + public void h2ServerIsNotShutdown() throws SQLException { + ConfigurableApplicationContext context = createContext("org.h2.Driver", + "jdbc:h2:hsql://localhost", DataSourceAutoConfiguration.class, + DataSourceSpyConfiguration.class); + Statement statement = configureDataSourceBehaviour( + context.getBean(DataSource.class)); + context.close(); + verify(statement, times(0)).execute("SHUTDOWN"); + } + + @Test + public void inMemoryh2IsShutdown() throws SQLException { + ConfigurableApplicationContext context = createContext("org.h2.Driver", + "jdbc:h2:mem:test", DataSourceAutoConfiguration.class, + DataSourceSpyConfiguration.class); + Statement statement = configureDataSourceBehaviour( + context.getBean(DataSource.class)); + context.close(); + verify(statement, times(1)).execute("SHUTDOWN"); + } + + @Test + public void hsqlServerIsNotShutdown() throws SQLException { + ConfigurableApplicationContext context = createContext("org.hsqldb.jdbcDriver", + "jdbc:hsqldb:hsql://localhost", DataSourceAutoConfiguration.class, + DataSourceSpyConfiguration.class); + Statement statement = configureDataSourceBehaviour( + context.getBean(DataSource.class)); + context.close(); + verify(statement, times(0)).execute("SHUTDOWN"); + } + + @Test + public void inMemoryHsqlIsShutdown() throws SQLException { + ConfigurableApplicationContext context = createContext("org.hsqldb.jdbcDriver", + "jdbc:hsqldb:mem:test", DataSourceAutoConfiguration.class, + DataSourceSpyConfiguration.class); + Statement statement = configureDataSourceBehaviour( + context.getBean(DataSource.class)); + context.close(); + verify(statement, times(1)).execute("SHUTDOWN"); + } + + @Test + public void derbyClientIsNotShutdown() throws SQLException { + ConfigurableApplicationContext context = createContext( + "org.apache.derby.jdbc.ClientDriver", "jdbc:derby://localhost", + DataSourceAutoConfiguration.class, DataSourceSpyConfiguration.class); + Statement statement = configureDataSourceBehaviour( + context.getBean(DataSource.class)); + context.close(); + verify(statement, times(0)).execute("SHUTDOWN"); + } + + @Test + public void inMemoryDerbyIsShutdown() throws SQLException { + ConfigurableApplicationContext context = createContext( + "org.apache.derby.jdbc.EmbeddedDriver", "jdbc:derby:memory:test", + DataSourceAutoConfiguration.class, DataSourceSpyConfiguration.class); + Statement statement = configureDataSourceBehaviour( + context.getBean(DataSource.class)); + context.close(); + verify(statement, times(1)).execute("SHUTDOWN"); + } + }