From d2bc2530ccf3fbf01286589d021dfc5a7fd020e3 Mon Sep 17 00:00:00 2001 From: Glenn Renfro Date: Thu, 9 Aug 2018 17:54:56 -0400 Subject: [PATCH] Update Task to BOOT 2.1.M1 Migrating to use ApplicationContextRunner or ImportAutoConfiguration with SpringApp.run, instead of SpringApplicationBuilder, because builder does not handle AutoConfiguration properly SimpleTaskAutoConfiguration now has an annotation AutoConfigureBefore the BatchTaskAutoConfig so that it is processed prior. THis is so that that BatchTaskAutoConfig can create the appropriate beans SimpleTaskAutoConfiguration has new annotations so that it is AutoConfigured after BindingServiceConfiguration and after SimpleTaskAutoConfiguration. This is so that it does not attempt to start emitting messages before stream is ready and it can create the appropriate beans after SimpleTaskAutoConfiguration has run. Renamed SimpleTaskConfiguration to SimpleTaskAutoConfiguration. Task version updated to 2.1.0 Added missing headers Updated documentation. Deprecated EnableTask Added ability to disable Task autoconfiguration. Removed @EnableTask from tests Resolves #439 Resolves #440 Resolves #448 Resolves #466 --- README.adoc | 1 - pom.xml | 21 +- spring-cloud-starter-task/pom.xml | 2 +- spring-cloud-task-batch/pom.xml | 14 +- .../configuration/TaskBatchProperties.java | 33 ++- .../TaskJobLauncherAutoConfiguration.java | 27 +- ...bLauncherCommandLineRunnerFactoryBean.java | 21 +- .../TaskJobLauncherCommandLineRunner.java | 273 ++++++++++-------- .../batch/configuration/TaskBatchTest.java | 38 +++ ...TaskJobLauncherAutoConfigurationTests.java | 9 +- ...JobLauncherCommandLineRunnerCoreTests.java | 85 +++++- ...TaskJobLauncherCommandLineRunnerTests.java | 211 +++++++++++--- .../task/batch/listener/PrefixTests.java | 14 +- .../TaskBatchExecutionListenerTests.java | 113 +++----- .../test/resources/META-INF/spring.factories | 6 + spring-cloud-task-core/pom.xml | 8 +- .../cloud/task/configuration/EnableTask.java | 9 +- ....java => SimpleTaskAutoConfiguration.java} | 21 +- .../task/listener/TaskLifecycleListener.java | 35 ++- ...=> TaskListenerExecutorObjectFactory.java} | 55 ++-- .../main/resources/META-INF/spring.factories | 5 +- ...impleSingleTaskAutoConfigurationTests.java | 37 +-- ...kAutoConfigurationWithDataSourceTests.java | 40 ++- .../SimpleTaskAutoConfigurationTests.java | 251 ++++++++++++++++ .../task/SimpleTaskConfigurationTests.java | 194 ------------- .../cloud/task/TaskCoreTests.java | 83 ++++-- ...InitializerDefaultTaskConfigurerTests.java | 4 +- ...alizerNoDataSourceTaskConfigurerTests.java | 5 +- .../configuration/TaskPropertiesTests.java | 36 ++- .../listener/TaskExecutionListenerTests.java | 27 +- ...askListenerExecutorObjectFactoryTests.java | 141 +++++++++ .../SimpleTaskRepositoryJdbcTests.java | 4 +- .../support/TaskDatabaseInitializerTests.java | 6 +- .../task/util/TestDefaultConfiguration.java | 10 +- spring-cloud-task-dependencies/pom.xml | 12 +- spring-cloud-task-docs/pom.xml | 2 +- .../src/main/asciidoc/batch.adoc | 2 +- .../src/main/asciidoc/features.adoc | 14 +- .../src/main/asciidoc/getting-started.adoc | 12 +- .../src/main/asciidoc/stream.adoc | 1 - spring-cloud-task-integration-tests/pom.xml | 6 +- .../java/configuration/JobConfiguration.java | 2 - .../configuration/JobSkipConfiguration.java | 2 - .../executionid/TaskStartApplication.java | 2 - .../cloud/task/listener/TaskEventTests.java | 47 ++- .../batch-events/pom.xml | 13 +- .../spring/cloud/BatchEventsApplication.java | 2 - .../cloud/BatchEventsApplicationTests.java | 8 +- spring-cloud-task-samples/batch-job/pom.xml | 10 +- .../java/io/spring/BatchJobApplication.java | 2 - spring-cloud-task-samples/jpa-sample/pom.xml | 6 +- .../main/java/io/spring/JpaApplication.java | 2 - .../java/io/spring/JpaApplicationTests.java | 4 +- .../multiple-datasources/pom.xml | 6 +- .../MultipleDataSourcesApplication.java | 2 - .../partitioned-batch-job/pom.xml | 6 +- .../main/java/io/spring/JobConfiguration.java | 11 +- .../PartitionedBatchJobApplication.java | 2 - spring-cloud-task-samples/pom.xml | 4 +- spring-cloud-task-samples/task-events/pom.xml | 9 +- .../java/io/spring/TaskEventsApplication.java | 2 - .../taskprocessor/pom.xml | 10 +- spring-cloud-task-samples/tasksink/pom.xml | 10 +- spring-cloud-task-samples/timestamp/pom.xml | 10 +- .../cloud/task/timestamp/TaskApplication.java | 2 - spring-cloud-task-stream/pom.xml | 2 +- .../listener/BatchEventAutoConfiguration.java | 5 +- .../listener/TaskEventAutoConfiguration.java | 14 +- .../listener/JobExecutionEventTests.java | 57 ++-- .../cloud/task/listener/TaskEventTests.java | 42 ++- 70 files changed, 1381 insertions(+), 801 deletions(-) create mode 100644 spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/configuration/TaskBatchTest.java create mode 100644 spring-cloud-task-batch/src/test/resources/META-INF/spring.factories rename spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/{SimpleTaskConfiguration.java => SimpleTaskAutoConfiguration.java} (90%) rename spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/{annotation/TaskListenerExecutorFactoryBean.java => TaskListenerExecutorObjectFactory.java} (74%) create mode 100644 spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleTaskAutoConfigurationTests.java delete mode 100644 spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleTaskConfigurationTests.java create mode 100644 spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskListenerExecutorObjectFactoryTests.java diff --git a/README.adoc b/README.adoc index 6729a9ef..2c083101 100644 --- a/README.adoc +++ b/README.adoc @@ -23,7 +23,6 @@ $ ./mvnw clean install [source,java,indent=2] ---- @SpringBootApplication -@EnableTask public class MyApp { @Bean diff --git a/pom.xml b/pom.xml index 7e424ff4..4a8a3db8 100755 --- a/pom.xml +++ b/pom.xml @@ -5,13 +5,13 @@ org.springframework.cloud spring-cloud-build - 2.0.0.RELEASE + 2.1.0.BUILD-SNAPSHOT org.springframework.cloud spring-cloud-task-parent - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom Spring Cloud Task Build Spring Cloud Task Build @@ -57,7 +57,7 @@ org.springframework.cloud spring-cloud-task-dependencies - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom import @@ -132,15 +132,16 @@ - 2.0.0.RELEASE - 1.3.2.RELEASE - 1.3.5.RELEASE - 2.0.0.RELEASE - 1.3.2.RELEASE - 1.3.2.RELEASE - 4.0.1.RELEASE + 2.1.0.BUILD-SNAPSHOT + 1.3.3.RELEASE + 1.3.6.RELEASE + 2.1.0.BUILD-SNAPSHOT + 1.3.3.RELEASE + 1.3.3.RELEASE + 4.1.0.RELEASE 1.1 8.0 + 5.3.1 UTF-8 ${project.build.directory}/coverage-reports/jacoco-ut.exec diff --git a/spring-cloud-starter-task/pom.xml b/spring-cloud-starter-task/pom.xml index 2d0008ca..9a99b465 100644 --- a/spring-cloud-starter-task/pom.xml +++ b/spring-cloud-starter-task/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-task-parent - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT spring-cloud-starter-task diff --git a/spring-cloud-task-batch/pom.xml b/spring-cloud-task-batch/pom.xml index 2a8d7e86..ab60d4c8 100644 --- a/spring-cloud-task-batch/pom.xml +++ b/spring-cloud-task-batch/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-task-parent - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT spring-cloud-task-batch @@ -50,6 +50,10 @@ spring-test test + + org.springframework.boot + spring-boot-test + junit junit @@ -69,6 +73,7 @@ org.springframework.boot spring-boot-configuration-processor true + ${spring-boot.version} org.assertj @@ -76,8 +81,11 @@ test - org.springframework.boot - spring-boot-test + org.junit.jupiter + junit-jupiter-api + ${junit.version} + test + diff --git a/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskBatchProperties.java b/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskBatchProperties.java index fe7d7755..b3c8de7e 100644 --- a/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskBatchProperties.java +++ b/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskBatchProperties.java @@ -37,12 +37,27 @@ public class TaskBatchProperties { private String jobNames = ""; /** - * The order for the {@coce CommandLineRunner} used to run batch jobs when + * The order for the {@code CommandLineRunner} used to run batch jobs when * {@code spring.cloud.task.batch.fail-on-job-failure=true}. Defaults to 0 (same as the * {@link org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner}). */ private int commandLineRunnerOrder = 0; + /** + * Maximum wait time in milliseconds that Spring Cloud Task will wait for tasks to complete + * when spring.cloud.task.batch.failOnJobFailure is set to true. Defaults + * to 0. 0 indicates no wait time is enforced. + */ + private long failOnJobFailurewaitTime = 0; + + /** + * Fixed delay in milliseconds that Spring Cloud Task will wait when checking if + * {@link org.springframework.batch.core.JobExecution}s have completed, + * when spring.cloud.task.batch.failOnJobFailure is set to true. Defaults + * to 5000. + */ + private long failOnJobFailurePollInterval = 5000l; + public String getJobNames() { return this.jobNames; } @@ -58,4 +73,20 @@ public class TaskBatchProperties { public void setCommandLineRunnerOrder(int commandLineRunnerOrder) { this.commandLineRunnerOrder = commandLineRunnerOrder; } + + public long getFailOnJobFailurewaitTime() { + return failOnJobFailurewaitTime; + } + + public void setFailOnJobFailurewaitTime(long failOnJobFailurewaitTime) { + this.failOnJobFailurewaitTime = failOnJobFailurewaitTime; + } + + public long getFailOnJobFailurePollInterval() { + return failOnJobFailurePollInterval; + } + + public void setFailOnJobFailurePollInterval(long failOnJobFailurePollInterval) { + this.failOnJobFailurePollInterval = failOnJobFailurePollInterval; + } } diff --git a/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherAutoConfiguration.java b/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherAutoConfiguration.java index 71f331ee..e94c9260 100644 --- a/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherAutoConfiguration.java +++ b/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherAutoConfiguration.java @@ -18,11 +18,19 @@ package org.springframework.cloud.task.batch.configuration; import java.util.List; +import javax.sql.DataSource; + import org.springframework.batch.core.Job; import org.springframework.batch.core.configuration.JobRegistry; import org.springframework.batch.core.explore.JobExplorer; import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.repository.support.JobRepositoryFactoryBean; +import org.springframework.batch.core.repository.support.SimpleJobRepository; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -37,22 +45,31 @@ import org.springframework.context.annotation.Configuration; @Configuration @ConditionalOnProperty(name = "spring.cloud.task.batch.fail-on-job-failure", havingValue = "true", matchIfMissing = false) @EnableConfigurationProperties(TaskBatchProperties.class) +@AutoConfigureBefore(BatchAutoConfiguration.class) public class TaskJobLauncherAutoConfiguration { @Autowired private TaskBatchProperties properties; + + @Bean + @ConditionalOnMissingBean(JobRepository.class) + public JobRepository jobRepository(DataSource dataSource) throws Exception{ + JobRepositoryFactoryBean factoryBean = new JobRepositoryFactoryBean(); + factoryBean.setDataSource(dataSource); + return factoryBean.getObject(); + } + @Bean public TaskJobLauncherCommandLineRunnerFactoryBean jobLauncherCommandLineRunner(JobLauncher jobLauncher, - JobExplorer jobExplorer, List jobs, JobRegistry jobRegistry) { + JobExplorer jobExplorer, List jobs, JobRegistry jobRegistry, JobRepository jobRepository) { TaskJobLauncherCommandLineRunnerFactoryBean taskJobLauncherCommandLineRunnerFactoryBean = new TaskJobLauncherCommandLineRunnerFactoryBean(jobLauncher, jobExplorer, jobs, - this.properties.getJobNames(), - jobRegistry); - - taskJobLauncherCommandLineRunnerFactoryBean.setOrder(this.properties.getCommandLineRunnerOrder()); + this.properties, + jobRegistry, + jobRepository); return taskJobLauncherCommandLineRunnerFactoryBean; } diff --git a/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherCommandLineRunnerFactoryBean.java b/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherCommandLineRunnerFactoryBean.java index f5df4c50..1a658d52 100644 --- a/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherCommandLineRunnerFactoryBean.java +++ b/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherCommandLineRunnerFactoryBean.java @@ -22,6 +22,7 @@ import org.springframework.batch.core.Job; import org.springframework.batch.core.configuration.JobRegistry; import org.springframework.batch.core.explore.JobExplorer; import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.core.repository.JobRepository; import org.springframework.beans.factory.FactoryBean; import org.springframework.cloud.task.batch.handler.TaskJobLauncherCommandLineRunner; import org.springframework.util.Assert; @@ -46,15 +47,23 @@ public class TaskJobLauncherCommandLineRunnerFactoryBean implements FactoryBean< private Integer order = 0; + private TaskBatchProperties taskBatchProperties; + + private JobRepository jobRepository; + public TaskJobLauncherCommandLineRunnerFactoryBean(JobLauncher jobLauncher, - JobExplorer jobExplorer, List jobs, String jobNames, - JobRegistry jobRegistry) { + JobExplorer jobExplorer, List jobs, TaskBatchProperties taskBatchProperties, + JobRegistry jobRegistry, JobRepository jobRepository) { + Assert.notNull(taskBatchProperties, "properties must not be null"); this.jobLauncher = jobLauncher; this.jobExplorer = jobExplorer; Assert.notEmpty(jobs, "jobs must not be null nor empty"); this.jobs = jobs; - this.jobNames = jobNames; + this.jobNames = taskBatchProperties.getJobNames(); this.jobRegistry = jobRegistry; + this.taskBatchProperties = taskBatchProperties; + this.order = taskBatchProperties.getCommandLineRunnerOrder(); + this.jobRepository = jobRepository; } public void setOrder(int order) { @@ -62,9 +71,9 @@ public class TaskJobLauncherCommandLineRunnerFactoryBean implements FactoryBean< } @Override - public TaskJobLauncherCommandLineRunner getObject() throws Exception { + public TaskJobLauncherCommandLineRunner getObject() { TaskJobLauncherCommandLineRunner taskJobLauncherCommandLineRunner = - new TaskJobLauncherCommandLineRunner(this.jobLauncher, this.jobExplorer); + new TaskJobLauncherCommandLineRunner(this.jobLauncher, this.jobExplorer, this.jobRepository, this.taskBatchProperties); taskJobLauncherCommandLineRunner.setJobs(this.jobs); if(StringUtils.hasText(this.jobNames)) { taskJobLauncherCommandLineRunner.setJobNames(this.jobNames); @@ -74,7 +83,6 @@ public class TaskJobLauncherCommandLineRunnerFactoryBean implements FactoryBean< if(this.order != null) { taskJobLauncherCommandLineRunner.setOrder(this.order); } - return taskJobLauncherCommandLineRunner; } @@ -82,4 +90,5 @@ public class TaskJobLauncherCommandLineRunnerFactoryBean implements FactoryBean< public Class getObjectType() { return TaskJobLauncherCommandLineRunner.class; } + } diff --git a/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherCommandLineRunner.java b/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherCommandLineRunner.java index fb3c54a7..3f8a3cf8 100644 --- a/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherCommandLineRunner.java +++ b/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherCommandLineRunner.java @@ -16,177 +16,218 @@ package org.springframework.cloud.task.batch.handler; +import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; -import java.util.Properties; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.batch.core.ExitStatus; +import org.springframework.batch.core.BatchStatus; import org.springframework.batch.core.Job; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobExecutionException; +import org.springframework.batch.core.JobParameter; import org.springframework.batch.core.JobParameters; import org.springframework.batch.core.JobParametersBuilder; +import org.springframework.batch.core.JobParametersIncrementer; import org.springframework.batch.core.JobParametersInvalidException; -import org.springframework.batch.core.configuration.JobRegistry; -import org.springframework.batch.core.converter.DefaultJobParametersConverter; -import org.springframework.batch.core.converter.JobParametersConverter; import org.springframework.batch.core.explore.JobExplorer; import org.springframework.batch.core.launch.JobLauncher; -import org.springframework.batch.core.launch.JobParametersNotFoundException; -import org.springframework.batch.core.launch.NoSuchJobException; import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException; import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException; +import org.springframework.batch.core.repository.JobRepository; import org.springframework.batch.core.repository.JobRestartException; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.batch.repeat.RepeatCallback; +import org.springframework.batch.repeat.RepeatContext; +import org.springframework.batch.repeat.RepeatStatus; +import org.springframework.batch.repeat.support.RepeatTemplate; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.autoconfigure.batch.JobExecutionEvent; +import org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner; +import org.springframework.cloud.task.batch.configuration.TaskBatchProperties; import org.springframework.cloud.task.listener.TaskException; import org.springframework.context.ApplicationEventPublisher; -import org.springframework.context.ApplicationEventPublisherAware; -import org.springframework.core.Ordered; -import org.springframework.util.PatternMatchUtils; +import org.springframework.core.task.TaskExecutor; import org.springframework.util.StringUtils; /** * {@link CommandLineRunner} to {@link JobLauncher launch} Spring Batch jobs. Runs all - * jobs in the surrounding context by default and throw an exception upon the - * first job that returns an {@link ExitStatus} of FAILED. - * Can also be used to launch a specific job by providing a jobName. The - * TaskJobLaunchercommandLineRunner takes the place of the - * {@link org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner} - * when it is in use. + * jobs in the surrounding context by default and throws an exception upon the first job + * that returns an {@link BatchStatus} of FAILED if a {@link TaskExecutor} in the + * {@link JobLauncher} is not specified. If a {@link TaskExecutor} is specified + * in the {@link JobLauncher} then all Jobs are launched and an + * exception is thrown if one or more of the jobs has an {@link BatchStatus} of FAILED. + * TaskJobLauncherCommandLineRunner can also be used to launch a specific job by + * providing a jobName. The TaskJobLaunchercommandLineRunner takes the place of the + * {@link org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner} when + * it is in use. * * @author Glenn Renfro * @since 2.0.0 */ -public class TaskJobLauncherCommandLineRunner implements CommandLineRunner, Ordered, ApplicationEventPublisherAware{ - /** - * The default order for the command line runner. - */ - public static final int DEFAULT_ORDER = 0; +public class TaskJobLauncherCommandLineRunner extends JobLauncherCommandLineRunner { + + private JobLauncher taskJobLauncher; + + private JobExplorer taskJobExplorer; + + private JobRepository taskJobRepository; private static final Log logger = LogFactory .getLog(TaskJobLauncherCommandLineRunner.class); - private JobParametersConverter converter = new DefaultJobParametersConverter(); + private List jobExecutionList = new ArrayList<>(); - private JobLauncher jobLauncher; + private ApplicationEventPublisher taskApplicationEventPublisher; - private JobRegistry jobRegistry; + private TaskBatchProperties taskBatchProperties; - private JobExplorer jobExplorer; - - private String jobNames; - - private Collection jobs = Collections.emptySet(); - - private int order = DEFAULT_ORDER; - - private ApplicationEventPublisher publisher; - - public TaskJobLauncherCommandLineRunner(JobLauncher jobLauncher, - JobExplorer jobExplorer) { - this.jobLauncher = jobLauncher; - this.jobExplorer = jobExplorer; + /** + * Create a new {@link TaskJobLauncherCommandLineRunner}. + * @param jobLauncher to launch jobs + * @param jobExplorer to check the job repository for previous executions + * @param jobRepository to check if a job instance exists with the given parameters + * when running a job + * @param taskBatchProperties the properties used to configure the taskBatchProperties. + */ + public TaskJobLauncherCommandLineRunner(JobLauncher jobLauncher, JobExplorer jobExplorer, + JobRepository jobRepository, TaskBatchProperties taskBatchProperties) { + super(jobLauncher, jobExplorer, jobRepository); + this.taskJobLauncher = jobLauncher; + this.taskJobExplorer = jobExplorer; + this.taskJobRepository = jobRepository; + this.taskBatchProperties = taskBatchProperties; } - public void setOrder(int order) { - this.order = order; - } - - @Override - public int getOrder() { - return this.order; - } - - @Override public void setApplicationEventPublisher(ApplicationEventPublisher publisher) { - this.publisher = publisher; - } - - public void setJobRegistry(JobRegistry jobRegistry) { - this.jobRegistry = jobRegistry; - } - - public void setJobNames(String jobNames) { - this.jobNames = jobNames; - } - - public void setJobParametersConverter(JobParametersConverter converter) { - this.converter = converter; - } - - public void setJobs(Collection jobs) { - this.jobs = jobs; + super.setApplicationEventPublisher(publisher); + this.taskApplicationEventPublisher = publisher; } @Override public void run(String... args) throws JobExecutionException { logger.info("Running default command line with: " + Arrays.asList(args)); launchJobFromProperties(StringUtils.splitArrayElementsIntoProperties(args, "=")); - } - - protected void launchJobFromProperties(Properties properties) - throws JobExecutionException { - JobParameters jobParameters = this.converter.getJobParameters(properties); - executeLocalJobs(jobParameters); - executeRegisteredJobs(jobParameters); - } - - private void executeRegisteredJobs(JobParameters jobParameters) - throws JobExecutionException { - if (this.jobRegistry != null && StringUtils.hasText(this.jobNames)) { - String[] jobsToRun = this.jobNames.split(","); - for (String jobName : jobsToRun) { - try { - Job job = this.jobRegistry.getJob(jobName); - if (this.jobs.contains(job)) { - continue; - } - execute(job, jobParameters); - } - catch (NoSuchJobException ex) { - logger.debug("No job found in registry for job name: " + jobName); - } - } - } + validateJobExecutions(); } protected void execute(Job job, JobParameters jobParameters) throws JobExecutionAlreadyRunningException, JobRestartException, - JobInstanceAlreadyCompleteException, JobParametersInvalidException, - JobParametersNotFoundException { - JobParameters nextParameters = new JobParametersBuilder(jobParameters, - this.jobExplorer).getNextJobParameters(job).toJobParameters(); - JobExecution execution = this.jobLauncher.run(job, nextParameters); - if (this.publisher != null) { - this.publisher.publishEvent(new JobExecutionEvent(execution)); + JobInstanceAlreadyCompleteException, JobParametersInvalidException { + String jobName = job.getName(); + JobParameters parameters = jobParameters; + boolean jobInstanceExists = this.taskJobRepository.isJobInstanceExists(jobName, + parameters); + if (jobInstanceExists) { + JobExecution lastJobExecution = this.taskJobRepository + .getLastJobExecution(jobName, jobParameters); + if (lastJobExecution != null && isStoppedOrFailed(lastJobExecution) + && job.isRestartable()) { + // Retry a failed or stopped execution with previous parameters + JobParameters previousParameters = lastJobExecution.getJobParameters(); + /* + * remove Non-identifying parameters from the previous execution's + * parameters since there is no way to remove them programmatically. If + * they are required (or need to be modified) on a restart, they need to + * be (re)specified. + */ + JobParameters previousIdentifyingParameters = removeNonIdentifying( + previousParameters); + // merge additional parameters with previous ones (overriding those with + // the same key) + parameters = merge(previousIdentifyingParameters, jobParameters); + } } - if(execution.getExitStatus().getExitCode().equals(ExitStatus.FAILED.getExitCode())) { - String message = String.format("Job %s failed during " + - "execution for jobId %s with jobExecutionId of %s", - execution.getJobInstance().getJobName(), - execution.getJobId(), execution.getId()); - logger.error(message); - throw new TaskException(message); + else { + JobParametersIncrementer incrementer = job.getJobParametersIncrementer(); + if (incrementer != null) { + JobParameters nextParameters = new JobParametersBuilder(jobParameters, + this.taskJobExplorer).getNextJobParameters(job).toJobParameters(); + parameters = merge(nextParameters, jobParameters); + } + } + JobExecution execution = this.taskJobLauncher.run(job, parameters); + if (this.taskApplicationEventPublisher != null) { + this.taskApplicationEventPublisher.publishEvent(new JobExecutionEvent(execution)); + } + this.jobExecutionList.add(execution); + if (execution.getStatus().equals(BatchStatus.FAILED)) { + throwJobFailedException(Collections.singletonList(execution)); } } - private void executeLocalJobs(JobParameters jobParameters) - throws JobExecutionException { - for (Job job : this.jobs) { - if (StringUtils.hasText(this.jobNames)) { - String[] jobsToRun = this.jobNames.split(","); - if (!PatternMatchUtils.simpleMatch(jobsToRun, job.getName())) { - logger.debug("Skipped job: " + job.getName()); - continue; + private void validateJobExecutions() { + RepeatTemplate template = new RepeatTemplate(); + + Date startDate = new Date(); + + template.iterate(new RepeatCallback() { + + public RepeatStatus doInIteration(RepeatContext context) throws InterruptedException { + List failedJobExecutions = new ArrayList<>(); + RepeatStatus repeatStatus = RepeatStatus.FINISHED; + for (JobExecution jobExecution : jobExecutionList) { + JobExecution currentJobExecution = taskJobExplorer.getJobExecution(jobExecution.getId()); + BatchStatus batchStatus = currentJobExecution.getStatus(); + if (batchStatus.isRunning()) { + repeatStatus = RepeatStatus.CONTINUABLE; + } + if (batchStatus.equals(BatchStatus.FAILED)) { + failedJobExecutions.add(jobExecution); + } } + Thread.sleep(taskBatchProperties.getFailOnJobFailurePollInterval()); + + if (repeatStatus.equals(RepeatStatus.FINISHED) && failedJobExecutions.size() > 0) { + throwJobFailedException(failedJobExecutions); + } + if (repeatStatus.isContinuable() && taskBatchProperties.getFailOnJobFailurewaitTime() != 0 + && (new Date()).getTime() - startDate.getTime() > taskBatchProperties.getFailOnJobFailurewaitTime()) { + throw new IllegalStateException("Not all jobs were completed " + + "within the time specified by spring.cloud.task.batch." + + "failOnJobFailurewaitTime."); + } + return repeatStatus; } - execute(job, jobParameters); + + }); + } + + public void throwJobFailedException(List failedJobExecutions) { + String message = "The following Jobs have failed: \n"; + for (JobExecution failedJobExecution : failedJobExecutions) { + message += String.format("Job %s failed during " + + "execution for jobId %s with jobExecutionId of %s \n", + failedJobExecution.getJobInstance().getJobName(), + failedJobExecution.getJobId(), failedJobExecution.getId()); } + logger.error(message); + throw new TaskException(message); + + } + private JobParameters removeNonIdentifying(JobParameters parameters) { + Map parameterMap = parameters.getParameters(); + HashMap copy = new HashMap<>(parameterMap); + for (Map.Entry parameter : copy.entrySet()) { + if (!parameter.getValue().isIdentifying()) { + parameterMap.remove(parameter.getKey()); + } + } + return new JobParameters(parameterMap); + } + private boolean isStoppedOrFailed(JobExecution execution) { + BatchStatus status = execution.getStatus(); + return (status == BatchStatus.STOPPED || status == BatchStatus.FAILED); + } + private JobParameters merge(JobParameters parameters, JobParameters additionals) { + Map merged = new HashMap<>(); + merged.putAll(parameters.getParameters()); + merged.putAll(additionals.getParameters()); + return new JobParameters(merged); } } diff --git a/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/configuration/TaskBatchTest.java b/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/configuration/TaskBatchTest.java new file mode 100644 index 00000000..e5797cb0 --- /dev/null +++ b/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/configuration/TaskBatchTest.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018 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.batch.configuration; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; + +/** + * Contains the common configurations to run a unit test for the task batch features of + * SCT. + * + * @author Glenn Renfro + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@ImportAutoConfiguration +public @interface TaskBatchTest { +} diff --git a/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherAutoConfigurationTests.java b/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherAutoConfigurationTests.java index f8f1c8c2..9d7ecd2f 100644 --- a/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherAutoConfigurationTests.java +++ b/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherAutoConfigurationTests.java @@ -42,13 +42,10 @@ public class TaskJobLauncherAutoConfigurationTests { @Test public void testAutoBuiltDataSourceWithTaskJobLauncherCLR() { - this.contextRunner. - withPropertyValues("spring.cloud.task.batch.fail-on-job-failure=true"). - run(context -> { + this.contextRunner.withPropertyValues("spring.cloud.task.batch.fail-on-job-failure=true").run(context -> { assertThat(context).hasSingleBean(TaskJobLauncherCommandLineRunner.class); - assertThat(context).doesNotHaveBean(JobLauncherCommandLineRunner.class); - assertThat(context.getBean(TaskJobLauncherCommandLineRunner.class) - .getOrder()) + assertThat(context.getBean(TaskJobLauncherCommandLineRunner.class) + .getOrder()) .isEqualTo(0); }); } diff --git a/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherCommandLineRunnerCoreTests.java b/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherCommandLineRunnerCoreTests.java index 38cd20a8..9d62b9a9 100644 --- a/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherCommandLineRunnerCoreTests.java +++ b/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherCommandLineRunnerCoreTests.java @@ -16,11 +16,16 @@ package org.springframework.cloud.task.batch.handler; + +import org.assertj.core.api.AssertionsForClassTypes; import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.function.Executable; import org.junit.runner.RunWith; import org.springframework.batch.core.Job; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobInstance; import org.springframework.batch.core.JobParameters; import org.springframework.batch.core.JobParametersBuilder; import org.springframework.batch.core.Step; @@ -34,10 +39,12 @@ import org.springframework.batch.core.launch.JobLauncher; import org.springframework.batch.core.launch.support.RunIdIncrementer; import org.springframework.batch.core.launch.support.SimpleJobLauncher; import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.repository.JobRestartException; import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean; import org.springframework.batch.core.step.tasklet.Tasklet; import org.springframework.batch.support.transaction.ResourcelessTransactionManager; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.task.batch.configuration.TaskBatchProperties; import org.springframework.cloud.task.listener.TaskException; import org.springframework.context.annotation.Configuration; import org.springframework.core.task.SyncTaskExecutor; @@ -47,6 +54,7 @@ import org.springframework.test.context.junit4.SpringRunner; import org.springframework.transaction.PlatformTransactionManager; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; /** * @author Glenn Renfro @@ -64,6 +72,9 @@ public class TaskJobLauncherCommandLineRunnerCoreTests { @Autowired private JobExplorer jobExplorer; + @Autowired + private BatchConfiguration batchConfigurer; + @Autowired private PlatformTransactionManager transactionManager; @@ -79,12 +90,14 @@ public class TaskJobLauncherCommandLineRunnerCoreTests { @Before public void init() { + batchConfigurer.clear(); this.jobs = new JobBuilderFactory(this.jobRepository); this.steps = new StepBuilderFactory(this.jobRepository, this.transactionManager); Tasklet tasklet = (contribution, chunkContext) -> null; this.step = this.steps.get("step").tasklet(tasklet).build(); this.job = this.jobs.get("job").start(this.step).build(); - this.runner = new TaskJobLauncherCommandLineRunner(this.jobLauncher, this.jobExplorer); + this.runner = new TaskJobLauncherCommandLineRunner(this.jobLauncher, this.jobExplorer, jobRepository, new TaskBatchProperties()); + } @@ -115,10 +128,27 @@ public class TaskJobLauncherCommandLineRunnerCoreTests { .start(this.steps.get("step").tasklet(throwingTasklet()).build()) .incrementer(new RunIdIncrementer()).build(); runFailedJob(new JobParameters()); - runFailedJob(new JobParameters()); + runFailedJob(new JobParametersBuilder().addLong("run.id", 1L).toJobParameters()); assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(1); } + @Test + public void runDifferentInstances() throws Exception { + this.job = this.jobs.get("job") + .start(this.steps.get("step").tasklet(throwingTasklet()).build()).build(); + // start a job instance + JobParameters jobParameters = new JobParametersBuilder().addString("name", "foo") + .toJobParameters(); + runFailedJob(jobParameters); + assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(1); + // start a different job instance + JobParameters otherJobParameters = new JobParametersBuilder() + .addString("name", "bar").toJobParameters(); + runFailedJob(otherJobParameters); + assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(2); + } + + @DirtiesContext @Test public void retryFailedExecutionOnNonRestartableJob() throws Exception { @@ -130,6 +160,15 @@ public class TaskJobLauncherCommandLineRunnerCoreTests { // A failed job that is not restartable does not re-use the job params of // the last execution, but creates a new job instance when running it again. assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(2); + + // try to re-run a failed execution + Executable executable = () -> { + this.runner.execute(this.job, + new JobParametersBuilder().addLong("run.id", 1L).toJobParameters()); + }; + Throwable exception = assertThrows(JobRestartException.class, executable); + AssertionsForClassTypes.assertThat(exception.getMessage()) + .isEqualTo("JobInstance already exists and is not restartable"); } @DirtiesContext @@ -140,11 +179,47 @@ public class TaskJobLauncherCommandLineRunnerCoreTests { .incrementer(new RunIdIncrementer()).build(); JobParameters jobParameters = new JobParametersBuilder().addLong("id", 1L, false) .addLong("foo", 2L, false).toJobParameters(); - runFailedJob(new JobParameters()); - runFailedJob(new JobParameters()); + runFailedJob(jobParameters); + assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(1); + runFailedJob(new JobParametersBuilder(jobParameters) + .addLong("run.id", 1L).toJobParameters()); assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(1); } + + @Test + public void retryFailedExecutionWithDifferentNonIdentifyingParametersFromPreviousExecution() + throws Exception { + this.job = this.jobs.get("job") + .start(this.steps.get("step").tasklet(throwingTasklet()).build()) + .incrementer(new RunIdIncrementer()).build(); + JobParameters jobParameters = new JobParametersBuilder().addLong("id", 1L, false) + .addLong("foo", 2L, false).toJobParameters(); + runFailedJob(jobParameters); + assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(1); + // try to re-run a failed execution with non identifying parameters + runFailedJob( new JobParametersBuilder().addLong("run.id", 1L) + .addLong("id", 2L, false).addLong("foo", 3L, false).toJobParameters()); + assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(1); + JobInstance jobInstance = this.jobExplorer.getJobInstance(0L); + assertThat(this.jobExplorer.getJobExecutions(jobInstance)).hasSize(2); + // first execution + JobExecution firstJobExecution = this.jobExplorer.getJobExecution(0L); + JobParameters parameters = firstJobExecution.getJobParameters(); + assertThat(parameters.getLong("run.id")).isEqualTo(1L); + assertThat(parameters.getLong("id")).isEqualTo(1L); + assertThat(parameters.getLong("foo")).isEqualTo(2L); + // second execution + JobExecution secondJobExecution = this.jobExplorer.getJobExecution(1L); + parameters = secondJobExecution.getJobParameters(); + // identifying parameters should be the same as previous execution + assertThat(parameters.getLong("run.id")).isEqualTo(1L); + // non-identifying parameters should be the newly specified ones + assertThat(parameters.getLong("id")).isEqualTo(2L); + assertThat(parameters.getLong("foo")).isEqualTo(3L); + } + + private Tasklet throwingTasklet() { return (contribution, chunkContext) -> { throw new RuntimeException("Planned"); @@ -154,7 +229,7 @@ public class TaskJobLauncherCommandLineRunnerCoreTests { private void runFailedJob(JobParameters jobParameters) throws Exception { boolean isExceptionThrown = false; try { - this.runner.execute(this.job, new JobParameters()); + this.runner.execute(this.job, jobParameters); } catch (TaskException taskException) { isExceptionThrown = true; diff --git a/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherCommandLineRunnerTests.java b/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherCommandLineRunnerTests.java index 31e89939..96a155fb 100644 --- a/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherCommandLineRunnerTests.java +++ b/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherCommandLineRunnerTests.java @@ -18,36 +18,49 @@ package org.springframework.cloud.task.batch.handler; import java.util.Set; +import javax.sql.DataSource; + import org.junit.After; import org.junit.Test; +import org.junit.jupiter.api.function.Executable; import org.springframework.batch.core.Job; import org.springframework.batch.core.StepContribution; +import org.springframework.batch.core.configuration.annotation.BatchConfigurer; +import org.springframework.batch.core.configuration.annotation.DefaultBatchConfigurer; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.core.launch.support.SimpleJobLauncher; import org.springframework.batch.core.scope.context.ChunkContext; import org.springframework.batch.core.step.tasklet.Tasklet; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration; import org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; import org.springframework.cloud.task.batch.configuration.TaskBatchAutoConfiguration; import org.springframework.cloud.task.batch.configuration.TaskJobLauncherAutoConfiguration; +import org.springframework.cloud.task.batch.configuration.TaskBatchTest; import org.springframework.cloud.task.configuration.EnableTask; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; +import org.springframework.cloud.task.configuration.SingleTaskConfiguration; import org.springframework.cloud.task.repository.TaskExecution; import org.springframework.cloud.task.repository.TaskExplorer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; +import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor; import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; /** * @author Glenn Renfro @@ -56,6 +69,9 @@ public class TaskJobLauncherCommandLineRunnerTests { private ConfigurableApplicationContext applicationContext; + private static final String DEFAULT_ERROR_MESSAGE = "The following Jobs have failed: \n" + + "Job jobA failed during execution for jobId 1 with jobExecutionId of 1 \n"; + @After public void tearDown() { if (this.applicationContext != null) { @@ -65,37 +81,55 @@ public class TaskJobLauncherCommandLineRunnerTests { @Test public void testTaskJobLauncherCLRSuccessFail() { - String[] enabledArgs = new String[] { "--spring.cloud.task.batch.fail-on-job-failure=true" }; - boolean isExceptionThrown = false; - try { - this.applicationContext = SpringApplication - .run(new Class[] { TaskJobLauncherCommandLineRunnerTests.JobWithFailureConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - EmbeddedDataSourceConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class, - TaskJobLauncherAutoConfiguration.class }, enabledArgs); - } - catch (IllegalStateException exception) { - isExceptionThrown = true; - } - assertThat(isExceptionThrown).isTrue(); + String[] enabledArgs = new String[] { + "--spring.cloud.task.batch.failOnJobFailure=true"}; + validateForFail(DEFAULT_ERROR_MESSAGE, TaskJobLauncherCommandLineRunnerTests.JobWithFailureConfiguration.class, + enabledArgs); + } + + /** + * Verifies that the task will return an exit code other than zero if the + * job fails with the deprecated EnableTask annotation. + */ + @Test + public void testTaskJobLauncherCLRSuccessFailWithAnnotation() { + String[] enabledArgs = new String[] { + "--spring.cloud.task.batch.failOnJobFailure=true"}; + validateForFail(DEFAULT_ERROR_MESSAGE, TaskJobLauncherCommandLineRunnerTests.JobWithFailureAnnotatedConfiguration.class, + enabledArgs); + } + + @Test + public void testTaskJobLauncherCLRSuccessFailWithTaskExecutor() { + String[] enabledArgs = new String[] { + "--spring.cloud.task.batch.failOnJobFailure=true", + "--spring.cloud.task.batch.failOnJobFailurePollInterval=500"}; + validateForFail(DEFAULT_ERROR_MESSAGE, TaskJobLauncherCommandLineRunnerTests.JobWithFailureTaskExecutorConfiguration.class, + enabledArgs); + } + + + @Test + public void testTaskJobLauncherCLRSuccessWithLongWaitTaskExecutor() { + String[] enabledArgs = new String[] { + "--spring.cloud.task.batch.failOnJobFailure=true", + "--spring.cloud.task.batch.failOnJobFailurePollInterval=500", + "--spring.cloud.task.batch.failOnJobFailurewaitTime=1000" + }; + validateForFail("Not all jobs were completed within the time specified by spring.cloud.task.batch.failOnJobFailurewaitTime.", + TaskJobLauncherCommandLineRunnerTests.JobWithFailureTaskExecutorLongWaitConfiguration.class, + enabledArgs); } @Test public void testTaskJobLauncherPickOneJob() { String[] enabledArgs = new String[] { "--spring.cloud.task.batch.fail-on-job-failure=true", - "--spring.cloud.task.batch.jobNames=jobSucceed" }; + "--spring.cloud.task.batch.jobNames=jobSucceed"}; boolean isExceptionThrown = false; try { this.applicationContext = SpringApplication - .run(new Class[] { TaskJobLauncherCommandLineRunnerTests.JobWithFailureConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - EmbeddedDataSourceConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class, - TaskJobLauncherAutoConfiguration.class }, enabledArgs); + .run(new Class[] { TaskJobLauncherCommandLineRunnerTests.JobWithFailureConfiguration.class }, enabledArgs); } catch (IllegalStateException exception) { isExceptionThrown = true; @@ -106,24 +140,18 @@ public class TaskJobLauncherCommandLineRunnerTests { @Test public void testCommandLineRunnerSetToFalse() { - String[] enabledArgs = new String[] { }; + String[] enabledArgs = new String[] {}; this.applicationContext = SpringApplication - .run(new Class[] { TaskJobLauncherCommandLineRunnerTests.JobConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - EmbeddedDataSourceConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class, - TaskJobLauncherAutoConfiguration.class }, enabledArgs); + .run(new Class[] { TaskJobLauncherCommandLineRunnerTests.JobConfiguration.class }, enabledArgs); validateContext(); assertThat(applicationContext.getBean(JobLauncherCommandLineRunner.class)).isNotNull(); - boolean exceptionThrown = false; - try { + + Executable executable = () -> { applicationContext.getBean(TaskJobLauncherCommandLineRunner.class); - } - catch (NoSuchBeanDefinitionException exception) { - exceptionThrown = true; - } - assertThat(exceptionThrown).isTrue(); + }; + Throwable exception = assertThrows(NoSuchBeanDefinitionException.class, executable); + assertThat(exception.getMessage()).isEqualTo("No qualifying bean of type " + + "'org.springframework.cloud.task.batch.handler.TaskJobLauncherCommandLineRunner' available"); validateContext(); } @@ -137,12 +165,20 @@ public class TaskJobLauncherCommandLineRunnerTests { assertThat(jobExecutionIds.size()).isEqualTo(1); assertThat(taskExplorer.getTaskExecution(jobExecutionIds.iterator().next()).getExecutionId()).isEqualTo(1); - } - @Configuration + private void validateForFail(String errorMessage, Class clazz, String [] enabledArgs) { + Executable executable = () -> { + this.applicationContext = SpringApplication + .run(new Class[] { clazz,PropertyPlaceholderAutoConfiguration.class}, enabledArgs);}; + Throwable exception = assertThrows(IllegalStateException.class, executable); + assertThat(exception.getCause().getMessage()).isEqualTo(errorMessage); + } + + @EnableBatchProcessing - @EnableTask + @TaskBatchTest + @Import(EmbeddedDataSourceConfiguration.class) public static class JobConfiguration { @Autowired @@ -156,8 +192,7 @@ public class TaskJobLauncherCommandLineRunnerTests { return jobBuilderFactory.get("job") .start(stepBuilderFactory.get("step1").tasklet(new Tasklet() { @Override - public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) - throws Exception { + public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) { System.out.println("Executed"); return RepeatStatus.FINISHED; } @@ -166,9 +201,15 @@ public class TaskJobLauncherCommandLineRunnerTests { } } - @Configuration @EnableBatchProcessing - @EnableTask + @ImportAutoConfiguration({ + PropertyPlaceholderAutoConfiguration.class, + BatchAutoConfiguration.class, + TaskBatchAutoConfiguration.class, + TaskJobLauncherAutoConfiguration.class, + SingleTaskConfiguration.class, + SimpleTaskAutoConfiguration.class }) + @Import(EmbeddedDataSourceConfiguration.class) public static class JobWithFailureConfiguration { @Autowired @@ -198,8 +239,7 @@ public class TaskJobLauncherCommandLineRunnerTests { .start(stepBuilderFactory.get("step1Succeed").tasklet(new Tasklet() { @Override public RepeatStatus execute(StepContribution contribution, - ChunkContext chunkContext) - throws Exception { + ChunkContext chunkContext) { System.out.println("Executed"); return RepeatStatus.FINISHED; } @@ -207,4 +247,83 @@ public class TaskJobLauncherCommandLineRunnerTests { .build(); } } + + @EnableTask + public static class JobWithFailureAnnotatedConfiguration extends JobWithFailureConfiguration{ + + } + + public static class JobWithFailureTaskExecutorConfiguration extends JobWithFailureConfiguration{ + @Bean + public BatchConfigurer batchConfigurer(DataSource dataSource) { + return new TestBatchConfigurer(dataSource); + } + } + + + @EnableBatchProcessing + @ImportAutoConfiguration({ + PropertyPlaceholderAutoConfiguration.class, + BatchAutoConfiguration.class, + TaskBatchAutoConfiguration.class, + TaskJobLauncherAutoConfiguration.class, + SingleTaskConfiguration.class, + SimpleTaskAutoConfiguration.class }) + @Import(EmbeddedDataSourceConfiguration.class) + public static class JobWithFailureTaskExecutorLongWaitConfiguration { + + @Autowired + private JobBuilderFactory jobBuilderFactory; + + @Autowired + private StepBuilderFactory stepBuilderFactory; + @Bean + public BatchConfigurer batchConfigurer(DataSource dataSource) { + return new TestBatchConfigurer(dataSource); + } + + @Bean + public Job jobShortRunner() { + return jobBuilderFactory.get("jobSucceedShort") + .start(stepBuilderFactory.get("step1SucceedSort").tasklet(new Tasklet() { + @Override + public RepeatStatus execute(StepContribution contribution, + ChunkContext chunkContext) + throws Exception { + System.out.println("Executed Short Runner"); + return RepeatStatus.FINISHED; + } + }).build()) + .build(); + } + + @Bean + public Job jobLongRunner() { + return jobBuilderFactory.get("jobSucceedLong") + .start(stepBuilderFactory.get("step1SucceedLong").tasklet(new Tasklet() { + @Override + public RepeatStatus execute(StepContribution contribution, + ChunkContext chunkContext) + throws Exception { + System.out.println("Executed Long Runner"); + Thread.sleep(5000); + return RepeatStatus.FINISHED; + } + }).build()) + .build(); + } + } + + private static class TestBatchConfigurer extends DefaultBatchConfigurer{ + public TestBatchConfigurer(DataSource dataSource) { + super(dataSource); + } + protected JobLauncher createJobLauncher() throws Exception { + SimpleJobLauncher jobLauncher = new SimpleJobLauncher(); + jobLauncher.setJobRepository(getJobRepository()); + jobLauncher.setTaskExecutor(new ConcurrentTaskExecutor()); + jobLauncher.afterPropertiesSet(); + return jobLauncher; + } + } } diff --git a/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/listener/PrefixTests.java b/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/listener/PrefixTests.java index a187139a..f7ff20fe 100644 --- a/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/listener/PrefixTests.java +++ b/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/listener/PrefixTests.java @@ -29,10 +29,7 @@ import org.springframework.batch.core.configuration.annotation.StepBuilderFactor import org.springframework.batch.repeat.RepeatStatus; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration; -import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.cloud.task.batch.configuration.TaskBatchAutoConfiguration; -import org.springframework.cloud.task.configuration.EnableTask; +import org.springframework.cloud.task.batch.configuration.TaskBatchTest; import org.springframework.cloud.task.repository.TaskExplorer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; @@ -58,11 +55,8 @@ public class PrefixTests { @Test public void testPrefix() { - this.applicationContext = SpringApplication.run(new Class[] { - JobConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class }, new String[] { "--spring.cloud.task.tablePrefix=FOO_" }); + this.applicationContext = SpringApplication.run( + JobConfiguration.class, new String[] { "--spring.cloud.task.tablePrefix=FOO_" }); TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class); @@ -73,7 +67,7 @@ public class PrefixTests { @Configuration @EnableBatchProcessing - @EnableTask + @TaskBatchTest public static class JobConfiguration { @Autowired diff --git a/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/listener/TaskBatchExecutionListenerTests.java b/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/listener/TaskBatchExecutionListenerTests.java index 83827b55..8bce0a2b 100644 --- a/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/listener/TaskBatchExecutionListenerTests.java +++ b/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/listener/TaskBatchExecutionListenerTests.java @@ -20,6 +20,7 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Set; + import javax.sql.DataSource; import org.junit.After; @@ -43,15 +44,16 @@ import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoCon import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; import org.springframework.cloud.task.batch.configuration.TaskBatchAutoConfiguration; import org.springframework.cloud.task.batch.configuration.TaskBatchExecutionListenerBeanPostProcessor; +import org.springframework.cloud.task.batch.configuration.TaskBatchTest; import org.springframework.cloud.task.configuration.DefaultTaskConfigurer; -import org.springframework.cloud.task.configuration.EnableTask; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; +import org.springframework.cloud.task.configuration.SingleTaskConfiguration; import org.springframework.cloud.task.configuration.TaskConfigurer; import org.springframework.cloud.task.repository.TaskExecution; import org.springframework.cloud.task.repository.TaskExplorer; -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.context.annotation.Import; import org.springframework.context.annotation.Primary; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -62,6 +64,7 @@ import static org.junit.Assert.assertEquals; /** * @author Michael Minella + * @author Glenn Renfro */ public class TaskBatchExecutionListenerTests { @@ -78,71 +81,50 @@ public class TaskBatchExecutionListenerTests { @Test public void testAutobuiltDataSource() { - this.applicationContext = SpringApplication.run(new Class[] {JobConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - EmbeddedDataSourceConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class}, ARGS); + this.applicationContext = SpringApplication.run(JobConfiguration.class , + ARGS); validateContext(); } @Test(expected = AssertionError.class) public void testNoAutoConfigurationEnabled() { - this.applicationContext = SpringApplication.run(new Class[] {JobConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - EmbeddedDataSourceConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class}, new String[] {"--spring.cloud.task.batch.listener.enabled=false"}); + this.applicationContext = SpringApplication.run(JobConfiguration.class, + new String[] {"--spring.cloud.task.batch.listener.enabled=false"}); validateContext(); } @Test(expected = AssertionError.class) public void testNoAutoConfigurationEnable() { - this.applicationContext = SpringApplication.run(new Class[] {JobConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - EmbeddedDataSourceConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class}, new String[] {"--spring.cloud.task.batch.listener.enable=false"}); + this.applicationContext = SpringApplication.run(JobConfiguration.class , + new String[] {"--spring.cloud.task.batch.listener.enable=false"}); validateContext(); } @Test(expected = AssertionError.class) public void testNoAutoConfigurationBothDisabled() { - this.applicationContext = SpringApplication.run(new Class[] {JobConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - EmbeddedDataSourceConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class}, new String[] {"--spring.cloud.task.batch.listener.enable=false --spring.cloud.task.batch.listener.enabled=false"}); + this.applicationContext = SpringApplication.run(JobConfiguration.class , + new String[] {"--spring.cloud.task.batch.listener.enable=false --spring.cloud.task.batch.listener.enabled=false"}); validateContext(); } @Test public void testAutoConfigurationEnable() { - this.applicationContext = SpringApplication.run(new Class[] {JobConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - EmbeddedDataSourceConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class}, new String[] {"--spring.cloud.task.batch.listener.enable=true"}); + this.applicationContext = SpringApplication.run(JobConfiguration.class , + new String[] {"--spring.cloud.task.batch.listener.enable=true"}); validateContext(); } @Test public void testAutoConfigurationEnabled() { - this.applicationContext = SpringApplication.run(new Class[] {JobConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - EmbeddedDataSourceConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class}, new String[] {"--spring.cloud.task.batch.listener.enabled=true"}); + this.applicationContext = SpringApplication.run(JobConfiguration.class , + new String[] {"--spring.cloud.task.batch.listener.enabled=true"}); validateContext(); } @Test public void testFactoryBean() { - this.applicationContext = SpringApplication.run(new Class[]{JobFactoryBeanConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - EmbeddedDataSourceConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class}, ARGS); + this.applicationContext = SpringApplication.run(JobFactoryBeanConfiguration.class, + ARGS); validateContext(); } @@ -159,11 +141,7 @@ public class TaskBatchExecutionListenerTests { } @Test public void testMultipleDataSources() { - this.applicationContext = SpringApplication.run(new Class[] {JobConfigurationMultipleDataSources.class, - PropertyPlaceholderAutoConfiguration.class, - EmbeddedDataSourceConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class}, ARGS); + this.applicationContext = SpringApplication.run(JobConfigurationMultipleDataSources.class, ARGS); TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class); @@ -177,11 +155,7 @@ public class TaskBatchExecutionListenerTests { @Test public void testAutobuiltDataSourceNoJob() { - this.applicationContext = SpringApplication.run(new Class[] {NoJobConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - EmbeddedDataSourceConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class}, ARGS); + this.applicationContext = SpringApplication.run(NoJobConfiguration.class, ARGS); TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class); @@ -194,10 +168,7 @@ public class TaskBatchExecutionListenerTests { @Test public void testMapBased() { - this.applicationContext = SpringApplication.run(new Class[] {JobConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, EmbeddedDataSourceConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class}, ARGS); + this.applicationContext = SpringApplication.run(JobConfiguration.class, ARGS); TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class); @@ -211,10 +182,7 @@ public class TaskBatchExecutionListenerTests { @Test public void testMultipleJobs() { - this.applicationContext = SpringApplication.run(new Class[] {EmbeddedDataSourceConfiguration.class, MultipleJobConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class}, ARGS); + this.applicationContext = SpringApplication.run(MultipleJobConfiguration.class, ARGS); TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class); @@ -267,7 +235,9 @@ public class TaskBatchExecutionListenerTests { this.applicationContext = SpringApplication.run(new Class[] {JobConfiguration.class, PropertyPlaceholderAutoConfiguration.class, EmbeddedDataSourceConfiguration.class, BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class}, ARGS); + TaskBatchAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + SingleTaskConfiguration.class }, ARGS); TaskBatchExecutionListenerBeanPostProcessor beanPostProcessor = this.applicationContext.getBean( @@ -277,16 +247,16 @@ public class TaskBatchExecutionListenerTests { return beanPostProcessor; } - @Configuration @EnableBatchProcessing - @EnableTask + @TaskBatchTest + @Import(EmbeddedDataSourceConfiguration.class) public static class NoJobConfiguration { } - @Configuration @EnableBatchProcessing - @EnableTask + @TaskBatchTest + @Import(EmbeddedDataSourceConfiguration.class) public static class JobConfiguration { @Autowired @@ -309,9 +279,9 @@ public class TaskBatchExecutionListenerTests { } } - @Configuration @EnableBatchProcessing - @EnableTask + @TaskBatchTest + @Import(EmbeddedDataSourceConfiguration.class) public static class JobFactoryBeanConfiguration { @Autowired @@ -349,9 +319,9 @@ public class TaskBatchExecutionListenerTests { } } - @Configuration @EnableBatchProcessing - @EnableTask + @TaskBatchTest + @Import(EmbeddedDataSourceConfiguration.class) public static class JobConfigurationMultipleDataSources { @Autowired @@ -396,24 +366,15 @@ public class TaskBatchExecutionListenerTests { return new DefaultTaskConfigurer(myDataSource()); } - @Bean - public TaskRepositoryInitializer taskRepositoryInitializer() { - TaskRepositoryInitializer taskRepositoryInitializer = new TaskRepositoryInitializer(); - - taskRepositoryInitializer.setDataSource(myDataSource()); - - return taskRepositoryInitializer; - } - @Bean public DefaultBatchConfigurer batchConfigurer() { return new DefaultBatchConfigurer(myDataSource()); } } - @Configuration @EnableBatchProcessing - @EnableTask + @TaskBatchTest + @Import(EmbeddedDataSourceConfiguration.class) public static class MultipleJobConfiguration { @Autowired diff --git a/spring-cloud-task-batch/src/test/resources/META-INF/spring.factories b/spring-cloud-task-batch/src/test/resources/META-INF/spring.factories new file mode 100644 index 00000000..ddec7ef9 --- /dev/null +++ b/spring-cloud-task-batch/src/test/resources/META-INF/spring.factories @@ -0,0 +1,6 @@ +org.springframework.cloud.task.batch.configuration.TaskBatchTest=\ +org.springframework.cloud.task.batch.configuration.TaskBatchAutoConfiguration,\ +org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\ +org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\ +org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration,\ +org.springframework.cloud.task.configuration.SingleTaskConfiguration diff --git a/spring-cloud-task-core/pom.xml b/spring-cloud-task-core/pom.xml index 4283f505..702057be 100755 --- a/spring-cloud-task-core/pom.xml +++ b/spring-cloud-task-core/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-task-parent - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT spring-cloud-task-core @@ -91,6 +91,12 @@ spring-boot-configuration-processor true + + org.junit.jupiter + junit-jupiter-api + ${junit.version} + test + diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/EnableTask.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/EnableTask.java index 26d99364..9b731de4 100644 --- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/EnableTask.java +++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/EnableTask.java @@ -1,6 +1,5 @@ - /* - * Copyright 2015 the original author or authors. + * Copyright 2015-2018 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. @@ -54,11 +53,15 @@ import org.springframework.context.annotation.Import; * * * @author Glenn Renfro + * + * @deprecated The EnableTask annotation is no longer be required to initialize + * Spring Cloud Task. This will be handled by AutoConfiguration provided by Spring Cloud Task. */ +@Deprecated @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited -@Import({ SimpleTaskConfiguration.class, SingleTaskConfiguration.class }) +@Import({ }) public @interface EnableTask { } 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/SimpleTaskAutoConfiguration.java similarity index 90% rename from spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/SimpleTaskConfiguration.java rename to spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/SimpleTaskAutoConfiguration.java index e5815a52..54171a61 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/SimpleTaskAutoConfiguration.java @@ -29,9 +29,11 @@ import org.apache.commons.logging.LogFactory; import org.springframework.aop.scope.ScopedProxyUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.task.listener.TaskLifecycleListener; -import org.springframework.cloud.task.listener.annotation.TaskListenerExecutorFactoryBean; +import org.springframework.cloud.task.listener.TaskListenerExecutorObjectFactory; import org.springframework.cloud.task.repository.TaskExplorer; import org.springframework.cloud.task.repository.TaskNameResolver; import org.springframework.cloud.task.repository.TaskRepository; @@ -55,9 +57,10 @@ import org.springframework.util.CollectionUtils; @Configuration @EnableTransactionManagement @EnableConfigurationProperties(TaskProperties.class) -public class SimpleTaskConfiguration { +@ConditionalOnProperty(prefix = "spring.cloud.task.autoconfiguration", name = "enabled", havingValue = "true", matchIfMissing = true) +public class SimpleTaskAutoConfiguration { - protected static final Log logger = LogFactory.getLog(SimpleTaskConfiguration.class); + protected static final Log logger = LogFactory.getLog(SimpleTaskAutoConfiguration.class); @Autowired(required = false) private Collection dataSources; @@ -77,8 +80,6 @@ public class SimpleTaskConfiguration { private TaskLifecycleListener taskLifecycleListener; - private TaskListenerExecutorFactoryBean taskListenerExecutorFactoryBean; - private PlatformTransactionManager platformTransactionManager; private TaskExplorer taskExplorer; @@ -94,12 +95,7 @@ public class SimpleTaskConfiguration { } @Bean - public TaskListenerExecutorFactoryBean taskListenerExecutor() - throws Exception { - return this.taskListenerExecutorFactoryBean; - } - - @Bean + @ConditionalOnMissingBean public PlatformTransactionManager transactionManager() { return this.platformTransactionManager; } @@ -140,12 +136,11 @@ public class SimpleTaskConfiguration { taskConfigurer.getClass().getName())); this.taskRepository = taskConfigurer.getTaskRepository(); - this.taskListenerExecutorFactoryBean = new TaskListenerExecutorFactoryBean(context); this.platformTransactionManager = taskConfigurer.getTransactionManager(); this.taskExplorer = taskConfigurer.getTaskExplorer(); this.taskLifecycleListener = new TaskLifecycleListener(this.taskRepository, taskNameResolver(), - this.applicationArguments, taskExplorer, taskProperties); + this.applicationArguments, taskExplorer, taskProperties, new TaskListenerExecutorObjectFactory(context)); initialized = true; } diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/TaskLifecycleListener.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/TaskLifecycleListener.java index 9a426ed3..c6e3c9ec 100644 --- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/TaskLifecycleListener.java +++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/TaskLifecycleListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2016-2018 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. @@ -46,6 +46,7 @@ import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.SmartLifecycle; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; /** @@ -74,7 +75,9 @@ public class TaskLifecycleListener implements ApplicationListener taskExecutionListeners; + private Collection taskExecutionListenersFromContext; + + private List taskExecutionListeners; private final static Log logger = LogFactory.getLog(TaskLifecycleListener.class); @@ -82,6 +85,8 @@ public class TaskLifecycleListener implements ApplicationListener(); + this.taskListenerExecutorObjectFactory.getObject(); + if(!CollectionUtils.isEmpty(this.taskExecutionListenersFromContext)) { + this.taskExecutionListeners.addAll(this.taskExecutionListenersFromContext); + } + this.taskExecutionListeners.add(this.taskListenerExecutorObjectFactory.getObject()); + List args = new ArrayList<>(0); if(this.applicationArguments != null) { @@ -258,11 +273,11 @@ public class TaskLifecycleListener implements ApplicationListener startupListenerList = new ArrayList<>(this.taskExecutionListeners); + if (startupListenerList != null) { try { - List starterList = new ArrayList<>(taskExecutionListeners); - Collections.reverse(starterList); - for (TaskExecutionListener taskExecutionListener : starterList) { + Collections.reverse(startupListenerList); + for (TaskExecutionListener taskExecutionListener : startupListenerList) { taskExecutionListener.onTaskStartup(listenerTaskExecution); } } @@ -300,7 +315,7 @@ public class TaskLifecycleListener implements ApplicationListener { +public class TaskListenerExecutorObjectFactory implements ObjectFactory { private final static Log logger = LogFactory.getLog(TaskListenerExecutor.class); @@ -56,29 +65,19 @@ public class TaskListenerExecutorFactoryBean implements FactoryBean failedTaskInstances; - public TaskListenerExecutorFactoryBean(ConfigurableApplicationContext context){ + public TaskListenerExecutorObjectFactory(ConfigurableApplicationContext context){ this.context = context; } @Override - public TaskListenerExecutor getObject() throws Exception { - beforeTaskInstances = new HashMap<>(); - afterTaskInstances = new HashMap<>(); - failedTaskInstances = new HashMap<>(); + public TaskListenerExecutor getObject() { + this.beforeTaskInstances = new HashMap<>(); + this.afterTaskInstances = new HashMap<>(); + this.failedTaskInstances = new HashMap<>(); initializeExecutor(); return new TaskListenerExecutor(beforeTaskInstances, afterTaskInstances, failedTaskInstances); } - @Override - public Class getObjectType() { - return TaskListenerExecutor.class; - } - - @Override - public boolean isSingleton() { - return false; - } - private void initializeExecutor( ) { ConfigurableListableBeanFactory factory = context.getBeanFactory(); for( String beanName : context.getBeanDefinitionNames()) { diff --git a/spring-cloud-task-core/src/main/resources/META-INF/spring.factories b/spring-cloud-task-core/src/main/resources/META-INF/spring.factories index 22ff66d1..ea2f98ee 100644 --- a/spring-cloud-task-core/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-task-core/src/main/resources/META-INF/spring.factories @@ -1 +1,4 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.springframework.cloud.task.configuration.ResourceLoadingAutoConfiguration +org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.springframework.cloud.task.configuration.SingleTaskConfiguration,\ +org.springframework.cloud.task.configuration.ResourceLoadingAutoConfiguration,\ +org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration\ + diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleSingleTaskAutoConfigurationTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleSingleTaskAutoConfigurationTests.java index 671e4d9e..945ca4a8 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleSingleTaskAutoConfigurationTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleSingleTaskAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2017-2018 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. @@ -17,17 +17,13 @@ package org.springframework.cloud.task; import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cloud.task.configuration.SingleTaskConfiguration; -import org.springframework.cloud.task.configuration.SimpleTaskConfiguration; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; import org.springframework.cloud.task.configuration.SingleInstanceTaskListener; -import org.springframework.cloud.task.configuration.TaskProperties; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.cloud.task.configuration.SingleTaskConfiguration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -39,24 +35,23 @@ import static org.junit.Assert.assertNotNull; * @author Glenn Renfro * @since 2.0.0 */ -@RunWith(SpringRunner.class) -@ContextConfiguration(classes = {TaskProperties.class, SimpleTaskConfiguration.class, SingleTaskConfiguration.class}) -@TestPropertySource(properties = { - "spring.cloud.task.single-instance-enabled=true", -}) public class SimpleSingleTaskAutoConfigurationTests { - @Autowired - private ConfigurableApplicationContext context; @Test public void testConfiguration() throws Exception { - SingleInstanceTaskListener singleInstanceTaskListener = this.context.getBean(SingleInstanceTaskListener.class); + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + PropertyPlaceholderAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + SingleTaskConfiguration.class)) + .withPropertyValues("spring.cloud.task.singleInstanceEnabled=true"); + applicationContextRunner.run((context) -> { + SingleInstanceTaskListener singleInstanceTaskListener = context.getBean(SingleInstanceTaskListener.class); - assertNotNull("singleInstanceTaskListener should not be null", singleInstanceTaskListener); - - assertEquals(singleInstanceTaskListener.getClass(), SingleInstanceTaskListener.class); + assertNotNull("singleInstanceTaskListener should not be null", singleInstanceTaskListener); + assertEquals(singleInstanceTaskListener.getClass(), SingleInstanceTaskListener.class); }); } } diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleSingleTaskAutoConfigurationWithDataSourceTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleSingleTaskAutoConfigurationWithDataSourceTests.java index b86b1ac3..350fc2d8 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleSingleTaskAutoConfigurationWithDataSourceTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleSingleTaskAutoConfigurationWithDataSourceTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2017-2018 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. @@ -17,17 +17,14 @@ package org.springframework.cloud.task; import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; -import org.springframework.cloud.task.configuration.SingleTaskConfiguration; -import org.springframework.cloud.task.configuration.SimpleTaskConfiguration; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; import org.springframework.cloud.task.configuration.SingleInstanceTaskListener; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.cloud.task.configuration.SingleTaskConfiguration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -39,25 +36,24 @@ import static org.junit.Assert.assertNotNull; * @author Glenn Renfro * @since 2.0.0 */ -@RunWith(SpringRunner.class) -@ContextConfiguration(classes = {SimpleTaskConfiguration.class, - SingleTaskConfiguration.class, - EmbeddedDataSourceConfiguration.class}) -@TestPropertySource(properties = { - "spring.cloud.task.single-instance-enabled=true", -}) public class SimpleSingleTaskAutoConfigurationWithDataSourceTests { - @Autowired - private ConfigurableApplicationContext context; - @Test public void testConfiguration() throws Exception { - SingleInstanceTaskListener singleInstanceTaskListener = this.context.getBean(SingleInstanceTaskListener.class); + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + PropertyPlaceholderAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + SingleTaskConfiguration.class, + EmbeddedDataSourceConfiguration.class)) + .withPropertyValues("spring.cloud.task.singleInstanceEnabled=true"); + applicationContextRunner.run((context) -> { + SingleInstanceTaskListener singleInstanceTaskListener = context.getBean(SingleInstanceTaskListener.class); - assertNotNull("singleInstanceTaskListener should not be null", singleInstanceTaskListener); + assertNotNull("singleInstanceTaskListener should not be null", singleInstanceTaskListener); - assertEquals(singleInstanceTaskListener.getClass(), SingleInstanceTaskListener.class); + assertEquals(singleInstanceTaskListener.getClass(), SingleInstanceTaskListener.class); + }); } } diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleTaskAutoConfigurationTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleTaskAutoConfigurationTests.java new file mode 100644 index 00000000..5bfc1f04 --- /dev/null +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleTaskAutoConfigurationTests.java @@ -0,0 +1,251 @@ +/* + * Copyright 2015-2018 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; + +import javax.sql.DataSource; + +import org.junit.After; +import org.junit.Test; +import org.junit.jupiter.api.function.Executable; + +import org.springframework.aop.framework.AopProxyUtils; +import org.springframework.aop.scope.ScopedProxyUtils; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.GenericBeanDefinition; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.cloud.task.configuration.DefaultTaskConfigurer; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; +import org.springframework.cloud.task.configuration.SingleTaskConfiguration; +import org.springframework.cloud.task.configuration.TaskConfigurer; +import org.springframework.cloud.task.repository.TaskExplorer; +import org.springframework.cloud.task.repository.TaskRepository; +import org.springframework.cloud.task.repository.support.SimpleTaskRepository; +import org.springframework.context.ApplicationContextException; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; + +/** + * Verifies that the beans created by the SimpleTaskAutoConfiguration. + * + * @author Glenn Renfro + * @author Michael Minella + */ +public class SimpleTaskAutoConfigurationTests { + + private ConfigurableApplicationContext context; + + @After + public void tearDown() { + if (this.context != null) { + this.context.close(); + } + } + + @Test + public void testRepository() throws Exception { + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + PropertyPlaceholderAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + SingleTaskConfiguration.class)); + applicationContextRunner.run((context) -> { + + TaskRepository taskRepository = context.getBean(TaskRepository.class); + assertThat(taskRepository).isNotNull(); + Class targetClass = AopProxyUtils.ultimateTargetClass(taskRepository); + assertThat(targetClass).isEqualTo(SimpleTaskRepository.class); + }); + } + + @Test + public void testAutoConfigurationDisabled() throws Exception { + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + PropertyPlaceholderAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + SingleTaskConfiguration.class)) + .withPropertyValues("spring.cloud.task.autoconfiguration.enabled=false"); + Executable executable = () -> { + applicationContextRunner.run((context) -> { + context.getBean(TaskRepository.class); + }); + }; + verifyExceptionThrown(NoSuchBeanDefinitionException.class, "No qualifying " + + "bean of type 'org.springframework.cloud.task.repository.TaskRepository' " + + "available", executable); + } + + @Test + public void testRepositoryInitialized() throws Exception { + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(EmbeddedDataSourceConfiguration.class, + PropertyPlaceholderAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + SingleTaskConfiguration.class)); + applicationContextRunner.run((context) -> { + TaskExplorer taskExplorer = context.getBean(TaskExplorer.class); + assertThat(taskExplorer.getTaskExecutionCount()).isEqualTo(1l); + }); + } + + @Test + public void testRepositoryNotInitialized() throws Exception { + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(EmbeddedDataSourceConfiguration.class, + PropertyPlaceholderAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + SingleTaskConfiguration.class)) + .withPropertyValues("spring.cloud.task.tablePrefix=foobarless"); + + verifyExceptionThrownDefaultExecutable(ApplicationContextException.class, "Failed to start " + + "bean 'taskLifecycleListener'; nested exception is " + + "org.springframework.dao.DataAccessResourceFailureException: " + + "Could not obtain sequence value; nested exception is org.h2.jdbc.JdbcSQLException: " + + "Syntax error in SQL statement \"SELECT FOOBARLESSSEQ.NEXTVAL FROM[*] DUAL \"; " + + "expected \"identifier\"; SQL statement:\n" + + "select foobarlessSEQ.nextval from dual [42001-197]", applicationContextRunner); + } + + @Test + public void testMultipleConfigurers() { + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + PropertyPlaceholderAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + SingleTaskConfiguration.class)) + .withUserConfiguration(MultipleConfigurers.class); + + verifyExceptionThrownDefaultExecutable(BeanCreationException.class, "Error creating bean " + + "with name 'simpleTaskAutoConfiguration': Invocation of init " + + "method failed; nested exception is java.lang.IllegalStateException:" + + " Expected one TaskConfigurer but found 2", applicationContextRunner); + } + + @Test + public void testMultipleDataSources() { + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + SingleTaskConfiguration.class)) + .withUserConfiguration(MultipleDataSources.class); + + verifyExceptionThrownDefaultExecutable(BeanCreationException.class, "Error creating bean " + + "with name 'simpleTaskAutoConfiguration': Invocation of init method " + + "failed; nested exception is java.lang.IllegalStateException: To use " + + "the default TaskConfigurer the context must contain no more than " + + "one DataSource, found 2", applicationContextRunner); + + } + + public void verifyExceptionThrownDefaultExecutable(Class classToCheck, String message, + ApplicationContextRunner applicationContextRunner) { + Executable executable = () -> { + applicationContextRunner.run((context) -> { + Throwable expectedException = context.getStartupFailure(); + assertThat(expectedException).isNotNull(); + throw expectedException; + }); + }; + verifyExceptionThrown(classToCheck, message, executable); + } + + public void verifyExceptionThrown(Class classToCheck, String message, Executable executable) { + Throwable exception = assertThrows(classToCheck, executable); + assertThat(exception.getMessage()).isEqualTo(message); + } + + /** + * Verify that the verifyEnvironment method skips DataSource Proxy Beans when determining + * the number of available dataSources. + */ + @Test + public void testWithDataSourceProxy() { + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + EmbeddedDataSourceConfiguration.class, + PropertyPlaceholderAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + SingleTaskConfiguration.class)) + .withUserConfiguration(DataSourceProxyConfiguration.class); + applicationContextRunner.run((context) -> { + assertThat(context.getBeanNamesForType(DataSource.class).length).isEqualTo(2); + SimpleTaskAutoConfiguration taskConfiguration = context.getBean(SimpleTaskAutoConfiguration.class); + assertThat(taskConfiguration).isNotNull(); + assertThat(taskConfiguration.taskExplorer()).isNotNull(); + }); + } + + @Configuration + public static class MultipleConfigurers { + + @Bean + public TaskConfigurer taskConfigurer1() { + return new DefaultTaskConfigurer((DataSource) null); + } + + @Bean + public TaskConfigurer taskConfigurer2() { + return new DefaultTaskConfigurer((DataSource) null); + } + } + + @Configuration + public static class MultipleDataSources { + + @Bean + public DataSource dataSource() { + return mock(DataSource.class); + }; + + @Bean + public DataSource dataSource2() { + return mock(DataSource.class); + }; + + } + + @Configuration + public static class DataSourceProxyConfiguration { + + @Autowired + private ConfigurableApplicationContext context; + + @Bean + public BeanDefinitionHolder proxyDataSource() { + GenericBeanDefinition proxyBeanDefinition = new GenericBeanDefinition(); + proxyBeanDefinition.setBeanClassName("javax.sql.DataSource"); + BeanDefinitionHolder myDataSource = new BeanDefinitionHolder(proxyBeanDefinition, "dataSource2"); + ScopedProxyUtils.createScopedProxy(myDataSource, (BeanDefinitionRegistry) this.context.getBeanFactory(), + true); + return myDataSource; + } + + } + +} diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleTaskConfigurationTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleTaskConfigurationTests.java deleted file mode 100644 index d5f38101..00000000 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleTaskConfigurationTests.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * 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. - * 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; - -import java.util.Properties; - -import javax.sql.DataSource; - -import org.junit.After; -import org.junit.Test; - -import org.springframework.aop.framework.AopProxyUtils; -import org.springframework.aop.scope.ScopedProxyUtils; -import org.springframework.beans.factory.BeanCreationException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.config.BeanDefinitionHolder; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.GenericBeanDefinition; -import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; -import org.springframework.cloud.task.configuration.DefaultTaskConfigurer; -import org.springframework.cloud.task.configuration.EnableTask; -import org.springframework.cloud.task.configuration.SimpleTaskConfiguration; -import org.springframework.cloud.task.configuration.TaskConfigurer; -import org.springframework.cloud.task.configuration.TaskProperties; -import org.springframework.cloud.task.repository.TaskExplorer; -import org.springframework.cloud.task.repository.TaskRepository; -import org.springframework.cloud.task.repository.support.SimpleTaskRepository; -import org.springframework.context.ApplicationContextException; -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.core.env.PropertiesPropertySource; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; - -/** - * Verifies that the beans created by the SimpleTaskConfiguration. - * - * @author Glenn Renfro - * @author Michael Minella - */ -public class SimpleTaskConfigurationTests { - - private ConfigurableApplicationContext context; - - @After - public void tearDown() { - if(this.context != null) { - this.context.close(); - } - } - - @Test - public void testRepository() throws Exception { - this.context = new AnnotationConfigApplicationContext(SimpleTaskConfiguration.class, - PropertyPlaceholderAutoConfiguration.class); - - TaskRepository taskRepository = this.context.getBean(TaskRepository.class); - - assertThat(taskRepository).isNotNull(); - - Class targetClass = AopProxyUtils.ultimateTargetClass(taskRepository); - - assertThat(targetClass).isEqualTo(SimpleTaskRepository.class); - } - - - @Test - public void testRepositoryInitialized() throws Exception { - this.context = new AnnotationConfigApplicationContext(EmbeddedDataSourceConfiguration.class, SimpleTaskConfiguration.class, - PropertyPlaceholderAutoConfiguration.class); - - TaskExplorer taskExplorer = this.context.getBean(TaskExplorer.class); - - assertThat(taskExplorer.getTaskExecutionCount()).isEqualTo(1l); - } - - @Test - public void testRepositoryNotInitialized() throws Exception { - Properties properties = new Properties(); - - properties.put("spring.cloud.task.tablePrefix", "foobarless"); - PropertiesPropertySource propertiesSource = new PropertiesPropertySource("test", properties); - - this.context = new AnnotationConfigApplicationContext(); - this.context.getEnvironment().getPropertySources().addLast(propertiesSource); - ((AnnotationConfigApplicationContext)context).register(SimpleTaskConfiguration.class); - ((AnnotationConfigApplicationContext)context).register(PropertyPlaceholderAutoConfiguration.class); - ((AnnotationConfigApplicationContext)context).register(EmbeddedDataSourceConfiguration.class); - boolean wasExceptionThrown = false; - try { - this.context.refresh(); - } - catch (ApplicationContextException ex) { - wasExceptionThrown = true; - } - assertThat( wasExceptionThrown).isTrue(); - } - - - @Test(expected = BeanCreationException.class) - public void testMultipleConfigurers() { - this.context = new AnnotationConfigApplicationContext(MultipleConfigurers.class, - PropertyPlaceholderAutoConfiguration.class); - } - - @Test(expected = BeanCreationException.class) - public void testMultipleDataSources() { - this.context = new AnnotationConfigApplicationContext( - MultipleDataSources.class, SimpleTaskConfiguration.class, - PropertyPlaceholderAutoConfiguration.class); - } - - /** - * Verify that the verifyEnvironment method skips DataSource Proxy Beans - * when determining the number of available dataSources. - */ - @Test - public void testWithDataSourceProxy() { - this.context = new AnnotationConfigApplicationContext(EmbeddedDataSourceConfiguration.class, TaskProperties.class, - PropertyPlaceholderAutoConfiguration.class, DataSourceProxyConfiguration.class - ); - - assertThat(this.context.getBeanNamesForType(DataSource.class).length).isEqualTo(2); - SimpleTaskConfiguration taskConfiguration = this.context.getBean(SimpleTaskConfiguration.class); - assertThat(taskConfiguration).isNotNull(); - assertThat(taskConfiguration.taskExplorer()).isNotNull(); - } - - @Configuration - @EnableTask - public static class MultipleConfigurers { - - @Bean - public TaskConfigurer taskConfigurer1() { - return new DefaultTaskConfigurer((DataSource) null); - } - - @Bean - public TaskConfigurer taskConfigurer2() { - return new DefaultTaskConfigurer((DataSource) null); - } - } - - @Configuration - public static class MultipleDataSources { - - @Bean - public DataSource dataSource() { - return mock(DataSource.class); - }; - - @Bean - public DataSource dataSource2() { - return mock(DataSource.class); - }; - - } - - @Configuration - public static class DataSourceProxyConfiguration { - - @Autowired - private ConfigurableApplicationContext context; - - @Bean - public SimpleTaskConfiguration simpleTaskConfiguration() { - GenericBeanDefinition proxyBeanDefinition = new GenericBeanDefinition(); - proxyBeanDefinition.setBeanClassName("javax.sql.DataSource"); - BeanDefinitionHolder myDataSource = new BeanDefinitionHolder(proxyBeanDefinition,"dataSource2"); - ScopedProxyUtils.createScopedProxy(myDataSource, (BeanDefinitionRegistry) this.context.getBeanFactory(), true); - return new SimpleTaskConfiguration(); - } - - } - -} diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskCoreTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskCoreTests.java index 95e2eb40..df30c003 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskCoreTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskCoreTests.java @@ -1,3 +1,19 @@ +/* + * Copyright 2015-2018 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; import org.junit.After; @@ -5,14 +21,15 @@ import org.junit.Rule; import org.junit.Test; import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.test.rule.OutputCapture; import org.springframework.cloud.task.configuration.EnableTask; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; import org.springframework.context.ApplicationContextException; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; import static org.junit.Assert.assertTrue; @@ -48,11 +65,31 @@ public class TaskCoreTests { @Test public void successfulTaskTest() { - applicationContext = new SpringApplicationBuilder().sources(new Class[]{TaskConfiguration.class, - PropertyPlaceholderAutoConfiguration.class}).build().run(new String[]{ - "--spring.cloud.task.closecontext.enable=false", - "--spring.cloud.task.name=" + TASK_NAME, - "--spring.main.web-environment=false"}); + this.applicationContext = SpringApplication.run( TaskConfiguration.class, + new String[] { + "--spring.cloud.task.closecontext.enable=false", + "--spring.cloud.task.name=" + TASK_NAME, + "--spring.main.web-environment=false" }); + + String output = this.outputCapture.toString(); + assertTrue("Test results do not show create task message: " + output, + output.contains(CREATE_TASK_MESSAGE)); + assertTrue("Test results do not show success message: " + output, + output.contains(UPDATE_TASK_MESSAGE)); + assertTrue("Test results have incorrect exit code: " + output, + output.contains(SUCCESS_EXIT_CODE_MESSAGE)); + } + + /** + * Test to verify that deprecated annotation does not affect task execution. + */ + @Test + public void successfulTaskTestWithAnnotation() { + this.applicationContext = SpringApplication.run( TaskConfigurationWithAnotation.class, + new String[] { + "--spring.cloud.task.closecontext.enable=false", + "--spring.cloud.task.name=" + TASK_NAME, + "--spring.main.web-environment=false" }); String output = this.outputCapture.toString(); assertTrue("Test results do not show create task message: " + output, @@ -67,11 +104,11 @@ public class TaskCoreTests { public void exceptionTaskTest() { boolean exceptionFired = false; try { - applicationContext = new SpringApplicationBuilder().sources(TaskExceptionConfiguration.class, - PropertyPlaceholderAutoConfiguration.class).build().run(new String[]{ - "--spring.cloud.task.closecontext.enable=false", - "--spring.cloud.task.name=" + TASK_NAME, - "--spring.main.web-environment=false"}); + this.applicationContext = SpringApplication.run( TaskExceptionConfiguration.class, + new String[] { + "--spring.cloud.task.closecontext.enable=false", + "--spring.cloud.task.name=" + TASK_NAME, + "--spring.main.web-environment=false" }); } catch (IllegalStateException exception) { exceptionFired = true; @@ -95,8 +132,8 @@ public class TaskCoreTests { public void invalidExecutionId() { boolean exceptionFired = false; try { - applicationContext = new SpringApplicationBuilder().sources(TaskExceptionConfiguration.class, - PropertyPlaceholderAutoConfiguration.class).build().run(new String[]{ + applicationContext = this.applicationContext = SpringApplication.run( + TaskExceptionConfiguration.class, new String[]{ "--spring.cloud.task.closecontext.enable=false", "--spring.cloud.task.name=" + TASK_NAME, "--spring.main.web-environment=false", @@ -112,8 +149,7 @@ public class TaskCoreTests { output.contains(EXCEPTION_INVALID_TASK_EXECUTION_ID)); } - @Configuration - @EnableTask + @ImportAutoConfiguration({SimpleTaskAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class}) public static class TaskConfiguration { @Bean @@ -126,8 +162,21 @@ public class TaskCoreTests { } } - @Configuration @EnableTask + @ImportAutoConfiguration({SimpleTaskAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class}) + public static class TaskConfigurationWithAnotation { + + @Bean + public CommandLineRunner commandLineRunner() { + return new CommandLineRunner() { + @Override + public void run(String... strings) throws Exception { + } + }; + } + } + + @ImportAutoConfiguration({SimpleTaskAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class}) public static class TaskExceptionConfiguration { @Bean diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskRepositoryInitializerDefaultTaskConfigurerTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskRepositoryInitializerDefaultTaskConfigurerTests.java index 3fcce0e7..8174e9a0 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskRepositoryInitializerDefaultTaskConfigurerTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskRepositoryInitializerDefaultTaskConfigurerTests.java @@ -26,7 +26,7 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; -import org.springframework.cloud.task.configuration.SimpleTaskConfiguration; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; import org.springframework.cloud.task.configuration.TaskConfigurer; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.context.ContextConfiguration; @@ -42,7 +42,7 @@ import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; * @since 2.0.0 */ @RunWith(SpringRunner.class) -@ContextConfiguration(classes = {SimpleTaskConfiguration.class, +@ContextConfiguration(classes = {SimpleTaskAutoConfiguration.class, EmbeddedDataSourceConfiguration.class}) public class TaskRepositoryInitializerDefaultTaskConfigurerTests { diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskRepositoryInitializerNoDataSourceTaskConfigurerTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskRepositoryInitializerNoDataSourceTaskConfigurerTests.java index 0705ba20..00ab42d8 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskRepositoryInitializerNoDataSourceTaskConfigurerTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskRepositoryInitializerNoDataSourceTaskConfigurerTests.java @@ -27,7 +27,8 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; import org.springframework.cloud.task.configuration.DefaultTaskConfigurer; -import org.springframework.cloud.task.configuration.SimpleTaskConfiguration; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; +import org.springframework.cloud.task.configuration.SingleTaskConfiguration; import org.springframework.cloud.task.configuration.TaskConfigurer; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.context.ContextConfiguration; @@ -43,7 +44,7 @@ import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; * @since 2.0.0 */ @RunWith(SpringRunner.class) -@ContextConfiguration(classes = {SimpleTaskConfiguration.class, +@ContextConfiguration(classes = {SimpleTaskAutoConfiguration.class, SingleTaskConfiguration.class, EmbeddedDataSourceConfiguration.class, DefaultTaskConfigurer.class}) public class TaskRepositoryInitializerNoDataSourceTaskConfigurerTests { diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/configuration/TaskPropertiesTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/configuration/TaskPropertiesTests.java index ed6495b8..b8b1aa72 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/configuration/TaskPropertiesTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/configuration/TaskPropertiesTests.java @@ -1,3 +1,19 @@ +/* + * Copyright 2017-2018 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.configuration; import org.junit.Test; @@ -7,10 +23,6 @@ import org.junit.runners.Suite.SuiteClasses; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.task.repository.TaskRepository; -import org.springframework.cloud.task.repository.support.SimpleTaskRepository; -import org.springframework.cloud.task.repository.support.TaskExecutionDaoFactoryBean; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringRunner; @@ -21,7 +33,7 @@ import static org.junit.Assert.assertThat; @RunWith(Suite.class) @SuiteClasses({ - TaskPropertiesTests.CloseContextEnabledTest.class, + TaskPropertiesTests.CloseContextEnabledTest.class }) @@ -36,21 +48,15 @@ public class TaskPropertiesTests { } @RunWith(SpringRunner.class) - @SpringBootTest(classes={TaskPropertiesTests.Config.class}, properties = { "spring.cloud.task.closecontextEnabled=false" }) + @SpringBootTest(classes={TaskPropertiesTests.Config.class, + SimpleTaskAutoConfiguration.class, SingleTaskConfiguration.class}, + properties = { "spring.cloud.task.closecontextEnabled=false" }) @DirtiesContext public static class CloseContextEnabledTest extends TaskPropertiesTests {} @Configuration - @EnableTask public static class Config { - @Bean - TaskExecutionDaoFactoryBean taskExecutionDaoFactoryBean() { - return new TaskExecutionDaoFactoryBean(); - } - @Bean - public TaskRepository taskRepository(TaskExecutionDaoFactoryBean tefb) { - return new SimpleTaskRepository(tefb); - } + } } diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskExecutionListenerTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskExecutionListenerTests.java index a1f4d25c..3f78bcbe 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskExecutionListenerTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskExecutionListenerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2016-2018 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. @@ -29,11 +29,9 @@ import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.cloud.task.listener.annotation.AfterTask; import org.springframework.cloud.task.listener.annotation.BeforeTask; import org.springframework.cloud.task.listener.annotation.FailedTask; -import org.springframework.cloud.task.listener.annotation.TaskListenerExecutorFactoryBean; import org.springframework.cloud.task.repository.TaskExecution; import org.springframework.cloud.task.util.TestDefaultConfiguration; import org.springframework.cloud.task.util.TestListener; -import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -290,12 +288,6 @@ public class TaskExecutionListenerTests { return new AnnotatedTaskListener(); } - @Bean - public TaskListenerExecutorFactoryBean taskListenerExecutor(ConfigurableApplicationContext context) throws Exception - { - return new TaskListenerExecutorFactoryBean(context); - } - public static class AnnotatedTaskListener extends TestListener { @BeforeTask @@ -331,12 +323,6 @@ public class TaskExecutionListenerTests { return new AnnotatedTaskListener(); } - @Bean - public TaskListenerExecutorFactoryBean taskListenerExecutor(ConfigurableApplicationContext context) throws Exception - { - return new TaskListenerExecutorFactoryBean(context); - } - public static class AnnotatedTaskListener { @BeforeTask @@ -365,11 +351,6 @@ public class TaskExecutionListenerTests { return new AnnotatedTaskListener(); } - @Bean - public TaskListenerExecutorFactoryBean taskListenerExecutor(ConfigurableApplicationContext context) throws Exception - { - return new TaskListenerExecutorFactoryBean(context); - } public static class AnnotatedTaskListener { @@ -400,12 +381,6 @@ public class TaskExecutionListenerTests { return new AnnotatedTaskListener(); } - @Bean - public TaskListenerExecutorFactoryBean taskListenerExecutor(ConfigurableApplicationContext context) throws Exception - { - return new TaskListenerExecutorFactoryBean(context); - } - public static class AnnotatedTaskListener extends TestListener{ @BeforeTask diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskListenerExecutorObjectFactoryTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskListenerExecutorObjectFactoryTests.java new file mode 100644 index 00000000..0fd11c0d --- /dev/null +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskListenerExecutorObjectFactoryTests.java @@ -0,0 +1,141 @@ +/* + * Copyright 2018 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.listener; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.task.listener.annotation.AfterTask; +import org.springframework.cloud.task.listener.annotation.BeforeTask; +import org.springframework.cloud.task.listener.annotation.FailedTask; +import org.springframework.cloud.task.listener.annotation.TaskListenerExecutor; +import org.springframework.cloud.task.repository.TaskExecution; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Verifies that the {@link TaskListenerExecutorObjectFactory} retrieves the + * {@link TaskListenerExecutor}. + * + * @author Glenn Renfro + * @since 2.1.0 + */ +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = { TaskListenerExecutorObjectFactoryTests.TaskExecutionListenerConfiguration.class }) +public class TaskListenerExecutorObjectFactoryTests { + + public static final String BEFORE_LISTENER = "BEFORE LISTENER"; + + public static final String AFTER_LISTENER = "AFTER LISTENER"; + + public static final String FAIL_LISTENER = "FAIL LISTENER"; + + public static List taskExecutionListenerResults = new ArrayList<>(3); + + @Autowired + private ConfigurableApplicationContext context; + + private TaskListenerExecutor taskListenerExecutor; + + private TaskListenerExecutorObjectFactory taskListenerExecutorObjectFactory; + + @Before + public void setup() { + taskExecutionListenerResults.clear(); + this.taskListenerExecutorObjectFactory = new TaskListenerExecutorObjectFactory(this.context); + this.taskListenerExecutor = this.taskListenerExecutorObjectFactory.getObject(); + } + + @Test + public void verifyTaskStartupListener() { + this.taskListenerExecutor.onTaskStartup(createSampleTaskExecution(BEFORE_LISTENER)); + validateSingleEntry(BEFORE_LISTENER); + } + + @Test + public void verifyTaskFailedListener() { + this.taskListenerExecutor.onTaskFailed(createSampleTaskExecution(FAIL_LISTENER), + new IllegalStateException("oops")); + validateSingleEntry(FAIL_LISTENER); + } + + @Test + public void verifyTaskEndListener() { + this.taskListenerExecutor.onTaskEnd(createSampleTaskExecution(AFTER_LISTENER)); + validateSingleEntry(AFTER_LISTENER); + } + + @Test + public void verifyAllListener() { + this.taskListenerExecutor.onTaskStartup(createSampleTaskExecution(BEFORE_LISTENER)); + this.taskListenerExecutor.onTaskFailed(createSampleTaskExecution(FAIL_LISTENER), + new IllegalStateException("oops")); + this.taskListenerExecutor.onTaskEnd(createSampleTaskExecution(AFTER_LISTENER)); + assertThat(taskExecutionListenerResults.size()).isEqualTo(3); + assertThat(taskExecutionListenerResults.get(0).getTaskName()).isEqualTo(BEFORE_LISTENER); + assertThat(taskExecutionListenerResults.get(1).getTaskName()).isEqualTo(FAIL_LISTENER); + assertThat(taskExecutionListenerResults.get(2).getTaskName()).isEqualTo(AFTER_LISTENER); + } + + private TaskExecution createSampleTaskExecution(String taskName) { + TaskExecution taskExecution = new TaskExecution(); + taskExecution.setTaskName(taskName); + return taskExecution; + } + + private void validateSingleEntry(String event) { + assertThat(taskExecutionListenerResults.size()).isEqualTo(1); + assertThat(taskExecutionListenerResults.get(0).getTaskName()).isEqualTo(event); + } + + @Configuration + public static class TaskExecutionListenerConfiguration { + + @Bean + public TaskRunComponent taskRunComponent() { + return new TaskRunComponent(); + } + } + + public static class TaskRunComponent { + + @BeforeTask + public void initBeforeListener(TaskExecution taskExecution) { + TaskListenerExecutorObjectFactoryTests.taskExecutionListenerResults.add(taskExecution); + } + + @AfterTask + public void initAfterListener(TaskExecution taskExecution) { + TaskListenerExecutorObjectFactoryTests.taskExecutionListenerResults.add(taskExecution); + } + + @FailedTask + public void initFailedListener(TaskExecution taskExecution, Throwable exception) { + TaskListenerExecutorObjectFactoryTests.taskExecutionListenerResults.add(taskExecution); + } + } +} diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/SimpleTaskRepositoryJdbcTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/SimpleTaskRepositoryJdbcTests.java index caa30426..55506eef 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/SimpleTaskRepositoryJdbcTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/SimpleTaskRepositoryJdbcTests.java @@ -28,7 +28,7 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; -import org.springframework.cloud.task.configuration.SimpleTaskConfiguration; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; import org.springframework.cloud.task.repository.TaskExecution; import org.springframework.cloud.task.repository.TaskExplorer; import org.springframework.cloud.task.repository.TaskRepository; @@ -49,7 +49,7 @@ import static org.junit.Assert.assertEquals; */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {EmbeddedDataSourceConfiguration.class, - SimpleTaskConfiguration.class, + SimpleTaskAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class}) public class SimpleTaskRepositoryJdbcTests { 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 b758ab6f..c0e7e324 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 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2016 the original author or authors. + * Copyright 2015-2018 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. @@ -26,7 +26,7 @@ import org.junit.rules.ExpectedException; import org.springframework.beans.factory.BeanCreationException; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; -import org.springframework.cloud.task.configuration.SimpleTaskConfiguration; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; import org.springframework.cloud.task.configuration.TestConfiguration; import org.springframework.cloud.task.repository.dao.MapTaskExecutionDao; import org.springframework.context.annotation.AnnotationConfigApplicationContext; @@ -89,7 +89,7 @@ public class TaskDatabaseInitializerTests { @Test(expected = BeanCreationException.class) public void testMultipleDataSourcesContext() throws Exception { this.context = new AnnotationConfigApplicationContext(); - this.context.register( SimpleTaskConfiguration.class, + this.context.register( SimpleTaskAutoConfiguration.class, EmbeddedDataSourceConfiguration.class, PropertyPlaceholderAutoConfiguration.class); DataSource dataSource = mock(DataSource.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 a171a07b..7732c0e4 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 @@ -1,5 +1,5 @@ /* - * Copyright 2015-2016 the original author or authors. + * Copyright 2015-2018 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. @@ -24,6 +24,7 @@ import org.springframework.boot.ApplicationArguments; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.task.configuration.TaskProperties; import org.springframework.cloud.task.listener.TaskLifecycleListener; +import org.springframework.cloud.task.listener.TaskListenerExecutorObjectFactory; import org.springframework.cloud.task.repository.TaskExplorer; import org.springframework.cloud.task.repository.TaskNameResolver; import org.springframework.cloud.task.repository.TaskRepository; @@ -74,10 +75,15 @@ public class TestDefaultConfiguration implements InitializingBean { return new SimpleTaskNameResolver(); } + @Bean + public TaskListenerExecutorObjectFactory taskListenerExecutorObjectProvider(ConfigurableApplicationContext context) { + return new TaskListenerExecutorObjectFactory(context); + } + @Bean public TaskLifecycleListener taskHandler(TaskExplorer taskExplorer){ return new TaskLifecycleListener(taskRepository(), taskNameResolver(), - applicationArguments, taskExplorer, taskProperties); + applicationArguments, taskExplorer, taskProperties, taskListenerExecutorObjectProvider(context)); } @Override diff --git a/spring-cloud-task-dependencies/pom.xml b/spring-cloud-task-dependencies/pom.xml index 3a2fd0d2..3e3dede8 100644 --- a/spring-cloud-task-dependencies/pom.xml +++ b/spring-cloud-task-dependencies/pom.xml @@ -2,7 +2,7 @@ 4.0.0 spring-cloud-task-dependencies - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom Spring Cloud Task Dependencies Spring Cloud Task Dependencies @@ -10,7 +10,7 @@ spring-cloud-dependencies-parent org.springframework.cloud - 2.0.0.RELEASE + 2.1.0.BUILD-SNAPSHOT @@ -19,22 +19,22 @@ org.springframework.cloud spring-cloud-starter-task - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT org.springframework.cloud spring-cloud-task-core - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT org.springframework.cloud spring-cloud-task-batch - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT org.springframework.cloud spring-cloud-task-stream - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT diff --git a/spring-cloud-task-docs/pom.xml b/spring-cloud-task-docs/pom.xml index 0f4ef93b..8eaf32b3 100644 --- a/spring-cloud-task-docs/pom.xml +++ b/spring-cloud-task-docs/pom.xml @@ -4,7 +4,7 @@ org.springframework.cloud spring-cloud-task-parent - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT spring-cloud-task-docs Spring Cloud Task Docs diff --git a/spring-cloud-task-docs/src/main/asciidoc/batch.adoc b/spring-cloud-task-docs/src/main/asciidoc/batch.adoc index da5d6321..e1cd3825 100644 --- a/spring-cloud-task-docs/src/main/asciidoc/batch.adoc +++ b/spring-cloud-task-docs/src/main/asciidoc/batch.adoc @@ -217,7 +217,7 @@ Batch/Boot behavior. Keep in mind that a task is a boot application and that the returned from the task is the same as a boot application. To override this behavior and allow the task to return an exit code other than zero when a batch job returns an -https://docs.spring.io/spring-batch/4.0.x/reference/html/step.html#conditionalFlow[ExitStatus] +https://docs.spring.io/spring-batch/4.0.x/reference/html/step.html#batchStatusVsExitStatus[BatchStatus] of `FAILED`, set `spring.cloud.task.batch.fail-on-job-failure` to `true`. Then the exit code can be 1 (the default) or be based on the https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-spring-application.html#boot-features-application-exit[specified diff --git a/spring-cloud-task-docs/src/main/asciidoc/features.adoc b/spring-cloud-task-docs/src/main/asciidoc/features.adoc index 743dd5cd..00b4cacd 100644 --- a/spring-cloud-task-docs/src/main/asciidoc/features.adoc +++ b/spring-cloud-task-docs/src/main/asciidoc/features.adoc @@ -33,8 +33,7 @@ processes, typified by most web applications, do not save their lifecycle events tasks at the heart of Spring Cloud Task do. The lifecycle consists of a single task execution. This is a physical execution of a -Spring Boot application configured to be a task (that is, it has the `@EnableTask` -annotation). +Spring Boot application configured to be a task (that is, it has the Sprint Cloud Task dependencies). At the beginning of a task, before any `CommandLineRunner` or `ApplicationRunner` implementations have been run, an entry in the `TaskRepository` that records the start @@ -367,3 +366,14 @@ application: org.springframework.integration spring-integration-jdbc + +=== Disabling Spring Cloud Task Auto Configuration + +In cases where Spring Cloud Task should not be auto configured for an implementation, you can disable Task's auto configuration. +This can be done either by adding the following annotation to your Task application: +``` +@EnableAutoConfiguration(exclude={SimpleTaskAutoConfiguration.class}) +``` +You may also disable Task auto configuration by setting the `spring.cloud.task.autoconfiguration.enabled` property to `false`. + + diff --git a/spring-cloud-task-docs/src/main/asciidoc/getting-started.adoc b/spring-cloud-task-docs/src/main/asciidoc/getting-started.adoc index d039d752..e5e877e2 100755 --- a/spring-cloud-task-docs/src/main/asciidoc/getting-started.adoc +++ b/spring-cloud-task-docs/src/main/asciidoc/getting-started.adoc @@ -77,12 +77,11 @@ package io.spring.demo.helloworld; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.task.configuration.EnableTask; import org.springframework.context.annotation.Bean; @SpringBootApplication -@EnableTask public class HelloworldApplication { +public class SampleTask { @Bean public CommandLineRunner commandLineRunner() { @@ -124,13 +123,10 @@ spring.application.name=helloWorld ---- [[getting-started-at-task]] -==== The @EnableTask annotation +==== Task Auto Configuration -The first non-boot annotation in our example is the `@EnableTask` annotation. This -class-level annotation tells Spring Cloud Task to bootstrap it's functionality. By -default, it imports an additional configuration class (`SimpleTaskConfiguration`). This -additional configuration registers the `TaskRepository` and the infrastructure for its -use. +When including Spring Cloud Task Starter dependency, Task auto configures all beans to bootstrap it's functionality. +Part of this configuration registers the `TaskRepository` and the infrastructure for its use. In our demo, the `TaskRepository` uses an embedded H2 database to record the results of a task. This H2 embedded database is not a practical solution for a production environment, since diff --git a/spring-cloud-task-docs/src/main/asciidoc/stream.adoc b/spring-cloud-task-docs/src/main/asciidoc/stream.adoc index f4a0d7d8..af473d66 100644 --- a/spring-cloud-task-docs/src/main/asciidoc/stream.adoc +++ b/spring-cloud-task-docs/src/main/asciidoc/stream.adoc @@ -93,7 +93,6 @@ event on the `task-events` channel (at both the start and the end of the task): [source, java] ---- @SpringBootApplication -@EnableTask public class TaskEventsApplication { public static void main(String[] args) { diff --git a/spring-cloud-task-integration-tests/pom.xml b/spring-cloud-task-integration-tests/pom.xml index 24202898..ead1a69d 100644 --- a/spring-cloud-task-integration-tests/pom.xml +++ b/spring-cloud-task-integration-tests/pom.xml @@ -3,7 +3,7 @@ spring-cloud-task-parent org.springframework.cloud - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT 4.0.0 Spring Cloud Task Integration Tests @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-task-dependencies - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom import @@ -72,7 +72,7 @@ io.spring.cloud partitioned-batch-job - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT test diff --git a/spring-cloud-task-integration-tests/src/test/java/configuration/JobConfiguration.java b/spring-cloud-task-integration-tests/src/test/java/configuration/JobConfiguration.java index d09c9d55..cc6591c2 100644 --- a/spring-cloud-task-integration-tests/src/test/java/configuration/JobConfiguration.java +++ b/spring-cloud-task-integration-tests/src/test/java/configuration/JobConfiguration.java @@ -32,7 +32,6 @@ import org.springframework.batch.item.ItemWriter; import org.springframework.batch.item.support.ListItemReader; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cloud.task.configuration.EnableTask; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -41,7 +40,6 @@ import org.springframework.context.annotation.Configuration; */ @Configuration @EnableBatchProcessing -@EnableTask public class JobConfiguration { @Autowired private JobBuilderFactory jobBuilderFactory; diff --git a/spring-cloud-task-integration-tests/src/test/java/configuration/JobSkipConfiguration.java b/spring-cloud-task-integration-tests/src/test/java/configuration/JobSkipConfiguration.java index 0b33f572..dfa5e584 100644 --- a/spring-cloud-task-integration-tests/src/test/java/configuration/JobSkipConfiguration.java +++ b/spring-cloud-task-integration-tests/src/test/java/configuration/JobSkipConfiguration.java @@ -27,7 +27,6 @@ import org.springframework.batch.core.step.tasklet.Tasklet; import org.springframework.batch.item.ItemProcessor; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cloud.task.configuration.EnableTask; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -36,7 +35,6 @@ import org.springframework.context.annotation.Configuration; */ @Configuration @EnableBatchProcessing -@EnableTask public class JobSkipConfiguration { @Autowired private JobBuilderFactory jobBuilderFactory; diff --git a/spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/executionid/TaskStartApplication.java b/spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/executionid/TaskStartApplication.java index d07d5ca3..c09e3079 100644 --- a/spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/executionid/TaskStartApplication.java +++ b/spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/executionid/TaskStartApplication.java @@ -19,14 +19,12 @@ package org.springframework.cloud.task.executionid; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.task.configuration.EnableTask; import org.springframework.context.annotation.Bean; /** * @author Glenn Renfro */ @SpringBootApplication -@EnableTask public class TaskStartApplication { public static void main(String[] args) { diff --git a/spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/listener/TaskEventTests.java b/spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/listener/TaskEventTests.java index f88b094b..ffad327e 100644 --- a/spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/listener/TaskEventTests.java +++ b/spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/listener/TaskEventTests.java @@ -22,18 +22,22 @@ import org.junit.ClassRule; import org.junit.Test; import org.junit.runner.RunWith; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.cloud.stream.annotation.EnableBinding; import org.springframework.cloud.stream.annotation.StreamListener; import org.springframework.cloud.stream.binder.rabbit.config.RabbitServiceAutoConfiguration; import org.springframework.cloud.stream.binder.test.junit.rabbit.RabbitTestSupport; +import org.springframework.cloud.stream.config.BindingServiceConfiguration; import org.springframework.cloud.stream.messaging.Sink; -import org.springframework.cloud.task.configuration.EnableTask; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; +import org.springframework.cloud.task.configuration.SingleTaskConfiguration; import org.springframework.cloud.task.repository.TaskExecution; -import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.test.context.junit4.SpringRunner; @@ -59,21 +63,26 @@ public class TaskEventTests { @Test public void testTaskEventListener() throws Exception { - ConfigurableApplicationContext applicationContext = new SpringApplicationBuilder().sources(new Class[] {TaskEventsConfiguration.class, - TaskEventAutoConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - RabbitServiceAutoConfiguration.class}).build().run("--spring.cloud.task.closecontext_enabled=false", - "--spring.cloud.task.name=" + TASK_NAME, - "--spring.main.web-environment=false", - "--spring.cloud.stream.defaultBinder=rabbit", - "--spring.cloud.stream.bindings.task-events.destination=test"); - assertNotNull(applicationContext.getBean("taskEventListener")); - assertNotNull(applicationContext.getBean(TaskEventAutoConfiguration.TaskEventChannels.class)); + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(TaskEventsConfiguration.class, + TaskEventAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class, + RabbitServiceAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + BindingServiceConfiguration.class)) + .withPropertyValues("--spring.cloud.task.closecontext_enabled=false", + "--spring.cloud.task.name=" + TASK_NAME, + "--spring.main.web-environment=false", + "--spring.cloud.stream.defaultBinder=rabbit", + "--spring.cloud.stream.bindings.task-events.destination=test"); + applicationContextRunner.run((context) -> { + assertNotNull(context.getBean("taskEventListener")); + assertNotNull(context.getBean(TaskEventAutoConfiguration.TaskEventChannels.class)); + }); assertTrue(latch.await(1, TimeUnit.SECONDS)); } @Configuration - @EnableTask public static class TaskEventsConfiguration { } @@ -87,5 +96,15 @@ public class TaskEventTests { assertTrue(String.format("Task name should be '%s'", TASK_NAME), execution.getTaskName().equals(TASK_NAME)); latch.countDown(); } + + @Bean + public CommandLineRunner commandLineRunner(){ + return new CommandLineRunner() { + @Override + public void run(String... args) throws Exception { + System.out.println("Hello World"); + } + }; + } } } diff --git a/spring-cloud-task-samples/batch-events/pom.xml b/spring-cloud-task-samples/batch-events/pom.xml index 53e77e63..e8e1b958 100644 --- a/spring-cloud-task-samples/batch-events/pom.xml +++ b/spring-cloud-task-samples/batch-events/pom.xml @@ -4,7 +4,7 @@ io.spring.cloud batch-events - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT jar Batch Events Sample Application @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.0.BUILD-SNAPSHOT @@ -27,7 +27,7 @@ org.springframework.cloud spring-cloud-task-dependencies - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom import @@ -47,19 +47,19 @@ org.springframework.cloud spring-cloud-starter-stream-rabbit - 2.0.0.RELEASE + 2.1.0.BUILD-SNAPSHOT compile org.springframework.cloud spring-cloud-stream-binder-rabbit-test-support - 2.0.0.RELEASE + 2.1.0.BUILD-SNAPSHOT test org.springframework.cloud spring-cloud-stream-test-support-internal - 2.0.0.RELEASE + 2.1.0.BUILD-SNAPSHOT test @@ -70,6 +70,7 @@ org.hsqldb hsqldb + diff --git a/spring-cloud-task-samples/batch-events/src/main/java/io/spring/cloud/BatchEventsApplication.java b/spring-cloud-task-samples/batch-events/src/main/java/io/spring/cloud/BatchEventsApplication.java index cfee7c96..3a31a627 100644 --- a/spring-cloud-task-samples/batch-events/src/main/java/io/spring/cloud/BatchEventsApplication.java +++ b/spring-cloud-task-samples/batch-events/src/main/java/io/spring/cloud/BatchEventsApplication.java @@ -34,12 +34,10 @@ import org.springframework.batch.repeat.RepeatStatus; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.task.configuration.EnableTask; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @SpringBootApplication -@EnableTask @EnableBatchProcessing public class BatchEventsApplication { diff --git a/spring-cloud-task-samples/batch-events/src/test/java/io/spring/cloud/BatchEventsApplicationTests.java b/spring-cloud-task-samples/batch-events/src/test/java/io/spring/cloud/BatchEventsApplicationTests.java index 8d4563e0..5c69aa2d 100644 --- a/spring-cloud-task-samples/batch-events/src/test/java/io/spring/cloud/BatchEventsApplicationTests.java +++ b/spring-cloud-task-samples/batch-events/src/test/java/io/spring/cloud/BatchEventsApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2016-2018 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. @@ -50,12 +50,14 @@ public class BatchEventsApplicationTests { context.close(); } } - + @Test public void testExecution() throws Exception { SpringApplication.run(JobExecutionListenerBinding.class, "--spring.main.web-environment=false"); SpringApplication.run(BatchEventsApplication.class, "--server.port=0", - "--spring.cloud.stream.bindings.output.producer.requiredGroups=testgroup"); + "--spring.cloud.stream.bindings.output.producer.requiredGroups=testgroup", + "--spring.jmx.default-domain=fakedomain", + "--spring.main.webEnvironment=false"); Assert.assertTrue("The latch did not count down to zero before timeout", jobExecutionLatch.await(60, TimeUnit.SECONDS)); } diff --git a/spring-cloud-task-samples/batch-job/pom.xml b/spring-cloud-task-samples/batch-job/pom.xml index 39cc65cc..484f2853 100644 --- a/spring-cloud-task-samples/batch-job/pom.xml +++ b/spring-cloud-task-samples/batch-job/pom.xml @@ -5,7 +5,7 @@ io.spring.cloud batch-job jar - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT Spring Cloud Task Batch Example Batch Job Sample Application @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.0.BUILD-SNAPSHOT @@ -27,7 +27,7 @@ org.springframework.cloud spring-cloud-task-dependencies - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom import @@ -53,6 +53,10 @@ spring-boot-starter-test test + + org.mariadb.jdbc + mariadb-java-client + diff --git a/spring-cloud-task-samples/batch-job/src/main/java/io/spring/BatchJobApplication.java b/spring-cloud-task-samples/batch-job/src/main/java/io/spring/BatchJobApplication.java index b05f5579..d2237984 100644 --- a/spring-cloud-task-samples/batch-job/src/main/java/io/spring/BatchJobApplication.java +++ b/spring-cloud-task-samples/batch-job/src/main/java/io/spring/BatchJobApplication.java @@ -3,10 +3,8 @@ package io.spring; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.task.configuration.EnableTask; @SpringBootApplication -@EnableTask @EnableBatchProcessing public class BatchJobApplication { diff --git a/spring-cloud-task-samples/jpa-sample/pom.xml b/spring-cloud-task-samples/jpa-sample/pom.xml index 54aa371d..5ee60343 100644 --- a/spring-cloud-task-samples/jpa-sample/pom.xml +++ b/spring-cloud-task-samples/jpa-sample/pom.xml @@ -19,7 +19,7 @@ io.spring.cloud jpa-sample jar - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT To show users how to enable a task with a JPA application. Spring Cloud Task JPA Sample Application @@ -27,7 +27,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.0.BUILD-SNAPSHOT @@ -41,7 +41,7 @@ org.springframework.cloud spring-cloud-task-dependencies - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom import diff --git a/spring-cloud-task-samples/jpa-sample/src/main/java/io/spring/JpaApplication.java b/spring-cloud-task-samples/jpa-sample/src/main/java/io/spring/JpaApplication.java index 7675425b..46d76fe8 100644 --- a/spring-cloud-task-samples/jpa-sample/src/main/java/io/spring/JpaApplication.java +++ b/spring-cloud-task-samples/jpa-sample/src/main/java/io/spring/JpaApplication.java @@ -18,10 +18,8 @@ package io.spring; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.task.configuration.EnableTask; @SpringBootApplication -@EnableTask public class JpaApplication { public static void main(String[] args) { diff --git a/spring-cloud-task-samples/jpa-sample/src/test/java/io/spring/JpaApplicationTests.java b/spring-cloud-task-samples/jpa-sample/src/test/java/io/spring/JpaApplicationTests.java index 4b192bf0..67d64c29 100644 --- a/spring-cloud-task-samples/jpa-sample/src/test/java/io/spring/JpaApplicationTests.java +++ b/spring-cloud-task-samples/jpa-sample/src/test/java/io/spring/JpaApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2017-2018 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. @@ -101,7 +101,7 @@ public class JpaApplicationTests { assertTrue("Unable to find the insert message: " + output, output.contains(INSERT_MESSAGE)); JdbcTemplate template = new JdbcTemplate(this.dataSource); Map result = template.queryForMap("Select * from TASK_RUN_OUTPUT"); - assertThat((result.get("ID")), is(1L)); + assertThat((Long)(result.get("ID")), is(1L)); assertThat(((String) result.get("OUTPUT")), containsString("Executed at")); } diff --git a/spring-cloud-task-samples/multiple-datasources/pom.xml b/spring-cloud-task-samples/multiple-datasources/pom.xml index e5ab27f2..9daa1427 100644 --- a/spring-cloud-task-samples/multiple-datasources/pom.xml +++ b/spring-cloud-task-samples/multiple-datasources/pom.xml @@ -5,7 +5,7 @@ io.spring.cloud multiple-datasources jar - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT To show users how to enable a task with a multiple DataSources. Spring Cloud Task Multiple DataSources Application @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.0.BUILD-SNAPSHOT @@ -27,7 +27,7 @@ org.springframework.cloud spring-cloud-task-dependencies - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom import diff --git a/spring-cloud-task-samples/multiple-datasources/src/main/java/io/spring/MultipleDataSourcesApplication.java b/spring-cloud-task-samples/multiple-datasources/src/main/java/io/spring/MultipleDataSourcesApplication.java index 13311519..8d34fca5 100644 --- a/spring-cloud-task-samples/multiple-datasources/src/main/java/io/spring/MultipleDataSourcesApplication.java +++ b/spring-cloud-task-samples/multiple-datasources/src/main/java/io/spring/MultipleDataSourcesApplication.java @@ -18,14 +18,12 @@ package io.spring; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.task.configuration.EnableTask; /** * @author Michael Minella */ @SpringBootApplication -@EnableTask public class MultipleDataSourcesApplication { public static void main(String[] args) { diff --git a/spring-cloud-task-samples/partitioned-batch-job/pom.xml b/spring-cloud-task-samples/partitioned-batch-job/pom.xml index 317625d9..2483fc15 100644 --- a/spring-cloud-task-samples/partitioned-batch-job/pom.xml +++ b/spring-cloud-task-samples/partitioned-batch-job/pom.xml @@ -6,13 +6,13 @@ partitioned-batch-job jar Partitioned Batch Job - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT Sample of using the DeployerPartitionHandler org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.0.BUILD-SNAPSHOT @@ -26,7 +26,7 @@ org.springframework.cloud spring-cloud-task-dependencies - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom import diff --git a/spring-cloud-task-samples/partitioned-batch-job/src/main/java/io/spring/JobConfiguration.java b/spring-cloud-task-samples/partitioned-batch-job/src/main/java/io/spring/JobConfiguration.java index 113fc983..3e81dfc1 100644 --- a/spring-cloud-task-samples/partitioned-batch-job/src/main/java/io/spring/JobConfiguration.java +++ b/spring-cloud-task-samples/partitioned-batch-job/src/main/java/io/spring/JobConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2016-2018 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. @@ -81,15 +81,6 @@ public class JobConfiguration { private static final int GRID_SIZE = 4; - @Bean - public JobExplorerFactoryBean jobExplorer() { - JobExplorerFactoryBean jobExplorerFactoryBean = new JobExplorerFactoryBean(); - - jobExplorerFactoryBean.setDataSource(this.dataSource); - - return jobExplorerFactoryBean; - } - @Bean public PartitionHandler partitionHandler(TaskLauncher taskLauncher, JobExplorer jobExplorer) throws Exception { Resource resource = resourceLoader.getResource("maven://io.spring.cloud:partitioned-batch-job:1.1.0.RELEASE"); diff --git a/spring-cloud-task-samples/partitioned-batch-job/src/main/java/io/spring/PartitionedBatchJobApplication.java b/spring-cloud-task-samples/partitioned-batch-job/src/main/java/io/spring/PartitionedBatchJobApplication.java index 7a042cf1..692699aa 100644 --- a/spring-cloud-task-samples/partitioned-batch-job/src/main/java/io/spring/PartitionedBatchJobApplication.java +++ b/spring-cloud-task-samples/partitioned-batch-job/src/main/java/io/spring/PartitionedBatchJobApplication.java @@ -3,11 +3,9 @@ package io.spring; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.task.configuration.EnableTask; @SpringBootApplication @EnableBatchProcessing -@EnableTask public class PartitionedBatchJobApplication { public static void main(String[] args) { diff --git a/spring-cloud-task-samples/pom.xml b/spring-cloud-task-samples/pom.xml index 77b592e5..5800d766 100644 --- a/spring-cloud-task-samples/pom.xml +++ b/spring-cloud-task-samples/pom.xml @@ -11,7 +11,7 @@ org.springframework.cloud spring-cloud-task-parent - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT @@ -36,7 +36,7 @@ org.springframework.cloud spring-cloud-task-dependencies - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom import diff --git a/spring-cloud-task-samples/task-events/pom.xml b/spring-cloud-task-samples/task-events/pom.xml index 5529cbf3..90be4a6b 100644 --- a/spring-cloud-task-samples/task-events/pom.xml +++ b/spring-cloud-task-samples/task-events/pom.xml @@ -4,7 +4,7 @@ io.spring.cloud task-events - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT jar Task Events @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.0.BUILD-SNAPSHOT @@ -27,7 +27,7 @@ org.springframework.cloud spring-cloud-task-dependencies - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom import @@ -43,10 +43,9 @@ org.springframework.cloud spring-cloud-starter-stream-rabbit - 2.0.0.RELEASE + 2.1.0.BUILD-SNAPSHOT compile - org.springframework.boot spring-boot-starter-test diff --git a/spring-cloud-task-samples/task-events/src/main/java/io/spring/TaskEventsApplication.java b/spring-cloud-task-samples/task-events/src/main/java/io/spring/TaskEventsApplication.java index ee7093b7..4858e200 100644 --- a/spring-cloud-task-samples/task-events/src/main/java/io/spring/TaskEventsApplication.java +++ b/spring-cloud-task-samples/task-events/src/main/java/io/spring/TaskEventsApplication.java @@ -18,12 +18,10 @@ package io.spring; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.task.configuration.EnableTask; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @SpringBootApplication -@EnableTask public class TaskEventsApplication { public static void main(String[] args) { diff --git a/spring-cloud-task-samples/taskprocessor/pom.xml b/spring-cloud-task-samples/taskprocessor/pom.xml index df29d82a..15f5f3e0 100644 --- a/spring-cloud-task-samples/taskprocessor/pom.xml +++ b/spring-cloud-task-samples/taskprocessor/pom.xml @@ -4,7 +4,7 @@ io.spring.cloud taskprocessor - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT jar Task Processor Sample Application @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.0.BUILD-SNAPSHOT @@ -27,7 +27,7 @@ org.springframework.cloud spring-cloud-task-dependencies - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom import @@ -42,7 +42,7 @@ org.springframework.cloud spring-cloud-starter-stream-rabbit - 2.0.0.RELEASE + 2.1.0.BUILD-SNAPSHOT compile @@ -52,7 +52,7 @@ org.springframework.cloud spring-cloud-stream-test-support - 2.0.0.RELEASE + 2.1.0.BUILD-SNAPSHOT test diff --git a/spring-cloud-task-samples/tasksink/pom.xml b/spring-cloud-task-samples/tasksink/pom.xml index 0f966b54..f5ddabce 100644 --- a/spring-cloud-task-samples/tasksink/pom.xml +++ b/spring-cloud-task-samples/tasksink/pom.xml @@ -4,7 +4,7 @@ io.spring.cloud tasksink - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT jar Task Sink Sample Application @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.0.BUILD-SNAPSHOT @@ -27,7 +27,7 @@ org.springframework.cloud spring-cloud-task-dependencies - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom import @@ -42,13 +42,13 @@ org.springframework.cloud spring-cloud-starter-stream-rabbit - 2.0.0.RELEASE + 2.1.0.BUILD-SNAPSHOT compile org.springframework.cloud spring-cloud-stream-test-support - 2.0.0.RELEASE + 2.1.0.BUILD-SNAPSHOT test diff --git a/spring-cloud-task-samples/timestamp/pom.xml b/spring-cloud-task-samples/timestamp/pom.xml index adf64e93..89e804c3 100644 --- a/spring-cloud-task-samples/timestamp/pom.xml +++ b/spring-cloud-task-samples/timestamp/pom.xml @@ -7,13 +7,13 @@ timestamp-task jar Timestamp Task - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT Spring Cloud Timestamp Task org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.0.BUILD-SNAPSHOT @@ -27,7 +27,7 @@ org.springframework.cloud spring-cloud-task-dependencies - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom import @@ -57,6 +57,10 @@ com.h2database h2 + + org.mariadb.jdbc + mariadb-java-client + diff --git a/spring-cloud-task-samples/timestamp/src/main/java/org/springframework/cloud/task/timestamp/TaskApplication.java b/spring-cloud-task-samples/timestamp/src/main/java/org/springframework/cloud/task/timestamp/TaskApplication.java index 22e0cb0d..3d9bd8d8 100644 --- a/spring-cloud-task-samples/timestamp/src/main/java/org/springframework/cloud/task/timestamp/TaskApplication.java +++ b/spring-cloud-task-samples/timestamp/src/main/java/org/springframework/cloud/task/timestamp/TaskApplication.java @@ -29,14 +29,12 @@ import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.task.configuration.EnableTask; import org.springframework.context.annotation.Bean; /** * Spring Boot Application that has tasks enabled. */ @SpringBootApplication -@EnableTask @EnableConfigurationProperties({ TimestampTaskProperties.class }) public class TaskApplication { diff --git a/spring-cloud-task-stream/pom.xml b/spring-cloud-task-stream/pom.xml index 44e0a2e2..5059753d 100644 --- a/spring-cloud-task-stream/pom.xml +++ b/spring-cloud-task-stream/pom.xml @@ -10,7 +10,7 @@ org.springframework.cloud spring-cloud-task-parent - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT diff --git a/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/BatchEventAutoConfiguration.java b/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/BatchEventAutoConfiguration.java index 7c2707da..d28e5973 100644 --- a/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/BatchEventAutoConfiguration.java +++ b/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/BatchEventAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2016-2018 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. @@ -24,6 +24,7 @@ import org.springframework.batch.core.JobExecutionListener; import org.springframework.batch.core.SkipListener; import org.springframework.batch.core.StepExecutionListener; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -33,6 +34,7 @@ import org.springframework.cloud.stream.annotation.EnableBinding; import org.springframework.cloud.stream.annotation.Output; import org.springframework.cloud.task.batch.listener.support.TaskBatchEventListenerBeanPostProcessor; import org.springframework.cloud.task.batch.listener.support.TaskEventProperties; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; import org.springframework.cloud.task.listener.TaskLifecycleListener; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -60,6 +62,7 @@ import org.springframework.messaging.MessageChannel; @ConditionalOnClass(Job.class) @ConditionalOnBean(value = { Job.class, TaskLifecycleListener.class }) @ConditionalOnProperty(prefix = "spring.cloud.task.batch.events", name = "enabled", havingValue = "true", matchIfMissing = true) +@AutoConfigureAfter(SimpleTaskAutoConfiguration.class) public class BatchEventAutoConfiguration { public final static String JOB_EXECUTION_EVENTS_LISTENER = "jobExecutionEventsListener"; diff --git a/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/listener/TaskEventAutoConfiguration.java b/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/listener/TaskEventAutoConfiguration.java index 36142271..a5de53e8 100644 --- a/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/listener/TaskEventAutoConfiguration.java +++ b/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/listener/TaskEventAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2016-2018 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. @@ -15,12 +15,15 @@ */ package org.springframework.cloud.task.listener; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.stream.annotation.EnableBinding; import org.springframework.cloud.stream.annotation.Output; +import org.springframework.cloud.stream.config.BindingServiceConfiguration; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; @@ -36,21 +39,20 @@ import org.springframework.messaging.MessageChannel; @ConditionalOnBean(TaskLifecycleListener.class) @ConditionalOnProperty(prefix = "spring.cloud.task.events", name = "enabled", havingValue = "true", matchIfMissing = true) @PropertySource("classpath:/org/springframework/cloud/task/application.properties") +@AutoConfigureBefore(BindingServiceConfiguration.class) +@AutoConfigureAfter(SimpleTaskAutoConfiguration.class) public class TaskEventAutoConfiguration { @Configuration @EnableBinding(TaskEventChannels.class) public static class ListenerConfiguration { - @Autowired - private TaskEventChannels taskEventChannels; - @Bean public GatewayProxyFactoryBean taskEventListener() { GatewayProxyFactoryBean factoryBean = new GatewayProxyFactoryBean(TaskExecutionListener.class); - factoryBean.setDefaultRequestChannel(taskEventChannels.taskEvents()); + factoryBean.setDefaultRequestChannelName(TaskEventChannels.TASK_EVENTS); return factoryBean; } diff --git a/spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/batch/listener/JobExecutionEventTests.java b/spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/batch/listener/JobExecutionEventTests.java index e0770cb7..1e8088f9 100644 --- a/spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/batch/listener/JobExecutionEventTests.java +++ b/spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/batch/listener/JobExecutionEventTests.java @@ -34,15 +34,16 @@ import org.springframework.batch.core.JobParameters; import org.springframework.batch.core.StepExecution; import org.springframework.batch.item.ExecutionContext; import org.springframework.beans.factory.NoSuchBeanDefinitionException; -import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.cloud.stream.test.binder.TestSupportBinderAutoConfiguration; import org.springframework.cloud.task.batch.listener.support.JobExecutionEvent; import org.springframework.cloud.task.batch.listener.support.JobInstanceEvent; import org.springframework.cloud.task.batch.listener.support.StepExecutionEvent; -import org.springframework.cloud.task.configuration.EnableTask; -import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; +import org.springframework.cloud.task.configuration.SingleTaskConfiguration; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; @@ -275,12 +276,15 @@ public class JobExecutionEventTests { @Test public void testOrderConfiguration() { - ConfigurableApplicationContext applicationContext = - SpringApplication.run(new Class[]{BatchEventAutoConfiguration.JobExecutionListenerConfiguration.class, - EventJobExecutionConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - TestSupportBinderAutoConfiguration.class}, - new String[]{"--spring.cloud.task.closecontext_enabled=false", + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + EventJobExecutionConfiguration.class, + PropertyPlaceholderAutoConfiguration.class, + TestSupportBinderAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + SingleTaskConfiguration.class)) + .withUserConfiguration(BatchEventAutoConfiguration.JobExecutionListenerConfiguration.class) + .withPropertyValues("--spring.cloud.task.closecontext_enabled=false", "--spring.main.web-environment=false", "--spring.cloud.task.batch.events.chunk-order=5", "--spring.cloud.task.batch.events.item-process-order=5", @@ -288,30 +292,35 @@ public class JobExecutionEventTests { "--spring.cloud.task.batch.events.item-write-order=5", "--spring.cloud.task.batch.events.job-execution-order=5", "--spring.cloud.task.batch.events.skip-order=5", - "--spring.cloud.task.batch.events.step-execution-order=5" - }); + "--spring.cloud.task.batch.events.step-execution-order=5"); + applicationContextRunner.run((context) -> { for (String beanName : LISTENER_BEAN_NAMES) { - Ordered ordered = (Ordered)applicationContext.getBean(beanName); + Ordered ordered = (Ordered)context.getBean(beanName); assertEquals("Expected order value of 5 for " + beanName,ordered.getOrder(),5); } + + }); } private void testDisabledConfiguration(String property, String disabledListener) { - boolean exceptionThrown = false; String disabledPropertyArg = (property != null) ? "--" + property + "=false" : ""; - ConfigurableApplicationContext applicationContext = - SpringApplication.run(new Class[]{BatchEventAutoConfiguration.JobExecutionListenerConfiguration.class, + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( EventJobExecutionConfiguration.class, PropertyPlaceholderAutoConfiguration.class, - TestSupportBinderAutoConfiguration.class}, - new String[]{"--spring.cloud.task.closecontext_enabled=false", - "--spring.main.web-environment=false", - disabledPropertyArg}); - + TestSupportBinderAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + SingleTaskConfiguration.class)) + .withUserConfiguration(BatchEventAutoConfiguration.JobExecutionListenerConfiguration.class) + .withPropertyValues("--spring.cloud.task.closecontext_enabled=false", + "--spring.main.web-environment=false", + disabledPropertyArg); + applicationContextRunner.run((context) -> { + boolean exceptionThrown = false; for (String beanName : LISTENER_BEAN_NAMES) { if (disabledListener != null && disabledListener.equals(beanName)) { try { - applicationContext.getBean(disabledListener); + context.getBean(disabledListener); } catch (NoSuchBeanDefinitionException nsbde) { exceptionThrown = true; @@ -319,15 +328,15 @@ public class JobExecutionEventTests { assertTrue(String.format("Did not expect %s bean in context", beanName), exceptionThrown); } else { - applicationContext.getBean(beanName); + context.getBean(beanName); } } - applicationContext.getBean(BatchEventAutoConfiguration.BatchEventsChannels.class); + }); + } @Configuration - @EnableTask public static class EventJobExecutionConfiguration { } } diff --git a/spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/listener/TaskEventTests.java b/spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/listener/TaskEventTests.java index 6baaccb4..6c81adf1 100644 --- a/spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/listener/TaskEventTests.java +++ b/spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/listener/TaskEventTests.java @@ -17,13 +17,18 @@ package org.springframework.cloud.task.listener; import org.junit.Test; -import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.cloud.stream.config.BindingServiceConfiguration; import org.springframework.cloud.stream.test.binder.TestSupportBinderAutoConfiguration; -import org.springframework.cloud.task.configuration.EnableTask; -import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; +import org.springframework.cloud.task.configuration.SingleTaskConfiguration; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.integration.annotation.BridgeFrom; +import org.springframework.integration.channel.NullChannel; import static org.junit.Assert.assertNotNull; @@ -38,20 +43,31 @@ public class TaskEventTests { @Test public void testDefaultConfiguration() { - ConfigurableApplicationContext applicationContext = - SpringApplication.run(new Class[]{PropertyPlaceholderAutoConfiguration.class,EmbeddedDataSourceConfiguration.class,TaskEventsConfiguration.class, - TaskEventAutoConfiguration.class, - TestSupportBinderAutoConfiguration.class}, - new String[]{ "--spring.cloud.task.closecontext_enabled=false", - "--spring.main.web-environment=false"}); - - assertNotNull(applicationContext.getBean("taskEventListener")); - assertNotNull(applicationContext.getBean(TaskEventAutoConfiguration.TaskEventChannels.class)); + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(EmbeddedDataSourceConfiguration.class, + TaskEventAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class, + TestSupportBinderAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + SingleTaskConfiguration.class, + BindingServiceConfiguration.class)) + .withUserConfiguration(TaskEventsConfiguration.class) + .withPropertyValues("spring.cloud.task.closecontext_enabled=false", + "spring.main.web-environment=false"); + applicationContextRunner.run((context) -> { + assertNotNull(context.getBean("taskEventListener")); + assertNotNull(context.getBean(TaskEventAutoConfiguration.TaskEventChannels.class)); + }); } @Configuration - @EnableTask public static class TaskEventsConfiguration { + + @Bean + @BridgeFrom(TaskEventAutoConfiguration.TaskEventChannels.TASK_EVENTS) + public NullChannel testEmptyChannel() { + return new NullChannel(); + } } }