Refactored database initialization

This commit introduces the `TaskRepositoryInitializer` component.  This
component will initialize the `DataSource` when appropriate and silently do
nothing otherwise.  It can be customized to initialize a specific
`DataSource` as required.

Resolves spring-cloud/spring-cloud-task#84
This commit is contained in:
Michael Minella
2016-02-11 08:28:23 -06:00
parent ff881f6546
commit d8e68d2558
4 changed files with 93 additions and 65 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2015-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.
@@ -25,26 +25,25 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.cloud.task.listener.TaskLifecycleListener;
import org.springframework.cloud.task.repository.TaskNameResolver;
import org.springframework.cloud.task.repository.TaskRepository;
import org.springframework.cloud.task.repository.support.SimpleTaskNameResolver;
import org.springframework.cloud.task.repository.support.TaskDatabaseInitializer;
import org.springframework.cloud.task.repository.support.TaskRepositoryInitializer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* Base {@code Configuration} class providing common structure for enabling and using
* Spring Task. Customization is
* available by implementing the {@link TaskConfigurer} interface.
* Spring Task. Customization is available by implementing the {@link TaskConfigurer}
* interface.
*
* @author Glenn Renfro
* @author Michael Minella
*/
@Configuration
@EnableTransactionManagement
@@ -58,15 +57,9 @@ public class SimpleTaskConfiguration {
@Autowired(required = false)
private Collection<DataSource> dataSources;
@Autowired
private ResourceLoader resourceLoader;
@Autowired(required = false)
private ApplicationArguments applicationArguments;
@Value("${spring.class.initialize.enable:true}")
private boolean taskInitializationEnable;
private boolean initialized = false;
private TaskRepository taskRepository;
@@ -95,6 +88,17 @@ public class SimpleTaskConfiguration {
return new SimpleTaskNameResolver();
}
@Bean
public TaskRepositoryInitializer taskRepositoryInitializer() {
TaskRepositoryInitializer taskRepositoryInitializer = new TaskRepositoryInitializer();
if(this.dataSources != null && this.dataSources.size() == 1) {
taskRepositoryInitializer.setDataSource(this.dataSources.iterator().next());
}
return taskRepositoryInitializer;
}
/**
* Sets up the basic components by extracting them from the {@link TaskConfigurer}, defaulting to some
* sensible values as long as a unique DataSource is available.
@@ -116,7 +120,7 @@ public class SimpleTaskConfiguration {
}
private TaskConfigurer getDefaultConfigurer(Collection<TaskConfigurer> configurers) {
boolean isDataSourceConfigured = (dataSources != null && !dataSources.isEmpty());
boolean isDataSourceConfigured = (dataSources != null && dataSources.size() == 1);
verifyEnvironment(configurers);
if (configurers == null || configurers.isEmpty()) {
if (!isDataSourceConfigured) {
@@ -124,12 +128,7 @@ public class SimpleTaskConfiguration {
return this.configurer;
}
else {
DataSource dataSource = dataSources.iterator().next();
if(taskInitializationEnable) {
logger.debug("Initializing Task Schema");
TaskDatabaseInitializer.initializeDatabase(dataSource, resourceLoader);
}
this.configurer = new DefaultTaskConfigurer(dataSource);
this.configurer = new DefaultTaskConfigurer(this.dataSources.iterator().next());
return this.configurer;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2015-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.
@@ -20,18 +20,32 @@ import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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;
/**
* Utility for initializing the Task Repository's datasource. If a single
* {@link DataSource} is available in the current context, and functionality is enabled
* (as it is by default), this will initialize the database. If more than one DataSource
* is available in the current context, custom configuration of this is required
* (if desired).
*
* By default, initialization of the database can be disabled by configuring the property
* <code>spring.cloud.task.initialize.enable</code> to false.
*
* @author Glenn Renfro
* @author Michael Minella
*/
public final class TaskDatabaseInitializer {
public final class TaskRepositoryInitializer implements InitializingBean {
private static final Log logger = LogFactory.getLog(TaskDatabaseInitializer.class);
private static final Log logger = LogFactory.getLog(TaskRepositoryInitializer.class);
private static final String DEFAULT_SCHEMA_LOCATION = "classpath:org/springframework/"
+ "cloud/task/schema-@@platform@@.sql";
@@ -41,12 +55,37 @@ public final class TaskDatabaseInitializer {
*/
private static String schema = DEFAULT_SCHEMA_LOCATION;
private TaskDatabaseInitializer(){
private DataSource dataSource;
private ResourceLoader resourceLoader;
@Value("${spring.cloud.task.initialize.enable:true}")
private boolean taskInitializationEnable;
public TaskRepositoryInitializer(){
}
public static void initializeDatabase(DataSource dataSource, ResourceLoader resourceLoader) {
if (dataSource != null) {
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
@Autowired(required = false)
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
private String getDatabaseType(DataSource dataSource) {
try {
return DatabaseType.fromMetaData(dataSource).toString().toLowerCase();
}
catch (MetaDataAccessException ex) {
throw new IllegalStateException("Unable to detect database type", ex);
}
}
@Override
public void afterPropertiesSet() throws Exception {
if (dataSource != null && taskInitializationEnable) {
String platform = getDatabaseType(dataSource);
if ("hsql".equals(platform)) {
platform = "hsqldb";
@@ -70,14 +109,4 @@ public final class TaskDatabaseInitializer {
DatabasePopulatorUtils.execute(populator, dataSource);
}
}
private static String getDatabaseType(DataSource dataSource) {
try {
return DatabaseType.fromMetaData(dataSource).toString().toLowerCase();
}
catch (MetaDataAccessException ex) {
throw new IllegalStateException("Unable to detect database type", ex);
}
}
}