Skip to content

Commit

Permalink
Improve database initializers
Browse files Browse the repository at this point in the history
This commit improves database initializers for Spring Batch and Spring
Session by introducing `AbstractDatabaseInitializer` which eliminates
duplicated logic in existing initializers. Additionally, database
platform resolution now relies on `DatabaseDriver`.

See spring-projectsgh-6543
  • Loading branch information
vpavic authored and snicoll committed Oct 10, 2016
1 parent d2d911b commit 286a928
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 105 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright 2012-2016 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.boot.autoconfigure;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;

import org.springframework.boot.jdbc.DatabaseDriver;
import org.springframework.core.io.ResourceLoader;
import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.util.Assert;

/**
* Abstract base class for database schema initializers.
*
* @author Vedran Pavic
* @since 1.5.0
*/
public abstract class AbstractDatabaseInitializer {

private static final String PLATFORM_PLACEHOLDER = "@@platform@@";

private DataSource dataSource;

private ResourceLoader resourceLoader;

public AbstractDatabaseInitializer(DataSource dataSource, ResourceLoader resourceLoader) {
Assert.notNull(dataSource, "DataSource must not be null");
Assert.notNull(resourceLoader, "ResourceLoader must not be null");
this.dataSource = dataSource;
this.resourceLoader = resourceLoader;
}

@PostConstruct
protected void initialize() {
if (isEnabled()) {
ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
String schemaLocation = getSchemaLocation();
if (schemaLocation.contains(PLATFORM_PLACEHOLDER)) {
String platform = customizeDatabaseName(getDatabaseName());
schemaLocation = schemaLocation.replace(PLATFORM_PLACEHOLDER, platform);
}
populator.addScript(this.resourceLoader.getResource(schemaLocation));
populator.setContinueOnError(true);
DatabasePopulatorUtils.execute(populator, this.dataSource);
}
}

protected abstract boolean isEnabled();

protected abstract String getSchemaLocation();

protected String customizeDatabaseName(String databaseName) {
return databaseName;
}

private String getDatabaseName() {
try {
String databaseProductName = JdbcUtils.extractDatabaseMetaData(
this.dataSource, "getDatabaseProductName").toString();
databaseProductName = JdbcUtils.commonDatabaseName(databaseProductName);
DatabaseDriver databaseDriver = DatabaseDriver.fromProductName(
databaseProductName);
if (databaseDriver == DatabaseDriver.UNKNOWN) {
throw new IllegalStateException("Unable to detect database type");
}
return databaseDriver.toString().toLowerCase();
}
catch (MetaDataAccessException ex) {
throw new IllegalStateException("Unable to detect database type", ex);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.util.StringUtils;

Expand Down Expand Up @@ -77,8 +78,9 @@ public BatchAutoConfiguration(BatchProperties properties,
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(DataSource.class)
public BatchDatabaseInitializer batchDatabaseInitializer() {
return new BatchDatabaseInitializer();
public BatchDatabaseInitializer batchDatabaseInitializer(DataSource dataSource,
ResourceLoader resourceLoader) {
return new BatchDatabaseInitializer(dataSource, resourceLoader, this.properties);
}

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,63 +16,45 @@

package org.springframework.boot.autoconfigure.batch;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;

import org.springframework.batch.support.DatabaseType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AbstractDatabaseInitializer;
import org.springframework.core.io.ResourceLoader;
import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

/**
* Initialize the Spring Batch schema (ignoring errors, so should be idempotent).
*
* @author Dave Syer
* @author Vedran Pavic
*/
@Component
public class BatchDatabaseInitializer {
public class BatchDatabaseInitializer extends AbstractDatabaseInitializer {

@Autowired
private BatchProperties properties;

@Autowired
private DataSource dataSource;
public BatchDatabaseInitializer(DataSource dataSource,
ResourceLoader resourceLoader, BatchProperties properties) {
super(dataSource, resourceLoader);
Assert.notNull(properties, "BatchProperties must not be null");
this.properties = properties;
}

@Autowired
private ResourceLoader resourceLoader;
@Override
protected boolean isEnabled() {
return this.properties.getInitializer().isEnabled();
}

@PostConstruct
protected void initialize() {
if (this.properties.getInitializer().isEnabled()) {
String platform = getDatabaseType();
if ("hsql".equals(platform)) {
platform = "hsqldb";
}
if ("postgres".equals(platform)) {
platform = "postgresql";
}
if ("oracle".equals(platform)) {
platform = "oracle10g";
}
ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
String schemaLocation = this.properties.getSchema();
schemaLocation = schemaLocation.replace("@@platform@@", platform);
populator.addScript(this.resourceLoader.getResource(schemaLocation));
populator.setContinueOnError(true);
DatabasePopulatorUtils.execute(populator, this.dataSource);
}
@Override
protected String getSchemaLocation() {
return this.properties.getSchema();
}

private String getDatabaseType() {
try {
return DatabaseType.fromMetaData(this.dataSource).toString().toLowerCase();
}
catch (MetaDataAccessException ex) {
throw new IllegalStateException("Unable to detect database type", ex);
@Override
protected String customizeDatabaseName(String databaseName) {
if ("oracle".equals(databaseName)) {
return "oracle10g";
}
return databaseName;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ class JdbcSessionConfiguration {
@Bean
@ConditionalOnMissingBean
public JdbcSessionDatabaseInitializer jdbcSessionDatabaseInitializer(
SessionProperties properties, DataSource dataSource,
ResourceLoader resourceLoader) {
return new JdbcSessionDatabaseInitializer(properties, dataSource, resourceLoader);
DataSource dataSource, ResourceLoader resourceLoader,
SessionProperties properties) {
return new JdbcSessionDatabaseInitializer(dataSource, resourceLoader, properties);
}

@Configuration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,10 @@

package org.springframework.boot.autoconfigure.session;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;

import org.springframework.boot.autoconfigure.AbstractDatabaseInitializer;
import org.springframework.core.io.ResourceLoader;
import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.util.Assert;

/**
Expand All @@ -36,64 +28,25 @@
* @author Vedran Pavic
* @since 1.4.0
*/
public class JdbcSessionDatabaseInitializer {

private static Map<String, String> ALIASES;

static {
Map<String, String> aliases = new HashMap<String, String>();
aliases.put("apache derby", "derby");
aliases.put("hsql database engine", "hsqldb");
aliases.put("microsoft sql server", "sqlserver");
ALIASES = Collections.unmodifiableMap(aliases);
}
public class JdbcSessionDatabaseInitializer extends AbstractDatabaseInitializer {

private SessionProperties properties;
private SessionProperties.Jdbc properties;

private DataSource dataSource;

private ResourceLoader resourceLoader;

public JdbcSessionDatabaseInitializer(SessionProperties properties,
DataSource dataSource, ResourceLoader resourceLoader) {
public JdbcSessionDatabaseInitializer(DataSource dataSource,
ResourceLoader resourceLoader, SessionProperties properties) {
super(dataSource, resourceLoader);
Assert.notNull(properties, "SessionProperties must not be null");
Assert.notNull(dataSource, "DataSource must not be null");
Assert.notNull(resourceLoader, "ResourceLoader must not be null");
this.properties = properties;
this.dataSource = dataSource;
this.resourceLoader = resourceLoader;
}

@PostConstruct
protected void initialize() {
if (this.properties.getJdbc().getInitializer().isEnabled()) {
ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
String schemaLocation = this.properties.getJdbc().getSchema();
schemaLocation = schemaLocation.replace("@@platform@@", getPlatform());
populator.addScript(this.resourceLoader.getResource(schemaLocation));
populator.setContinueOnError(true);
DatabasePopulatorUtils.execute(populator, this.dataSource);
}
this.properties = properties.getJdbc();
}

private String getPlatform() {
String databaseName = getDatabaseName();
if (ALIASES.containsKey(databaseName)) {
return ALIASES.get(databaseName);
}
return databaseName;
@Override
protected boolean isEnabled() {
return this.properties.getInitializer().isEnabled();
}

private String getDatabaseName() {
try {
String databaseProductName = JdbcUtils
.extractDatabaseMetaData(this.dataSource, "getDatabaseProductName")
.toString();
return JdbcUtils.commonDatabaseName(databaseProductName).toLowerCase();
}
catch (MetaDataAccessException ex) {
throw new IllegalStateException("Unable to detect database type", ex);
}
@Override
protected String getSchemaLocation() {
return this.properties.getSchema();
}

}

0 comments on commit 286a928

Please sign in to comment.