From 27c8c6d76d19a8698a42f1d851568b34df8a8ac8 Mon Sep 17 00:00:00 2001 From: Michael Minella Date: Wed, 24 Feb 2016 11:02:33 -0600 Subject: [PATCH] Refactored building of TaskLifecycleListener When using Spring Boot's datasource initialization features, there was the possibility that the datasource used by the TaskLifecycleListener was not ready by the time it was needed for regular injection. This commit addresses that by obtaining the datasource at the last possible moment. Resolves spring-cloud/spring-cloud-task#83 Updates per code review --- .../configuration/DefaultTaskConfigurer.java | 69 +++--- .../SimpleTaskConfiguration.java | 47 ++-- .../support/JdbcTaskExplorerFactoryBean.java | 90 -------- .../JdbcTaskRepositoryFactoryBean.java | 105 --------- .../support/MapTaskExplorerFactoryBean.java | 61 ----- .../support/MapTaskRepositoryFactoryBean.java | 61 ----- .../support/SimpleTaskExplorer.java | 12 +- .../support/SimpleTaskRepository.java | 29 ++- .../support/TaskExecutionDaoFactoryBean.java | 141 ++++++++++++ .../task/configuration/TestConfiguration.java | 38 ++-- .../listener/TaskLifecycleListenerTests.java | 15 +- .../support/SimpleTaskExplorerTests.java | 41 ++-- .../support/SimpleTaskRepositoryMapTests.java | 11 +- .../support/TaskDatabaseInitializerTests.java | 3 +- .../TaskExecutionDaoFactoryBeanTests.java | 214 ++++++++++++++++++ .../TaskRepositoryFactoryBeanTests.java | 57 ----- .../task/util/TestDefaultConfiguration.java | 25 +- 17 files changed, 503 insertions(+), 516 deletions(-) delete mode 100644 spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/JdbcTaskExplorerFactoryBean.java delete mode 100644 spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/JdbcTaskRepositoryFactoryBean.java delete mode 100644 spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/MapTaskExplorerFactoryBean.java delete mode 100644 spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/MapTaskRepositoryFactoryBean.java create mode 100644 spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/TaskExecutionDaoFactoryBean.java create mode 100644 spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/TaskExecutionDaoFactoryBeanTests.java delete mode 100644 spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/TaskRepositoryFactoryBeanTests.java diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/DefaultTaskConfigurer.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/DefaultTaskConfigurer.java index fcd6a486..066773b1 100644 --- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/DefaultTaskConfigurer.java +++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/DefaultTaskConfigurer.java @@ -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. @@ -18,19 +18,15 @@ package org.springframework.cloud.task.configuration; import javax.sql.DataSource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import org.springframework.batch.support.transaction.ResourcelessTransactionManager; import org.springframework.cloud.task.repository.TaskExplorer; import org.springframework.cloud.task.repository.TaskRepository; import org.springframework.cloud.task.repository.dao.JdbcTaskExecutionDao; import org.springframework.cloud.task.repository.dao.MapTaskExecutionDao; -import org.springframework.cloud.task.repository.support.JdbcTaskExplorerFactoryBean; -import org.springframework.cloud.task.repository.support.JdbcTaskRepositoryFactoryBean; -import org.springframework.cloud.task.repository.support.MapTaskExplorerFactoryBean; -import org.springframework.cloud.task.repository.support.MapTaskRepositoryFactoryBean; +import org.springframework.cloud.task.repository.support.SimpleTaskExplorer; import org.springframework.cloud.task.repository.support.SimpleTaskRepository; +import org.springframework.cloud.task.repository.support.TaskExecutionDaoFactoryBean; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager; @@ -45,64 +41,53 @@ import org.springframework.transaction.PlatformTransactionManager; * * * @author Glenn Renfro + * @author Michael Minella */ public class DefaultTaskConfigurer implements TaskConfigurer { - private final static Logger logger = LoggerFactory.getLogger(DefaultTaskConfigurer.class); - - private DataSource dataSource; - private TaskRepository taskRepository; private TaskExplorer taskExplorer; private PlatformTransactionManager transactionManager; - public DefaultTaskConfigurer(){ - initialize(); - } + private ConfigurableApplicationContext context; - public DefaultTaskConfigurer(DataSource dataSource) { - this.dataSource = dataSource; - initialize(); + private TaskExecutionDaoFactoryBean taskExecutionDaoFactoryBean; + + public DefaultTaskConfigurer(ConfigurableApplicationContext context) { + this.context = context; + + this.taskExecutionDaoFactoryBean = new TaskExecutionDaoFactoryBean(this.context); + this.taskRepository = new SimpleTaskRepository(this.taskExecutionDaoFactoryBean); + this.taskExplorer = new SimpleTaskExplorer(this.taskExecutionDaoFactoryBean); } @Override public TaskRepository getTaskRepository() { - return taskRepository; + return this.taskRepository; } @Override public TaskExplorer getTaskExplorer() { - return taskExplorer; + return this.taskExplorer; } @Override public PlatformTransactionManager getTransactionManager() { + if(this.transactionManager == null) { + if(isDataSourceAvailable()) { + this.transactionManager = new DataSourceTransactionManager(this.context.getBean(DataSource.class)); + } + else { + this.transactionManager = new ResourcelessTransactionManager(); + } + } + return this.transactionManager; } - private void initialize(){ - logger.debug("Initializing TaskRepository"); - if (dataSource == null) { - MapTaskRepositoryFactoryBean mapTaskRepositoryFactoryBean = - new MapTaskRepositoryFactoryBean(); - taskRepository = mapTaskRepositoryFactoryBean.getObject(); - MapTaskExplorerFactoryBean mapTaskExplorerFactoryBean = - new MapTaskExplorerFactoryBean(); - taskExplorer = mapTaskExplorerFactoryBean.getObject(); - transactionManager = new ResourcelessTransactionManager(); - - } - else { - JdbcTaskRepositoryFactoryBean jdbcTaskRepositoryFactoryBean = - new JdbcTaskRepositoryFactoryBean(dataSource); - taskRepository = jdbcTaskRepositoryFactoryBean.getObject(); - JdbcTaskExplorerFactoryBean jdbcTaskExplorerFactoryBean = - new JdbcTaskExplorerFactoryBean(dataSource); - taskExplorer = jdbcTaskExplorerFactoryBean.getObject(); - transactionManager = new DataSourceTransactionManager(dataSource); - } + private boolean isDataSourceAvailable() { + return this.context.getBeanNamesForType(DataSource.class).length == 1; } - } diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/SimpleTaskConfiguration.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/SimpleTaskConfiguration.java index 1606f325..ac60b298 100644 --- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/SimpleTaskConfiguration.java +++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/SimpleTaskConfiguration.java @@ -27,11 +27,12 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationArguments; import org.springframework.cloud.task.listener.TaskLifecycleListener; +import org.springframework.cloud.task.repository.TaskExplorer; 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.TaskRepositoryInitializer; -import org.springframework.context.ApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.transaction.PlatformTransactionManager; @@ -52,25 +53,18 @@ public class SimpleTaskConfiguration { protected static final Log logger = LogFactory.getLog(SimpleTaskConfiguration.class); @Autowired - private ApplicationContext context; - - @Autowired(required = false) - private Collection dataSources; + private ConfigurableApplicationContext context; @Autowired(required = false) private ApplicationArguments applicationArguments; private boolean initialized = false; - private TaskRepository taskRepository; - private TaskConfigurer configurer; - private PlatformTransactionManager transactionManager; - @Bean public TaskRepository taskRepository(){ - return taskRepository; + return this.configurer.getTaskRepository(); } @Bean @@ -80,7 +74,12 @@ public class SimpleTaskConfiguration { @Bean public PlatformTransactionManager transactionManager() { - return this.transactionManager; + return this.configurer.getTransactionManager(); + } + + @Bean + public TaskExplorer taskExplorer() { + return this.configurer.getTaskExplorer(); } @Bean @@ -92,16 +91,15 @@ public class SimpleTaskConfiguration { public TaskRepositoryInitializer taskRepositoryInitializer() { TaskRepositoryInitializer taskRepositoryInitializer = new TaskRepositoryInitializer(); - if(this.dataSources != null && this.dataSources.size() == 1) { - taskRepositoryInitializer.setDataSource(this.dataSources.iterator().next()); + if(this.context.getBeanNamesForType(DataSource.class).length == 1) { + taskRepositoryInitializer.setDataSource(context.getBean(DataSource.class)); } 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. + * Determines the {@link TaskConfigurer} to use. */ @PostConstruct protected void initialize() { @@ -114,32 +112,25 @@ public class SimpleTaskConfiguration { } logger.debug(String.format("Using %s TaskConfigurer", configurer.getClass().getName())); - taskRepository = configurer.getTaskRepository(); - transactionManager = configurer.getTransactionManager(); initialized = true; } private TaskConfigurer getDefaultConfigurer(Collection configurers) { - boolean isDataSourceConfigured = (dataSources != null && dataSources.size() == 1); verifyEnvironment(configurers); if (configurers == null || configurers.isEmpty()) { - if (!isDataSourceConfigured) { - this.configurer = new DefaultTaskConfigurer(); - return this.configurer; - } - else { - this.configurer = new DefaultTaskConfigurer(this.dataSources.iterator().next()); - return this.configurer; - } + this.configurer = new DefaultTaskConfigurer(this.context); + return this.configurer; } this.configurer = configurers.iterator().next(); return this.configurer; } private void verifyEnvironment(Collection configurers){ - if (dataSources != null && dataSources.size() > 1) { + int dataSources = this.context.getBeanNamesForType(DataSource.class).length; + + if (dataSources > 1) { throw new IllegalStateException("To use the default TaskConfigurer the context must contain no more than" + - "one DataSource, found " + dataSources.size()); + "one DataSource, found " + dataSources); } if (configurers.size() > 1) { throw new IllegalStateException( diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/JdbcTaskExplorerFactoryBean.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/JdbcTaskExplorerFactoryBean.java deleted file mode 100644 index 81e4a33a..00000000 --- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/JdbcTaskExplorerFactoryBean.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2015 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.cloud.task.repository.support; - -import javax.sql.DataSource; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.cloud.task.repository.TaskExplorer; -import org.springframework.cloud.task.repository.dao.JdbcTaskExecutionDao; -import org.springframework.cloud.task.repository.dao.TaskExecutionDao; - -/** - * Automates the creation of a {@link SimpleTaskExplorer} which will retrieve task - * execution data from a database. - * - * @author Glenn Renfro - */ -public class JdbcTaskExplorerFactoryBean implements FactoryBean{ - - public static final String DEFAULT_TABLE_PREFIX = "TASK_"; - - private static final Log logger = LogFactory.getLog(JdbcTaskExplorerFactoryBean.class); - - private DataSource dataSource; - - private String tablePrefix = DEFAULT_TABLE_PREFIX; - - public JdbcTaskExplorerFactoryBean(){ - - } - - public JdbcTaskExplorerFactoryBean(DataSource dataSource) { - if(dataSource != null) { - this.dataSource = dataSource; - } - } - - /** - * Sets the table prefix for all the task meta-data tables. - * @param tablePrefix prefix prepended to task meta-data tables - */ - public void setTablePrefix(String tablePrefix) { - this.tablePrefix = tablePrefix; - } - - /** - * Returns the a simpleTaskExplorer that utilizes a JdbcTaskExecutionDao - * @return instance of task repository. - */ - public TaskExplorer getObject(){ - TaskExplorer taskExplorer = null; - logger.debug(String.format("Creating SimpleTaskExplorer that will use a %s", - JdbcTaskExecutionDao.class.getName())); - taskExplorer = new SimpleTaskExplorer(createJdbcTaskExecutionDao()); - return taskExplorer; - } - - @Override - public Class getObjectType() { - return TaskExplorer.class; - } - - @Override - public boolean isSingleton() { - return true; - } - - private TaskExecutionDao createJdbcTaskExecutionDao() { - JdbcTaskExecutionDao dao = new JdbcTaskExecutionDao(dataSource); - dao.setTablePrefix(tablePrefix); - return dao; - } - -} diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/JdbcTaskRepositoryFactoryBean.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/JdbcTaskRepositoryFactoryBean.java deleted file mode 100644 index d2bba83a..00000000 --- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/JdbcTaskRepositoryFactoryBean.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2015 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.cloud.task.repository.support; - -import javax.sql.DataSource; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.batch.item.database.support.DataFieldMaxValueIncrementerFactory; -import org.springframework.batch.item.database.support.DefaultDataFieldMaxValueIncrementerFactory; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.cloud.task.repository.TaskRepository; -import org.springframework.cloud.task.repository.dao.JdbcTaskExecutionDao; -import org.springframework.cloud.task.repository.dao.TaskExecutionDao; -import org.springframework.jdbc.support.MetaDataAccessException; - -/** - * Automates the creation of a {@link SimpleTaskRepository} which will persist task - * execution data into a database. Requires the user to describe what kind of database - * they are using. - * - * @author Glenn Renfro - */ -public class JdbcTaskRepositoryFactoryBean implements FactoryBean{ - - public static final String DEFAULT_TABLE_PREFIX = "TASK_"; - - private static final Log logger = LogFactory.getLog(JdbcTaskRepositoryFactoryBean.class); - - private DataSource dataSource; - - private String tablePrefix = DEFAULT_TABLE_PREFIX; - - private DataFieldMaxValueIncrementerFactory incrementerFactory; - - public JdbcTaskRepositoryFactoryBean(){ - - } - - public JdbcTaskRepositoryFactoryBean(DataSource dataSource) { - if(dataSource != null) { - this.dataSource = dataSource; - } - incrementerFactory = new DefaultDataFieldMaxValueIncrementerFactory(dataSource); - } - - /** - * Sets the table prefix for all the task meta-data tables. - * @param tablePrefix prefix prepended to task meta-data tables - */ - public void setTablePrefix(String tablePrefix) { - this.tablePrefix = tablePrefix; - } - - /** - * Returns the a simpleTaskRepository that utilizes a JdbcTaskExecutionDao - * @return instance of task repository. - */ - public TaskRepository getObject(){ - TaskRepository taskRepository = null; - logger.debug(String.format("Creating SimpleTaskRepository that will use a %s", - JdbcTaskExecutionDao.class.getName())); - taskRepository = new SimpleTaskRepository(createJdbcTaskExecutionDao()); - return taskRepository; - } - - @Override - public Class getObjectType() { - return TaskRepository.class; - } - - @Override - public boolean isSingleton() { - return true; - } - - private TaskExecutionDao createJdbcTaskExecutionDao() { - JdbcTaskExecutionDao dao = new JdbcTaskExecutionDao(dataSource); - String databaseType = null; - try { - databaseType = org.springframework.batch.support.DatabaseType.fromMetaData(dataSource).name(); - } - catch (MetaDataAccessException e) { - throw new IllegalStateException(e); - } - dao.setTaskIncrementer(incrementerFactory.getIncrementer(databaseType, tablePrefix + "SEQ")); - dao.setTablePrefix(tablePrefix); - return dao; - } - -} diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/MapTaskExplorerFactoryBean.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/MapTaskExplorerFactoryBean.java deleted file mode 100644 index 83ddd1c7..00000000 --- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/MapTaskExplorerFactoryBean.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2015 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.cloud.task.repository.support; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.cloud.task.repository.TaskExplorer; -import org.springframework.cloud.task.repository.dao.MapTaskExecutionDao; - -/** - * Automates the creation of a {@link SimpleTaskExplorer} which will retrieve task - * execution data from a in-memory map. - * - * @author Glenn Renfro - */ -public class MapTaskExplorerFactoryBean implements FactoryBean{ - - private static final Log logger = LogFactory.getLog(MapTaskExplorerFactoryBean.class); - - public MapTaskExplorerFactoryBean(){ - - } - - /** - * Returns the a simpleTaskExplorer that utilizes a MapTaskExecutionDao - * @return instance of task repository. - */ - public TaskExplorer getObject(){ - TaskExplorer taskExplorer = null; - logger.debug(String.format("Creating SimpleTaskExplorer that will use a %s", - MapTaskExecutionDao.class.getName())); - taskExplorer = new SimpleTaskExplorer(new MapTaskExecutionDao()); - return taskExplorer; - } - - @Override - public Class getObjectType() { - return TaskExplorer.class; - } - - @Override - public boolean isSingleton() { - return true; - } - -} diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/MapTaskRepositoryFactoryBean.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/MapTaskRepositoryFactoryBean.java deleted file mode 100644 index 706e03c2..00000000 --- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/MapTaskRepositoryFactoryBean.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2015 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.cloud.task.repository.support; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.cloud.task.repository.TaskRepository; -import org.springframework.cloud.task.repository.dao.MapTaskExecutionDao; - -/** - * Automates the creation of a {@link SimpleTaskRepository} which will persist task - * execution data into an in memory map. This is meant for development - * purposes and not for production use. - * - * @author Glenn Renfro - */ -public class MapTaskRepositoryFactoryBean implements FactoryBean{ - - private static final Log logger = LogFactory.getLog(MapTaskRepositoryFactoryBean.class); - - private TaskRepository taskRepository; - - public MapTaskRepositoryFactoryBean(){ - logger.debug(String.format("Creating SimpleTaskRepository that will use a %s", - MapTaskExecutionDao.class.getName())); - taskRepository = new SimpleTaskRepository(new MapTaskExecutionDao()); - } - - /** - * Returns the a simpleTaskRepository that utilizes a MapTaskExecutionDao - * @return instance of task repository. - */ - public TaskRepository getObject(){ - return taskRepository; - } - - @Override - public Class getObjectType() { - return TaskRepository.class; - } - - @Override - public boolean isSingleton() { - return true; - } -} diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/SimpleTaskExplorer.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/SimpleTaskExplorer.java index ede0f6a1..55f12b26 100644 --- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/SimpleTaskExplorer.java +++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/SimpleTaskExplorer.java @@ -34,9 +34,15 @@ public class SimpleTaskExplorer implements TaskExplorer{ private TaskExecutionDao taskExecutionDao; - public SimpleTaskExplorer(TaskExecutionDao taskExecutionDao){ - Assert.notNull(taskExecutionDao, "taskExecutionDao must not be null"); - this.taskExecutionDao = taskExecutionDao; + public SimpleTaskExplorer(TaskExecutionDaoFactoryBean taskExecutionDaoFactoryBean) { + Assert.notNull(taskExecutionDaoFactoryBean, "taskExecutionDaoFactoryBean must not be null"); + + try { + this.taskExecutionDao = taskExecutionDaoFactoryBean.getObject(); + } + catch (Exception e) { + throw new IllegalStateException("Unable to create a TaskExecutionDao", e); + } } @Override diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/SimpleTaskRepository.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/SimpleTaskRepository.java index 9fe74b21..8b27b3ca 100644 --- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/SimpleTaskRepository.java +++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/SimpleTaskRepository.java @@ -18,6 +18,8 @@ package org.springframework.cloud.task.repository.support; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + +import org.springframework.beans.factory.FactoryBean; import org.springframework.cloud.task.repository.TaskExecution; import org.springframework.cloud.task.repository.TaskRepository; import org.springframework.cloud.task.repository.dao.TaskExecutionDao; @@ -36,12 +38,20 @@ public class SimpleTaskRepository implements TaskRepository { private TaskExecutionDao taskExecutionDao; - public SimpleTaskRepository(TaskExecutionDao taskExecutionDao){ - this.taskExecutionDao = taskExecutionDao; + private FactoryBean taskExecutionDaoFactoryBean; + + private boolean initialized = false; + + public SimpleTaskRepository(FactoryBean taskExecutionDaoFactoryBean){ + Assert.notNull(taskExecutionDaoFactoryBean, "A FactoryBean that provides a TaskExecutionDao is required"); + + this.taskExecutionDaoFactoryBean = taskExecutionDaoFactoryBean; } @Override public void update(TaskExecution taskExecution) { + initialize(); + validateTaskExecution(taskExecution); taskExecutionDao.updateTaskExecution(taskExecution); logger.info("Updating: " + taskExecution.toString()); @@ -49,6 +59,7 @@ public class SimpleTaskRepository implements TaskRepository { @Override public void createTaskExecution(TaskExecution taskExecution) { + initialize(); validateTaskExecution(taskExecution); taskExecutionDao.saveTaskExecution(taskExecution); logger.info("Creating: " + taskExecution.toString()); @@ -56,6 +67,7 @@ public class SimpleTaskRepository implements TaskRepository { @Override public long getNextExecutionId() { + initialize(); return taskExecutionDao.getNextExecutionId(); } @@ -64,9 +76,22 @@ public class SimpleTaskRepository implements TaskRepository { * @return the taskExecutionDao */ public TaskExecutionDao getTaskExecutionDao() { + initialize(); return taskExecutionDao; } + private void initialize() { + if(!initialized) { + try { + this.taskExecutionDao = this.taskExecutionDaoFactoryBean.getObject(); + this.initialized = true; + } + catch (Exception e) { + throw new IllegalStateException("Unable to create the TaskExecutionDao", e); + } + } + } + /** * Validate TaskExecution. At a minimum a startTime. * diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/TaskExecutionDaoFactoryBean.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/TaskExecutionDaoFactoryBean.java new file mode 100644 index 00000000..11cea9f6 --- /dev/null +++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/TaskExecutionDaoFactoryBean.java @@ -0,0 +1,141 @@ +/* + * Copyright 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.cloud.task.repository.support; + +import javax.sql.DataSource; + +import org.springframework.batch.item.database.support.DataFieldMaxValueIncrementerFactory; +import org.springframework.batch.item.database.support.DefaultDataFieldMaxValueIncrementerFactory; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.cloud.task.repository.dao.JdbcTaskExecutionDao; +import org.springframework.cloud.task.repository.dao.MapTaskExecutionDao; +import org.springframework.cloud.task.repository.dao.TaskExecutionDao; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.jdbc.support.MetaDataAccessException; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * A {@link FactoryBean} implementation that creates the appropriate + * {@link TaskExecutionDao} based on the provided information. + * + * @author Michael Minella + */ +public class TaskExecutionDaoFactoryBean implements FactoryBean { + + public static final String DEFAULT_TABLE_PREFIX = "TASK_"; + + private ConfigurableApplicationContext context; + + private TaskExecutionDao dao = null; + + private String dataSourceName; + + private String tablePrefix = DEFAULT_TABLE_PREFIX; + + /** + * Default constructor will result in a Map based TaskExecutionDao. This is only + * intended for testing purposes. + */ + public TaskExecutionDaoFactoryBean() { + } + + /** + * ApplicationContext provided will be used to obtain the appropriate + * {@link DataSource}. + * + * @param context context for this application + */ + public TaskExecutionDaoFactoryBean(ConfigurableApplicationContext context) { + Assert.notNull(context, "An ApplicationContext is required"); + + this.context = context; + } + + @Override + public TaskExecutionDao getObject() throws Exception { + if(this.dao == null) { + if(this.context != null) { + if (StringUtils.hasText(this.dataSourceName)) { + if(!this.context.containsBean(this.dataSourceName)) { + throw new IllegalArgumentException("The configured dataSourceName is not available in the current context"); + } + + DataSource dataSource = (DataSource) this.context.getBean(this.dataSourceName); + buildTaskExecutionDao(dataSource); + } + else if (this.context.getBeanNamesForType(DataSource.class).length == 1) { + DataSource dataSource = this.context.getBean(DataSource.class); + buildTaskExecutionDao(dataSource); + + } + else { + this.dao = new MapTaskExecutionDao(); + } + } + else { + this.dao = new MapTaskExecutionDao(); + } + } + + return this.dao; + } + + @Override + public Class getObjectType() { + return TaskExecutionDao.class; + } + + @Override + public boolean isSingleton() { + return true; + } + + /** + * Identifies the {@link DataSource} to be used if one is to be used. By default, the + * name is not specified and it is assumed that only one DataSource exists within the + * context. + * + * @param dataSourceName bean id for the DataSource to be used. + */ + public void setDataSourceName(String dataSourceName) { + this.dataSourceName = dataSourceName; + } + + /** + * Indicates a prefix for all of the task repository's tables if the jdbc option is + * used. + * + * @param tablePrefix the string prefix for the task table names + */ + public void setTablePrefix(String tablePrefix) { + this.tablePrefix = tablePrefix; + } + + private void buildTaskExecutionDao(DataSource dataSource) { + DataFieldMaxValueIncrementerFactory incrementerFactory = new DefaultDataFieldMaxValueIncrementerFactory(dataSource); + this.dao = new JdbcTaskExecutionDao(dataSource); + String databaseType; + try { + databaseType = org.springframework.batch.support.DatabaseType.fromMetaData(dataSource).name(); + } + catch (MetaDataAccessException e) { + throw new IllegalStateException(e); + } + ((JdbcTaskExecutionDao) this.dao).setTaskIncrementer(incrementerFactory.getIncrementer(databaseType, this.tablePrefix + "SEQ")); + ((JdbcTaskExecutionDao) this.dao).setTablePrefix(this.tablePrefix); + } +} diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/configuration/TestConfiguration.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/configuration/TestConfiguration.java index 199d4267..3c056d7a 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/configuration/TestConfiguration.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/configuration/TestConfiguration.java @@ -18,15 +18,15 @@ package org.springframework.cloud.task.configuration; import javax.sql.DataSource; import org.springframework.batch.support.transaction.ResourcelessTransactionManager; +import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.task.repository.TaskExplorer; import org.springframework.cloud.task.repository.TaskRepository; -import org.springframework.cloud.task.repository.dao.JdbcTaskExecutionDao; -import org.springframework.cloud.task.repository.dao.MapTaskExecutionDao; -import org.springframework.cloud.task.repository.dao.TaskExecutionDao; import org.springframework.cloud.task.repository.support.SimpleTaskExplorer; import org.springframework.cloud.task.repository.support.SimpleTaskRepository; +import org.springframework.cloud.task.repository.support.TaskExecutionDaoFactoryBean; import org.springframework.cloud.task.repository.support.TaskRepositoryInitializer; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ResourceLoader; @@ -38,7 +38,7 @@ import org.springframework.transaction.PlatformTransactionManager; */ @Configuration -public class TestConfiguration { +public class TestConfiguration implements InitializingBean { @Autowired(required = false) private DataSource dataSource; @@ -46,6 +46,11 @@ public class TestConfiguration { @Autowired(required = false) private ResourceLoader resourceLoader; + @Autowired + private ConfigurableApplicationContext applicationContext; + + private TaskExecutionDaoFactoryBean taskExecutionDaoFactoryBean; + @Bean public TaskRepositoryInitializer taskRepositoryInitializer() throws Exception { TaskRepositoryInitializer taskRepositoryInitializer = new TaskRepositoryInitializer(); @@ -57,8 +62,13 @@ public class TestConfiguration { } @Bean - public TaskRepository taskRepository(TaskExecutionDao taskExecutionDao){ - return new SimpleTaskRepository(taskExecutionDao); + public TaskExplorer taskExplorer() throws Exception { + return new SimpleTaskExplorer(this.taskExecutionDaoFactoryBean); + } + + @Bean + public TaskRepository taskRepository(){ + return new SimpleTaskRepository(this.taskExecutionDaoFactoryBean); } @Bean @@ -71,18 +81,8 @@ public class TestConfiguration { } } - @Bean - public TaskExplorer taskExplorer(TaskExecutionDao taskExecutionDao) { - return new SimpleTaskExplorer(taskExecutionDao); - } - - @Bean - public TaskExecutionDao taskExecutionDao() { - if(dataSource != null) { - return new JdbcTaskExecutionDao(dataSource); - } - else { - return new MapTaskExecutionDao(); - } + @Override + public void afterPropertiesSet() throws Exception { + this.taskExecutionDaoFactoryBean = new TaskExecutionDaoFactoryBean(this.applicationContext); } } diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskLifecycleListenerTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskLifecycleListenerTests.java index 933bd75c..41b1bccd 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskLifecycleListenerTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskLifecycleListenerTests.java @@ -21,9 +21,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -105,15 +103,6 @@ public class TaskLifecycleListenerTests { verifyTaskExecution(0, true, 1, exception); } - private static String stackTraceToString(Throwable exception) { - StringWriter writer = new StringWriter(); - PrintWriter printWriter = new PrintWriter(writer); - - exception.printStackTrace(printWriter); - - return writer.toString(); - } - private void verifyTaskExecution(int numberOfParams, boolean update, Integer exitCode, Throwable exception) { this.taskExplorer = context.getBean(TaskExplorer.class); @@ -195,7 +184,7 @@ public class TaskLifecycleListenerTests { @Override public List getOptionValues(String s) { - return Arrays.asList(this.args.get(s)); + return Collections.singletonList(this.args.get(s)); } @Override diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/SimpleTaskExplorerTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/SimpleTaskExplorerTests.java index d7f5b642..364d5c37 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/SimpleTaskExplorerTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/SimpleTaskExplorerTests.java @@ -16,10 +16,10 @@ package org.springframework.cloud.task.repository.support; -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertNotNull; -import static junit.framework.Assert.assertNull; -import static junit.framework.Assert.assertTrue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.Arrays; @@ -34,8 +34,6 @@ import java.util.Map; import java.util.Set; import java.util.TreeSet; -import javax.sql.DataSource; - import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -51,11 +49,10 @@ import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfigurati import org.springframework.cloud.task.configuration.TestConfiguration; import org.springframework.cloud.task.repository.TaskExecution; import org.springframework.cloud.task.repository.TaskExplorer; -import org.springframework.cloud.task.repository.dao.JdbcTaskExecutionDao; -import org.springframework.cloud.task.repository.dao.TaskExecutionDao; -import org.springframework.cloud.task.util.TestDBUtils; +import org.springframework.cloud.task.repository.TaskRepository; import org.springframework.cloud.task.util.TestVerifierUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Configuration; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -68,14 +65,11 @@ public class SimpleTaskExplorerTests { private AnnotationConfigApplicationContext context; - @Autowired - private TaskExecutionDao dao; - @Autowired private TaskExplorer taskExplorer; - @Autowired(required = false) - private DataSource dataSource; + @Autowired + private TaskRepository taskRepository; private DaoType testType; @@ -95,17 +89,12 @@ public class SimpleTaskExplorerTests { @Before public void testDefaultContext() throws Exception { - if (testType == DaoType.jdbc) { + if (this.testType == DaoType.jdbc) { initializeJdbcExplorerTest(); - dao = new JdbcTaskExecutionDao(dataSource); - ((JdbcTaskExecutionDao)dao). - setTaskIncrementer(TestDBUtils.getIncrementer(dataSource)); } else { initializeMapExplorerTest(); } - - taskExplorer = new SimpleTaskExplorer(dao); } @After @@ -176,7 +165,7 @@ public class SimpleTaskExplorerTests { for (; i < (COMPLETE_COUNT + TEST_COUNT); i++) { TaskExecution expectedTaskExecution = new TaskExecution(i, 0, TASK_NAME, new Date(), null, null, new ArrayList(0)); - dao.saveTaskExecution(expectedTaskExecution); + this.taskRepository.createTaskExecution(expectedTaskExecution); expectedResults.put(expectedTaskExecution.getExecutionId(), expectedTaskExecution); } Pageable pageable = new PageRequest(0, 10); @@ -211,7 +200,7 @@ public class SimpleTaskExplorerTests { for (int i = 0; i < TEST_COUNT; i++) { TaskExecution expectedTaskExecution = TestVerifierUtils.createSampleTaskExecutionNoParam(); expectedTaskExecution.setTaskName(TASK_NAME); - dao.saveTaskExecution(expectedTaskExecution); + this.taskRepository.createTaskExecution(expectedTaskExecution); expectedResults.put(expectedTaskExecution.getExecutionId(), expectedTaskExecution); } @@ -318,7 +307,7 @@ public class SimpleTaskExplorerTests { private TaskExecution createAndSaveTaskExecution(int i) { TaskExecution taskExecution = TestVerifierUtils.createSampleTaskExecution(i); - dao.saveTaskExecution(taskExecution); + this.taskRepository.createTaskExecution(taskExecution); return taskExecution; } @@ -378,4 +367,10 @@ public class SimpleTaskExplorerTests { } private enum DaoType{jdbc, map} + + @Configuration + public static class DataSourceConfiguration{} + + @Configuration + public static class EmptyConfiguration{} } diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/SimpleTaskRepositoryMapTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/SimpleTaskRepositoryMapTests.java index e535ba8c..0e6d28b2 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/SimpleTaskRepositoryMapTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/SimpleTaskRepositoryMapTests.java @@ -27,6 +27,9 @@ import org.springframework.cloud.task.repository.TaskRepository; import org.springframework.cloud.task.repository.dao.MapTaskExecutionDao; import org.springframework.cloud.task.util.TaskExecutionCreator; import org.springframework.cloud.task.util.TestVerifierUtils; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Configuration; /** * Tests for the SimpleTaskRepository that uses Map as a datastore. @@ -38,9 +41,8 @@ public class SimpleTaskRepositoryMapTests { @Before public void setUp() { - MapTaskRepositoryFactoryBean factoryBean = - new MapTaskRepositoryFactoryBean(); - taskRepository = factoryBean.getObject(); + ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(EmptyConfiguration.class); + this.taskRepository = new SimpleTaskRepository(new TaskExecutionDaoFactoryBean(context)); } @Test @@ -80,4 +82,7 @@ public class SimpleTaskRepositoryMapTests { taskMap.containsKey(taskExecutionId)); return taskMap.get(taskExecutionId); } + + @Configuration + public static class EmptyConfiguration{} } diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/TaskDatabaseInitializerTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/TaskDatabaseInitializerTests.java index eba0d539..800d2403 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/TaskDatabaseInitializerTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/TaskDatabaseInitializerTests.java @@ -69,7 +69,8 @@ public class TaskDatabaseInitializerTests { @Test public void testNoDatabase() throws Exception { - SimpleTaskRepository repository = new SimpleTaskRepository(new MapTaskExecutionDao()); + this.context = new AnnotationConfigApplicationContext(EmptyConfiguration.class); + SimpleTaskRepository repository = new SimpleTaskRepository(new TaskExecutionDaoFactoryBean(this.context)); assertThat(repository.getTaskExecutionDao(), instanceOf(MapTaskExecutionDao.class)); MapTaskExecutionDao dao = (MapTaskExecutionDao) repository.getTaskExecutionDao(); assertEquals(0, dao.getTaskExecutions().size()); diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/TaskExecutionDaoFactoryBeanTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/TaskExecutionDaoFactoryBeanTests.java new file mode 100644 index 00000000..7fcb1383 --- /dev/null +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/TaskExecutionDaoFactoryBeanTests.java @@ -0,0 +1,214 @@ +/* + * Copyright 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.cloud.task.repository.support; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import javax.sql.DataSource; + +import org.junit.After; +import org.junit.Test; + +import org.springframework.cloud.task.repository.dao.JdbcTaskExecutionDao; +import org.springframework.cloud.task.repository.dao.MapTaskExecutionDao; +import org.springframework.cloud.task.repository.dao.TaskExecutionDao; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; +import org.springframework.test.util.ReflectionTestUtils; + +/** + * @author Michael Minella + */ +public class TaskExecutionDaoFactoryBeanTests { + + private ConfigurableApplicationContext context; + + @After + public void tearDown() { + if(this.context != null) { + this.context.close(); + } + } + + @Test + public void testGetObjectType() { + assertEquals(new TaskExecutionDaoFactoryBean().getObjectType(), TaskExecutionDao.class); + } + + @Test + public void testIsSingleton() { + assertTrue(new TaskExecutionDaoFactoryBean().isSingleton()); + } + + @Test(expected = IllegalArgumentException.class) + public void testConstructorValidation() { + new TaskExecutionDaoFactoryBean(null); + } + + @Test + public void testMapTaskExecutionDaoWithAppContext() throws Exception { + this.context = new GenericApplicationContext(); + this.context.refresh(); + + TaskExecutionDaoFactoryBean factoryBean = new TaskExecutionDaoFactoryBean(this.context); + TaskExecutionDao taskExecutionDao = factoryBean.getObject(); + + assertTrue(taskExecutionDao instanceof MapTaskExecutionDao); + + TaskExecutionDao taskExecutionDao2 = factoryBean.getObject(); + + assertTrue(taskExecutionDao == taskExecutionDao2); + } + + @Test + public void testMapTaskExecutionDaoWithoutAppContext() throws Exception { + TaskExecutionDaoFactoryBean factoryBean = new TaskExecutionDaoFactoryBean(); + TaskExecutionDao taskExecutionDao = factoryBean.getObject(); + + assertTrue(taskExecutionDao instanceof MapTaskExecutionDao); + + TaskExecutionDao taskExecutionDao2 = factoryBean.getObject(); + + assertTrue(taskExecutionDao == taskExecutionDao2); + } + + @Test + public void testDefaultDataSourceConfiguration() throws Exception { + this.context = new AnnotationConfigApplicationContext(DefaultDataSourceConfiguration.class); + + TaskExecutionDaoFactoryBean factoryBean = new TaskExecutionDaoFactoryBean(this.context); + TaskExecutionDao taskExecutionDao = factoryBean.getObject(); + + assertTrue(taskExecutionDao instanceof JdbcTaskExecutionDao); + + TaskExecutionDao taskExecutionDao2 = factoryBean.getObject(); + + assertTrue(taskExecutionDao == taskExecutionDao2); + } + + @Test + public void testNonDefaultNameDataSourceConfiguration() throws Exception { + this.context = new AnnotationConfigApplicationContext(AlternativeDataSourceConfiguration.class); + + TaskExecutionDaoFactoryBean factoryBean = new TaskExecutionDaoFactoryBean(this.context); + TaskExecutionDao taskExecutionDao = factoryBean.getObject(); + + assertTrue(taskExecutionDao instanceof JdbcTaskExecutionDao); + + TaskExecutionDao taskExecutionDao2 = factoryBean.getObject(); + + assertTrue(taskExecutionDao == taskExecutionDao2); + } + + @Test(expected = IllegalArgumentException.class) + public void testMissingCustomDataSourceNameConfiguration() throws Exception { + ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(AlternativeDataSourceConfiguration.class); + + TaskExecutionDaoFactoryBean factoryBean = new TaskExecutionDaoFactoryBean(context); + factoryBean.setDataSourceName("wrongName"); + factoryBean.getObject(); + } + + @Test + public void testCustomDataSourceNameConfiguration() throws Exception { + this.context = new AnnotationConfigApplicationContext(AlternativeDataSourceConfiguration.class); + + TaskExecutionDaoFactoryBean factoryBean = new TaskExecutionDaoFactoryBean(this.context); + factoryBean.setDataSourceName("notDataSource"); + TaskExecutionDao taskExecutionDao = factoryBean.getObject(); + + assertTrue(taskExecutionDao instanceof JdbcTaskExecutionDao); + + TaskExecutionDao taskExecutionDao2 = factoryBean.getObject(); + + assertTrue(taskExecutionDao == taskExecutionDao2); + } + + @Test + public void testCustomDataSourceNameConfigurationWithMultipleDataSources() throws Exception { + this.context = new AnnotationConfigApplicationContext(MultipleDataSourceConfiguration.class); + + TaskExecutionDaoFactoryBean factoryBean = new TaskExecutionDaoFactoryBean(this.context); + factoryBean.setDataSourceName("useThisDataSource"); + JdbcTaskExecutionDao taskExecutionDao = (JdbcTaskExecutionDao) factoryBean.getObject(); + + Object usedDataSource = ReflectionTestUtils.getField(taskExecutionDao, "dataSource"); + + assertTrue(usedDataSource == this.context.getBean("useThisDataSource")); + + TaskExecutionDao taskExecutionDao2 = factoryBean.getObject(); + + assertTrue(taskExecutionDao == taskExecutionDao2); + } + + @Test + public void testSettingTablePrefix() throws Exception { + this.context = new AnnotationConfigApplicationContext(DefaultDataSourceConfiguration.class); + + TaskExecutionDaoFactoryBean factoryBean = new TaskExecutionDaoFactoryBean(this.context); + factoryBean.setTablePrefix("foo_"); + TaskExecutionDao taskExecutionDao = factoryBean.getObject(); + + assertEquals("foo_", ReflectionTestUtils.getField(taskExecutionDao, "tablePrefix")); + } + + @Configuration + public static class DefaultDataSourceConfiguration { + + @Bean + public DataSource dataSource() { + EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2); + return builder.build(); + } + } + + @Configuration + public static class AlternativeDataSourceConfiguration { + + @Bean + public DataSource notDataSource() { + EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2); + return builder.build(); + } + } + + @Configuration + public static class MultipleDataSourceConfiguration { + + @Bean + public DataSource useThisDataSource() { + EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder() + .setType(EmbeddedDatabaseType.H2) + .setName("useThisDataSource"); + return builder.build(); + } + + @Bean + public DataSource dontUseThisDataSource() { + EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder() + .setType(EmbeddedDatabaseType.H2) + .setName("dontUseThisDataSource"); + return builder.build(); + } + + } +} diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/TaskRepositoryFactoryBeanTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/TaskRepositoryFactoryBeanTests.java deleted file mode 100644 index ae75d841..00000000 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/TaskRepositoryFactoryBeanTests.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2015 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.cloud.task.repository.support; - -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.junit.Assert.assertThat; - -import javax.sql.DataSource; - -import org.junit.Test; -import org.springframework.cloud.task.repository.TaskRepository; -import org.springframework.cloud.task.repository.dao.JdbcTaskExecutionDao; -import org.springframework.cloud.task.repository.dao.MapTaskExecutionDao; -import org.springframework.cloud.task.util.TestDBUtils; - -/** - * Tests that the TaskRepositoryFactoryBeans produce the correct repositories. - * - * @author Glenn Renfro - */ - -public class TaskRepositoryFactoryBeanTests { - - @Test - public void testJdbcTaskRepositoryFactoryBean() throws Exception{ - DataSource dataSource = TestDBUtils.getMockDataSource("HSQL Database Engine"); - JdbcTaskRepositoryFactoryBean factory = new JdbcTaskRepositoryFactoryBean(dataSource); - TaskRepository repository = factory.getObject(); - assertThat(repository, instanceOf(SimpleTaskRepository.class)); - assertThat(((SimpleTaskRepository) repository).getTaskExecutionDao(), - instanceOf(JdbcTaskExecutionDao.class)); - } - - @Test - public void testMapTaskRepositoryFactoryBean() { - MapTaskRepositoryFactoryBean factory = new MapTaskRepositoryFactoryBean(); - TaskRepository repository = factory.getObject(); - assertThat(repository, instanceOf(SimpleTaskRepository.class)); - assertThat(((SimpleTaskRepository) repository).getTaskExecutionDao(), - instanceOf(MapTaskExecutionDao.class)); - } - -} diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestDefaultConfiguration.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestDefaultConfiguration.java index fe1204b4..79aeabb4 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestDefaultConfiguration.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestDefaultConfiguration.java @@ -16,16 +16,18 @@ package org.springframework.cloud.task.util; +import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationArguments; import org.springframework.cloud.task.listener.TaskLifecycleListener; import org.springframework.cloud.task.repository.TaskExplorer; import org.springframework.cloud.task.repository.TaskNameResolver; import org.springframework.cloud.task.repository.TaskRepository; -import org.springframework.cloud.task.repository.dao.MapTaskExecutionDao; import org.springframework.cloud.task.repository.support.SimpleTaskExplorer; import org.springframework.cloud.task.repository.support.SimpleTaskNameResolver; import org.springframework.cloud.task.repository.support.SimpleTaskRepository; +import org.springframework.cloud.task.repository.support.TaskExecutionDaoFactoryBean; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -35,20 +37,27 @@ import org.springframework.context.annotation.Configuration; * @author Glenn Renfro */ @Configuration -public class TestDefaultConfiguration { +public class TestDefaultConfiguration implements InitializingBean { - private MapTaskExecutionDao dao; + private TaskExecutionDaoFactoryBean factoryBean; @Autowired(required = false) private ApplicationArguments applicationArguments; + @Autowired + private ConfigurableApplicationContext context; + public TestDefaultConfiguration() { - this.dao = new MapTaskExecutionDao(); } @Bean public TaskRepository taskRepository(){ - return new SimpleTaskRepository(this.dao); + return new SimpleTaskRepository(this.factoryBean); + } + + @Bean + public TaskExplorer taskExplorer() throws Exception { + return new SimpleTaskExplorer(this.factoryBean); } @Bean @@ -61,8 +70,8 @@ public class TestDefaultConfiguration { return new TaskLifecycleListener(taskRepository(), taskNameResolver(), applicationArguments); } - @Bean - public TaskExplorer taskExplorer() { - return new SimpleTaskExplorer(this.dao); + @Override + public void afterPropertiesSet() throws Exception { + this.factoryBean = new TaskExecutionDaoFactoryBean(this.context); } }