Added checkstyle

This commit is contained in:
Marcin Grzejszczak
2019-02-03 19:27:07 +01:00
parent 4d0acf120c
commit 60f1e21d03
249 changed files with 7450 additions and 5857 deletions

14
.editorconfig Normal file
View File

@@ -0,0 +1,14 @@
# EditorConfig is awesome: http://EditorConfig.org
# top-most EditorConfig file
root = true
[*]
indent_style = tab
indent_size = 4
end_of_line = lf
insert_final_newline = true
[*.yml]
indent_style = space
indent_size = 2

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- <!--
~ /* ~ /*
~ * Copyright 2015 the original author or authors. ~ * Copyright 2015-2019 the original author or authors.
~ * ~ *
~ * Licensed under the Apache License, Version 2.0 (the "License"); ~ * Licensed under the Apache License, Version 2.0 (the "License");
~ * you may not use this file except in compliance with the License. ~ * you may not use this file except in compliance with the License.
@@ -34,7 +34,9 @@
this settings file, or copy the profile into their ~/.m2/settings.xml. this settings file, or copy the profile into their ~/.m2/settings.xml.
--> -->
<id>spring</id> <id>spring</id>
<activation><activeByDefault>true</activeByDefault></activation> <activation>
<activeByDefault>true</activeByDefault>
</activation>
<repositories> <repositories>
<repository> <repository>
<id>spring-snapshots</id> <id>spring-snapshots</id>

0
.springformat Normal file
View File

54
pom.xml
View File

@@ -1,12 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-build</artifactId> <artifactId>spring-cloud-build</artifactId>
<version>2.1.1.RELEASE</version> <version>2.1.3.BUILD-SNAPSHOT</version>
<relativePath /> <relativePath/>
</parent> </parent>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
@@ -126,15 +128,24 @@
<properties> <properties>
<spring-cloud-stream.version>2.1.0.RELEASE</spring-cloud-stream.version> <spring-cloud-stream.version>2.1.0.RELEASE</spring-cloud-stream.version>
<spring-cloud-deployer.version>2.0.0.RELEASE</spring-cloud-deployer.version> <spring-cloud-deployer.version>2.0.0.RELEASE</spring-cloud-deployer.version>
<spring-cloud-deployer-local.version>2.0.0.RELEASE</spring-cloud-deployer-local.version> <spring-cloud-deployer-local.version>2.0.0.RELEASE
<spring-cloud-stream-binder-rabbit.version>2.1.0.RELEASE</spring-cloud-stream-binder-rabbit.version> </spring-cloud-deployer-local.version>
<spring-cloud-stream-binder-rabbit.version>2.1.0.RELEASE
</spring-cloud-stream-binder-rabbit.version>
<spring-batch.version>4.1.1.RELEASE</spring-batch.version> <spring-batch.version>4.1.1.RELEASE</spring-batch.version>
<commons-logging.version>1.1</commons-logging.version> <commons-logging.version>1.1</commons-logging.version>
<java-ee-api.version>8.0</java-ee-api.version> <java-ee-api.version>8.0</java-ee-api.version>
<junit.version>5.3.1</junit.version> <junit.version>5.3.1</junit.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<sonar.jacoco.reportPath>${project.build.directory}/coverage-reports/jacoco-ut.exec</sonar.jacoco.reportPath> <sonar.jacoco.reportPath>
${project.build.directory}/coverage-reports/jacoco-ut.exec
</sonar.jacoco.reportPath>
<maven-checkstyle-plugin.failsOnError>true</maven-checkstyle-plugin.failsOnError>
<maven-checkstyle-plugin.failsOnViolation>true
</maven-checkstyle-plugin.failsOnViolation>
<maven-checkstyle-plugin.includeTestSourceDirectory>true
</maven-checkstyle-plugin.includeTestSourceDirectory>
</properties> </properties>
<build> <build>
@@ -211,7 +222,9 @@
</goals> </goals>
<configuration> <configuration>
<!-- Sets the path to the file which contains the execution data. --> <!-- Sets the path to the file which contains the execution data. -->
<destFile>${project.build.directory}/coverage-reports/jacoco-ut.exec</destFile> <destFile>
${project.build.directory}/coverage-reports/jacoco-ut.exec
</destFile>
<!-- <!--
Sets the name of the property containing the settings Sets the name of the property containing the settings
for JaCoCo runtime agent. for JaCoCo runtime agent.
@@ -231,15 +244,38 @@
</goals> </goals>
<configuration> <configuration>
<!-- Sets the path to the file which contains the execution data. --> <!-- Sets the path to the file which contains the execution data. -->
<dataFile>${project.build.directory}/coverage-reports/jacoco-ut.exec</dataFile> <dataFile>
${project.build.directory}/coverage-reports/jacoco-ut.exec
</dataFile>
<!-- Sets the output directory for the code coverage report. --> <!-- Sets the output directory for the code coverage report. -->
<outputDirectory>${project.reporting.outputDirectory}/jacoco-ut</outputDirectory> <outputDirectory>
${project.reporting.outputDirectory}/jacoco-ut
</outputDirectory>
</configuration> </configuration>
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
</plugin>
<plugin>
<groupId>io.spring.javaformat</groupId>
<artifactId>spring-javaformat-maven-plugin</artifactId>
</plugin>
</plugins> </plugins>
</build> </build>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
</plugin>
</plugins>
</reporting>
<profiles> <profiles>
<profile> <profile>
<id>spring</id> <id>spring</id>

View File

@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -12,7 +14,8 @@
<artifactId>spring-cloud-task-batch</artifactId> <artifactId>spring-cloud-task-batch</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>Spring Cloud Task Batch</name> <name>Spring Cloud Task Batch</name>
<description>Module for use when combining Spring Cloud Task with Spring Batch</description> <description>Module for use when combining Spring Cloud Task with Spring Batch
</description>
<dependencies> <dependencies>
<dependency> <dependency>
@@ -79,7 +82,7 @@
<groupId>org.assertj</groupId> <groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId> <artifactId>assertj-core</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId> <artifactId>junit-jupiter-api</artifactId>

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.configuration; package org.springframework.cloud.task.batch.configuration;
import org.springframework.batch.core.Job; import org.springframework.batch.core.Job;
@@ -38,8 +39,9 @@ import org.springframework.context.annotation.Configuration;
* @author Michael Minella * @author Michael Minella
*/ */
@Configuration @Configuration
@ConditionalOnBean({Job.class}) @ConditionalOnBean({ Job.class })
@ConditionalOnProperty(name = {"spring.cloud.task.batch.listener.enable", "spring.cloud.task.batch.listener.enabled"}, havingValue = "true", matchIfMissing = true) @ConditionalOnProperty(name = { "spring.cloud.task.batch.listener.enable",
"spring.cloud.task.batch.listener.enabled" }, havingValue = "true", matchIfMissing = true)
public class TaskBatchAutoConfiguration { public class TaskBatchAutoConfiguration {
@Bean @Bean
@@ -48,6 +50,9 @@ public class TaskBatchAutoConfiguration {
return new TaskBatchExecutionListenerBeanPostProcessor(); return new TaskBatchExecutionListenerBeanPostProcessor();
} }
/**
* Auto configuration for Task Batch Execution Listener.
*/
@Configuration @Configuration
@ConditionalOnMissingBean(name = "taskBatchExecutionListener") @ConditionalOnMissingBean(name = "taskBatchExecutionListener")
@EnableConfigurationProperties(TaskProperties.class) @EnableConfigurationProperties(TaskProperties.class)
@@ -60,20 +65,23 @@ public class TaskBatchAutoConfiguration {
private TaskProperties taskProperties; private TaskProperties taskProperties;
@Bean @Bean
public TaskBatchExecutionListenerFactoryBean taskBatchExecutionListener(TaskExplorer taskExplorer) { public TaskBatchExecutionListenerFactoryBean taskBatchExecutionListener(
TaskExplorer taskExplorer) {
TaskConfigurer taskConfigurer = null; TaskConfigurer taskConfigurer = null;
if(!this.context.getBeansOfType(TaskConfigurer.class).isEmpty()) { if (!this.context.getBeansOfType(TaskConfigurer.class).isEmpty()) {
taskConfigurer = this.context.getBean(TaskConfigurer.class); taskConfigurer = this.context.getBean(TaskConfigurer.class);
} }
if(taskConfigurer != null && taskConfigurer.getTaskDataSource() != null) { if (taskConfigurer != null && taskConfigurer.getTaskDataSource() != null) {
return new TaskBatchExecutionListenerFactoryBean( return new TaskBatchExecutionListenerFactoryBean(
taskConfigurer.getTaskDataSource(), taskConfigurer.getTaskDataSource(), taskExplorer,
taskExplorer, taskProperties.getTablePrefix()); this.taskProperties.getTablePrefix());
} }
else { else {
return new TaskBatchExecutionListenerFactoryBean(null, return new TaskBatchExecutionListenerFactoryBean(null, taskExplorer,
taskExplorer, taskProperties.getTablePrefix()); this.taskProperties.getTablePrefix());
} }
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.configuration; package org.springframework.cloud.task.batch.configuration;
import java.util.ArrayList; import java.util.ArrayList;
@@ -28,7 +29,7 @@ import org.springframework.util.Assert;
/** /**
* Injects a configured {@link TaskBatchExecutionListener} into any batch jobs (beans * Injects a configured {@link TaskBatchExecutionListener} into any batch jobs (beans
* assignable to {@link AbstractJob}) that are executed within the scope of a task. The * assignable to {@link AbstractJob}) that are executed within the scope of a task. The
* context this is used within is expected to have only one bean of type * context this is used within is expected to have only one bean of type
* {@link TaskBatchExecutionListener}. * {@link TaskBatchExecutionListener}.
* *
@@ -50,17 +51,17 @@ public class TaskBatchExecutionListenerBeanPostProcessor implements BeanPostProc
@Override @Override
public Object postProcessAfterInitialization(Object bean, String beanName) public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException { throws BeansException {
if(jobNames.size() > 0 && !jobNames.contains(beanName)) { if (this.jobNames.size() > 0 && !this.jobNames.contains(beanName)) {
return bean; return bean;
} }
int length = this.applicationContext int length = this.applicationContext
.getBeanNamesForType(TaskBatchExecutionListener.class).length; .getBeanNamesForType(TaskBatchExecutionListener.class).length;
if(bean instanceof AbstractJob) { if (bean instanceof AbstractJob) {
if(length != 1) { if (length != 1) {
throw new IllegalStateException("The application context is required to " + throw new IllegalStateException("The application context is required to "
"have exactly 1 instance of the TaskBatchExecutionListener but has " + + "have exactly 1 instance of the TaskBatchExecutionListener but has "
length); + length);
} }
((AbstractJob) bean).registerJobExecutionListener( ((AbstractJob) bean).registerJobExecutionListener(
this.applicationContext.getBean(TaskBatchExecutionListener.class)); this.applicationContext.getBean(TaskBatchExecutionListener.class));
@@ -73,4 +74,5 @@ public class TaskBatchExecutionListenerBeanPostProcessor implements BeanPostProc
this.jobNames = jobNames; this.jobNames = jobNames;
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,9 +13,11 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.configuration; package org.springframework.cloud.task.batch.configuration;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import javax.sql.DataSource; import javax.sql.DataSource;
import org.springframework.aop.framework.Advised; import org.springframework.aop.framework.Advised;
@@ -32,13 +34,14 @@ import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;
/** /**
* {@link FactoryBean} for a {@link TaskBatchExecutionListener}. Provides a jdbc based * {@link FactoryBean} for a {@link TaskBatchExecutionListener}. Provides a jdbc based
* listener if there is a {@link DataSource} available. Otherwise, builds a listener that * listener if there is a {@link DataSource} available. Otherwise, builds a listener that
* uses the map based implementation. * uses the map based implementation.
* *
* @author Michael Minella * @author Michael Minella
*/ */
public class TaskBatchExecutionListenerFactoryBean implements FactoryBean<TaskBatchExecutionListener> { public class TaskBatchExecutionListenerFactoryBean
implements FactoryBean<TaskBatchExecutionListener> {
private TaskBatchExecutionListener listener; private TaskBatchExecutionListener listener;
@@ -49,45 +52,45 @@ public class TaskBatchExecutionListenerFactoryBean implements FactoryBean<TaskBa
private String tablePrefix = TaskProperties.DEFAULT_TABLE_PREFIX; private String tablePrefix = TaskProperties.DEFAULT_TABLE_PREFIX;
/** /**
* Initializes the TaskBatchExecutionListenerFactoryBean and defaults the * Initializes the TaskBatchExecutionListenerFactoryBean and defaults the tablePrefix
* tablePrefix to {@link TaskProperties#DEFAULT_TABLE_PREFIX}. * to {@link TaskProperties#DEFAULT_TABLE_PREFIX}.
*
* @param dataSource the dataSource to use for the TaskBatchExecutionListener. * @param dataSource the dataSource to use for the TaskBatchExecutionListener.
* @param taskExplorer the taskExplorer to use for the TaskBatchExecutionListener. * @param taskExplorer the taskExplorer to use for the TaskBatchExecutionListener.
*/ */
public TaskBatchExecutionListenerFactoryBean(DataSource dataSource, TaskExplorer taskExplorer) { public TaskBatchExecutionListenerFactoryBean(DataSource dataSource,
TaskExplorer taskExplorer) {
this.dataSource = dataSource; this.dataSource = dataSource;
this.taskExplorer = taskExplorer; this.taskExplorer = taskExplorer;
} }
/** /**
* Initializes the TaskBatchExecutionListenerFactoryBean. * Initializes the TaskBatchExecutionListenerFactoryBean.
*
* @param dataSource the dataSource to use for the TaskBatchExecutionListener. * @param dataSource the dataSource to use for the TaskBatchExecutionListener.
* @param taskExplorer the taskExplorer to use for the TaskBatchExecutionListener. * @param taskExplorer the taskExplorer to use for the TaskBatchExecutionListener.
* @param tablePrefix the prefix for the task tables accessed by the * @param tablePrefix the prefix for the task tables accessed by the
* TaskBatchExecutionListener. * TaskBatchExecutionListener.
*/ */
public TaskBatchExecutionListenerFactoryBean(DataSource dataSource, TaskExplorer taskExplorer, String tablePrefix) { public TaskBatchExecutionListenerFactoryBean(DataSource dataSource,
this(dataSource,taskExplorer); TaskExplorer taskExplorer, String tablePrefix) {
this(dataSource, taskExplorer);
Assert.hasText(tablePrefix, "tablePrefix must not be null nor empty."); Assert.hasText(tablePrefix, "tablePrefix must not be null nor empty.");
this.tablePrefix = tablePrefix; this.tablePrefix = tablePrefix;
} }
@Override @Override
public TaskBatchExecutionListener getObject() throws Exception { public TaskBatchExecutionListener getObject() throws Exception {
if(listener != null){ if (this.listener != null) {
return listener; return this.listener;
} }
if(this.dataSource == null) { if (this.dataSource == null) {
this.listener = new TaskBatchExecutionListener(getMapTaskBatchDao()); this.listener = new TaskBatchExecutionListener(getMapTaskBatchDao());
} }
else { else {
this.listener = new TaskBatchExecutionListener( this.listener = new TaskBatchExecutionListener(
new JdbcTaskBatchDao(this.dataSource, tablePrefix)); new JdbcTaskBatchDao(this.dataSource, this.tablePrefix));
} }
return listener; return this.listener;
} }
@Override @Override
@@ -101,22 +104,25 @@ public class TaskBatchExecutionListenerFactoryBean implements FactoryBean<TaskBa
} }
private MapTaskBatchDao getMapTaskBatchDao() throws Exception { private MapTaskBatchDao getMapTaskBatchDao() throws Exception {
Field taskExecutionDaoField = ReflectionUtils.findField(SimpleTaskExplorer.class, "taskExecutionDao"); Field taskExecutionDaoField = ReflectionUtils.findField(SimpleTaskExplorer.class,
"taskExecutionDao");
taskExecutionDaoField.setAccessible(true); taskExecutionDaoField.setAccessible(true);
MapTaskExecutionDao taskExecutionDao; MapTaskExecutionDao taskExecutionDao;
if(AopUtils.isJdkDynamicProxy(this.taskExplorer)) { if (AopUtils.isJdkDynamicProxy(this.taskExplorer)) {
SimpleTaskExplorer dereferencedTaskRepository = (SimpleTaskExplorer) ((Advised) this.taskExplorer).getTargetSource().getTarget(); SimpleTaskExplorer dereferencedTaskRepository = (SimpleTaskExplorer) ((Advised) this.taskExplorer)
.getTargetSource().getTarget();
taskExecutionDao = taskExecutionDao = (MapTaskExecutionDao) ReflectionUtils
(MapTaskExecutionDao) ReflectionUtils.getField(taskExecutionDaoField, dereferencedTaskRepository); .getField(taskExecutionDaoField, dereferencedTaskRepository);
} }
else { else {
taskExecutionDao = taskExecutionDao = (MapTaskExecutionDao) ReflectionUtils
(MapTaskExecutionDao) ReflectionUtils.getField(taskExecutionDaoField, this.taskExplorer); .getField(taskExecutionDaoField, this.taskExplorer);
} }
return new MapTaskBatchDao(taskExecutionDao.getBatchJobAssociations()); return new MapTaskBatchDao(taskExecutionDao.getBatchJobAssociations());
} }
} }

View File

@@ -1,17 +1,17 @@
/* /*
* Copyright 2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.configuration; package org.springframework.cloud.task.batch.configuration;
@@ -19,18 +19,17 @@ package org.springframework.cloud.task.batch.configuration;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
/** /**
* Establish properties to be used for how Tasks work with * Establish properties to be used for how Tasks work with Spring Batch.
* Spring Batch.
* *
* @author Glenn Renfro * @author Glenn Renfro
* @author Michael Minella * @author Michael Minella
*
* @since 2.0.0 * @since 2.0.0
*/ */
@ConfigurationProperties(prefix = "spring.cloud.task.batch") @ConfigurationProperties(prefix = "spring.cloud.task.batch")
public class TaskBatchProperties { public class TaskBatchProperties {
private static final long DEFAULT_POLL_INTERVAL = 5000L; private static final long DEFAULT_POLL_INTERVAL = 5000L;
/** /**
* Comma-separated list of job names to execute on startup (for instance, * Comma-separated list of job names to execute on startup (for instance,
* `job1,job2`). By default, all Jobs found in the context are executed. * `job1,job2`). By default, all Jobs found in the context are executed.
@@ -39,16 +38,16 @@ public class TaskBatchProperties {
/** /**
* The order for the {@code 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 * {@code spring.cloud.task.batch.fail-on-job-failure=true}. Defaults to 0 (same as
* the
* {@link org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner}). * {@link org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner}).
*/ */
private int commandLineRunnerOrder = 0; private int commandLineRunnerOrder = 0;
/** /**
* Fixed delay in milliseconds that Spring Cloud Task will wait when checking if * Fixed delay in milliseconds that Spring Cloud Task will wait when checking if
* {@link org.springframework.batch.core.JobExecution}s have completed, * {@link org.springframework.batch.core.JobExecution}s have completed, when
* when spring.cloud.task.batch.failOnJobFailure is set to true. Defaults * spring.cloud.task.batch.failOnJobFailure is set to true. Defaults to 5000.
* to 5000.
*/ */
private long failOnJobFailurePollInterval = DEFAULT_POLL_INTERVAL; private long failOnJobFailurePollInterval = DEFAULT_POLL_INTERVAL;
@@ -61,7 +60,7 @@ public class TaskBatchProperties {
} }
public int getCommandLineRunnerOrder() { public int getCommandLineRunnerOrder() {
return commandLineRunnerOrder; return this.commandLineRunnerOrder;
} }
public void setCommandLineRunnerOrder(int commandLineRunnerOrder) { public void setCommandLineRunnerOrder(int commandLineRunnerOrder) {
@@ -69,10 +68,11 @@ public class TaskBatchProperties {
} }
public long getFailOnJobFailurePollInterval() { public long getFailOnJobFailurePollInterval() {
return failOnJobFailurePollInterval; return this.failOnJobFailurePollInterval;
} }
public void setFailOnJobFailurePollInterval(long failOnJobFailurePollInterval) { public void setFailOnJobFailurePollInterval(long failOnJobFailurePollInterval) {
this.failOnJobFailurePollInterval = failOnJobFailurePollInterval; this.failOnJobFailurePollInterval = failOnJobFailurePollInterval;
} }
} }

View File

@@ -1,17 +1,17 @@
/* /*
* Copyright 2018 the original author or authors. * Copyright 2015-2019 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 * Licensed under the Apache License, Version 2.0 (the "License");
* distributed under the License is distributed on an "AS IS" BASIS, * you may not use this file except in compliance with the License.
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * You may obtain a copy of the License at
* See the License for the specific language governing permissions and *
* limitations under the License. * 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; package org.springframework.cloud.task.batch.configuration;
@@ -47,16 +47,15 @@ public class TaskJobLauncherAutoConfiguration {
private TaskBatchProperties properties; private TaskBatchProperties properties;
@Bean @Bean
public TaskJobLauncherCommandLineRunnerFactoryBean jobLauncherCommandLineRunner(JobLauncher jobLauncher, public TaskJobLauncherCommandLineRunnerFactoryBean jobLauncherCommandLineRunner(
JobExplorer jobExplorer, List<Job> jobs, JobRegistry jobRegistry, JobRepository jobRepository) { JobLauncher jobLauncher, JobExplorer jobExplorer, List<Job> jobs,
TaskJobLauncherCommandLineRunnerFactoryBean taskJobLauncherCommandLineRunnerFactoryBean = JobRegistry jobRegistry, JobRepository jobRepository) {
new TaskJobLauncherCommandLineRunnerFactoryBean(jobLauncher, TaskJobLauncherCommandLineRunnerFactoryBean taskJobLauncherCommandLineRunnerFactoryBean;
jobExplorer, taskJobLauncherCommandLineRunnerFactoryBean = new TaskJobLauncherCommandLineRunnerFactoryBean(
jobs, jobLauncher, jobExplorer, jobs, this.properties, jobRegistry,
this.properties, jobRepository);
jobRegistry,
jobRepository);
return taskJobLauncherCommandLineRunnerFactoryBean; return taskJobLauncherCommandLineRunnerFactoryBean;
} }
} }

View File

@@ -1,17 +1,17 @@
/* /*
* Copyright 2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.configuration; package org.springframework.cloud.task.batch.configuration;
@@ -33,7 +33,8 @@ import org.springframework.util.StringUtils;
* *
* @author Glenn Renfro * @author Glenn Renfro
*/ */
public class TaskJobLauncherCommandLineRunnerFactoryBean implements FactoryBean<TaskJobLauncherCommandLineRunner> { public class TaskJobLauncherCommandLineRunnerFactoryBean
implements FactoryBean<TaskJobLauncherCommandLineRunner> {
private JobLauncher jobLauncher; private JobLauncher jobLauncher;
@@ -52,8 +53,9 @@ public class TaskJobLauncherCommandLineRunnerFactoryBean implements FactoryBean<
private JobRepository jobRepository; private JobRepository jobRepository;
public TaskJobLauncherCommandLineRunnerFactoryBean(JobLauncher jobLauncher, public TaskJobLauncherCommandLineRunnerFactoryBean(JobLauncher jobLauncher,
JobExplorer jobExplorer, List<Job> jobs, TaskBatchProperties taskBatchProperties, JobExplorer jobExplorer, List<Job> jobs,
JobRegistry jobRegistry, JobRepository jobRepository) { TaskBatchProperties taskBatchProperties, JobRegistry jobRegistry,
JobRepository jobRepository) {
Assert.notNull(taskBatchProperties, "properties must not be null"); Assert.notNull(taskBatchProperties, "properties must not be null");
this.jobLauncher = jobLauncher; this.jobLauncher = jobLauncher;
this.jobExplorer = jobExplorer; this.jobExplorer = jobExplorer;
@@ -72,15 +74,16 @@ public class TaskJobLauncherCommandLineRunnerFactoryBean implements FactoryBean<
@Override @Override
public TaskJobLauncherCommandLineRunner getObject() { public TaskJobLauncherCommandLineRunner getObject() {
TaskJobLauncherCommandLineRunner taskJobLauncherCommandLineRunner = TaskJobLauncherCommandLineRunner taskJobLauncherCommandLineRunner = new TaskJobLauncherCommandLineRunner(
new TaskJobLauncherCommandLineRunner(this.jobLauncher, this.jobExplorer, this.jobRepository, this.taskBatchProperties); this.jobLauncher, this.jobExplorer, this.jobRepository,
this.taskBatchProperties);
taskJobLauncherCommandLineRunner.setJobs(this.jobs); taskJobLauncherCommandLineRunner.setJobs(this.jobs);
if(StringUtils.hasText(this.jobNames)) { if (StringUtils.hasText(this.jobNames)) {
taskJobLauncherCommandLineRunner.setJobNames(this.jobNames); taskJobLauncherCommandLineRunner.setJobNames(this.jobNames);
} }
taskJobLauncherCommandLineRunner.setJobRegistry(this.jobRegistry); taskJobLauncherCommandLineRunner.setJobRegistry(this.jobRegistry);
if(this.order != null) { if (this.order != null) {
taskJobLauncherCommandLineRunner.setOrder(this.order); taskJobLauncherCommandLineRunner.setOrder(this.order);
} }
return taskJobLauncherCommandLineRunner; return taskJobLauncherCommandLineRunner;

View File

@@ -1,17 +1,17 @@
/* /*
* Copyright 2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.handler; package org.springframework.cloud.task.batch.handler;
@@ -57,11 +57,11 @@ import org.springframework.util.StringUtils;
* {@link CommandLineRunner} to {@link JobLauncher launch} Spring Batch jobs. Runs all * {@link CommandLineRunner} to {@link JobLauncher launch} Spring Batch jobs. Runs all
* jobs in the surrounding context by default and throws an exception upon the first job * 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 * that returns an {@link BatchStatus} of FAILED if a {@link TaskExecutor} in the
* {@link JobLauncher} is not specified. If a {@link TaskExecutor} is specified * {@link JobLauncher} is not specified. If a {@link TaskExecutor} is specified in the
* in the {@link JobLauncher} then all Jobs are launched and an * {@link JobLauncher} then all Jobs are launched and an exception is thrown if one or
* exception is thrown if one or more of the jobs has an {@link BatchStatus} of FAILED. * more of the jobs has an {@link BatchStatus} of FAILED. TaskJobLauncherCommandLineRunner
* TaskJobLauncherCommandLineRunner can also be used to launch a specific job by * can also be used to launch a specific job by providing a jobName. The
* providing a jobName. The TaskJobLaunchercommandLineRunner takes the place of the * TaskJobLaunchercommandLineRunner takes the place of the
* {@link org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner} when * {@link org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner} when
* it is in use. * it is in use.
* *
@@ -70,15 +70,15 @@ import org.springframework.util.StringUtils;
*/ */
public class TaskJobLauncherCommandLineRunner extends JobLauncherCommandLineRunner { public class TaskJobLauncherCommandLineRunner extends JobLauncherCommandLineRunner {
private static final Log logger = LogFactory
.getLog(TaskJobLauncherCommandLineRunner.class);
private JobLauncher taskJobLauncher; private JobLauncher taskJobLauncher;
private JobExplorer taskJobExplorer; private JobExplorer taskJobExplorer;
private JobRepository taskJobRepository; private JobRepository taskJobRepository;
private static final Log logger = LogFactory
.getLog(TaskJobLauncherCommandLineRunner.class);
private List<JobExecution> jobExecutionList = new ArrayList<>(); private List<JobExecution> jobExecutionList = new ArrayList<>();
private ApplicationEventPublisher taskApplicationEventPublisher; private ApplicationEventPublisher taskApplicationEventPublisher;
@@ -91,10 +91,12 @@ public class TaskJobLauncherCommandLineRunner extends JobLauncherCommandLineRunn
* @param jobExplorer to check the job repository for previous executions * @param jobExplorer to check the job repository for previous executions
* @param jobRepository to check if a job instance exists with the given parameters * @param jobRepository to check if a job instance exists with the given parameters
* when running a job * when running a job
* @param taskBatchProperties the properties used to configure the taskBatchProperties. * @param taskBatchProperties the properties used to configure the
* taskBatchProperties.
*/ */
public TaskJobLauncherCommandLineRunner(JobLauncher jobLauncher, JobExplorer jobExplorer, public TaskJobLauncherCommandLineRunner(JobLauncher jobLauncher,
JobRepository jobRepository, TaskBatchProperties taskBatchProperties) { JobExplorer jobExplorer, JobRepository jobRepository,
TaskBatchProperties taskBatchProperties) {
super(jobLauncher, jobExplorer, jobRepository); super(jobLauncher, jobExplorer, jobRepository);
this.taskJobLauncher = jobLauncher; this.taskJobLauncher = jobLauncher;
this.taskJobExplorer = jobExplorer; this.taskJobExplorer = jobExplorer;
@@ -151,7 +153,8 @@ public class TaskJobLauncherCommandLineRunner extends JobLauncherCommandLineRunn
} }
JobExecution execution = this.taskJobLauncher.run(job, parameters); JobExecution execution = this.taskJobLauncher.run(job, parameters);
if (this.taskApplicationEventPublisher != null) { if (this.taskApplicationEventPublisher != null) {
this.taskApplicationEventPublisher.publishEvent(new JobExecutionEvent(execution)); this.taskApplicationEventPublisher
.publishEvent(new JobExecutionEvent(execution));
} }
this.jobExecutionList.add(execution); this.jobExecutionList.add(execution);
if (execution.getStatus().equals(BatchStatus.FAILED)) { if (execution.getStatus().equals(BatchStatus.FAILED)) {
@@ -168,8 +171,9 @@ public class TaskJobLauncherCommandLineRunner extends JobLauncherCommandLineRunn
List<JobExecution> failedJobExecutions = new ArrayList<>(); List<JobExecution> failedJobExecutions = new ArrayList<>();
RepeatStatus repeatStatus = RepeatStatus.FINISHED; RepeatStatus repeatStatus = RepeatStatus.FINISHED;
for (JobExecution jobExecution : jobExecutionList) { for (JobExecution jobExecution : this.jobExecutionList) {
JobExecution currentJobExecution = taskJobExplorer.getJobExecution(jobExecution.getId()); JobExecution currentJobExecution = this.taskJobExplorer
.getJobExecution(jobExecution.getId());
BatchStatus batchStatus = currentJobExecution.getStatus(); BatchStatus batchStatus = currentJobExecution.getStatus();
if (batchStatus.isRunning()) { if (batchStatus.isRunning()) {
repeatStatus = RepeatStatus.CONTINUABLE; repeatStatus = RepeatStatus.CONTINUABLE;
@@ -178,9 +182,10 @@ public class TaskJobLauncherCommandLineRunner extends JobLauncherCommandLineRunn
failedJobExecutions.add(jobExecution); failedJobExecutions.add(jobExecution);
} }
} }
Thread.sleep(taskBatchProperties.getFailOnJobFailurePollInterval()); Thread.sleep(this.taskBatchProperties.getFailOnJobFailurePollInterval());
if (repeatStatus.equals(RepeatStatus.FINISHED) && failedJobExecutions.size() > 0) { if (repeatStatus.equals(RepeatStatus.FINISHED)
&& failedJobExecutions.size() > 0) {
throwJobFailedException(failedJobExecutions); throwJobFailedException(failedJobExecutions);
} }
return repeatStatus; return repeatStatus;
@@ -190,8 +195,8 @@ public class TaskJobLauncherCommandLineRunner extends JobLauncherCommandLineRunn
private void throwJobFailedException(List<JobExecution> failedJobExecutions) { private void throwJobFailedException(List<JobExecution> failedJobExecutions) {
StringBuilder message = new StringBuilder("The following Jobs have failed: \n"); StringBuilder message = new StringBuilder("The following Jobs have failed: \n");
for (JobExecution failedJobExecution : failedJobExecutions) { for (JobExecution failedJobExecution : failedJobExecutions) {
message.append(String.format("Job %s failed during " + message.append(String.format("Job %s failed during "
"execution for job instance id %s with jobExecutionId of %s \n", + "execution for job instance id %s with jobExecutionId of %s \n",
failedJobExecution.getJobInstance().getJobName(), failedJobExecution.getJobInstance().getJobName(),
failedJobExecution.getJobId(), failedJobExecution.getId())); failedJobExecution.getJobId(), failedJobExecution.getId()));
} }
@@ -201,6 +206,7 @@ public class TaskJobLauncherCommandLineRunner extends JobLauncherCommandLineRunn
throw new TaskException(message.toString()); throw new TaskException(message.toString());
} }
private JobParameters removeNonIdentifying(JobParameters parameters) { private JobParameters removeNonIdentifying(JobParameters parameters) {
Map<String, JobParameter> parameterMap = parameters.getParameters(); Map<String, JobParameter> parameterMap = parameters.getParameters();
HashMap<String, JobParameter> copy = new HashMap<>(parameterMap); HashMap<String, JobParameter> copy = new HashMap<>(parameterMap);
@@ -225,4 +231,5 @@ public class TaskJobLauncherCommandLineRunner extends JobLauncherCommandLineRunn
merged.putAll(additionals.getParameters()); merged.putAll(additionals.getParameters());
return new JobParameters(merged); return new JobParameters(merged);
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.listener; package org.springframework.cloud.task.batch.listener;
import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobExecution;
@@ -28,9 +29,9 @@ public interface TaskBatchDao {
/** /**
* Saves the relationship between a task execution and a job execution. * Saves the relationship between a task execution and a job execution.
*
* @param taskExecution task execution * @param taskExecution task execution
* @param jobExecution job execution * @param jobExecution job execution
*/ */
void saveRelationship(TaskExecution taskExecution, JobExecution jobExecution); void saveRelationship(TaskExecution taskExecution, JobExecution jobExecution);
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,10 +13,12 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.listener; package org.springframework.cloud.task.batch.listener;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.listener.JobExecutionListenerSupport; import org.springframework.batch.core.listener.JobExecutionListenerSupport;
import org.springframework.cloud.task.listener.annotation.BeforeTask; import org.springframework.cloud.task.listener.annotation.BeforeTask;
@@ -31,14 +33,14 @@ import org.springframework.util.Assert;
*/ */
public class TaskBatchExecutionListener extends JobExecutionListenerSupport { public class TaskBatchExecutionListener extends JobExecutionListenerSupport {
private static final Log logger = LogFactory.getLog(TaskBatchExecutionListener.class);
private TaskExecution taskExecution; private TaskExecution taskExecution;
private TaskBatchDao taskBatchDao; private TaskBatchDao taskBatchDao;
private static final Log logger = LogFactory.getLog(TaskBatchExecutionListener.class);
/** /**
* @param taskBatchDao dao used to persist the relationship. Must not be null * @param taskBatchDao dao used to persist the relationship. Must not be null
*/ */
public TaskBatchExecutionListener(TaskBatchDao taskBatchDao) { public TaskBatchExecutionListener(TaskBatchDao taskBatchDao) {
Assert.notNull(taskBatchDao, "A TaskBatchDao is required"); Assert.notNull(taskBatchDao, "A TaskBatchDao is required");
@@ -53,14 +55,16 @@ public class TaskBatchExecutionListener extends JobExecutionListenerSupport {
@Override @Override
public void beforeJob(JobExecution jobExecution) { public void beforeJob(JobExecution jobExecution) {
if(this.taskExecution == null) { if (this.taskExecution == null) {
logger.warn("This job was executed outside the scope of a task but still used the task listener."); logger.warn(
"This job was executed outside the scope of a task but still used the task listener.");
} }
else { else {
logger.info(String.format("The job execution id %s was run within the task execution %s", logger.info(String.format(
jobExecution.getId(), "The job execution id %s was run within the task execution %s",
this.taskExecution.getExecutionId())); jobExecution.getId(), this.taskExecution.getExecutionId()));
taskBatchDao.saveRelationship(taskExecution, jobExecution); this.taskBatchDao.saveRelationship(this.taskExecution, jobExecution);
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.listener.support; package org.springframework.cloud.task.batch.listener.support;
import javax.sql.DataSource; import javax.sql.DataSource;
@@ -27,7 +28,7 @@ import org.springframework.util.Assert;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
* JDBC based implementation of the {@link TaskBatchDao}. Intended to be used in * JDBC based implementation of the {@link TaskBatchDao}. Intended to be used in
* conjunction with the JDBC based * conjunction with the JDBC based
* {@link org.springframework.cloud.task.repository.TaskRepository} * {@link org.springframework.cloud.task.repository.TaskRepository}
* *
@@ -36,10 +37,10 @@ import org.springframework.util.StringUtils;
*/ */
public class JdbcTaskBatchDao implements TaskBatchDao { public class JdbcTaskBatchDao implements TaskBatchDao {
private String tablePrefix = TaskProperties.DEFAULT_TABLE_PREFIX;
private static final String INSERT_STATEMENT = "INSERT INTO %PREFIX%TASK_BATCH VALUES(?, ?)"; private static final String INSERT_STATEMENT = "INSERT INTO %PREFIX%TASK_BATCH VALUES(?, ?)";
private String tablePrefix = TaskProperties.DEFAULT_TABLE_PREFIX;
private JdbcOperations jdbcTemplate; private JdbcOperations jdbcTemplate;
/** /**
@@ -68,10 +69,12 @@ public class JdbcTaskBatchDao implements TaskBatchDao {
public void saveRelationship(TaskExecution taskExecution, JobExecution jobExecution) { public void saveRelationship(TaskExecution taskExecution, JobExecution jobExecution) {
Assert.notNull(taskExecution, "A taskExecution is required"); Assert.notNull(taskExecution, "A taskExecution is required");
Assert.notNull(jobExecution, "A jobExecution is required"); Assert.notNull(jobExecution, "A jobExecution is required");
jdbcTemplate.update(getQuery(INSERT_STATEMENT), taskExecution.getExecutionId(), jobExecution.getId()); this.jdbcTemplate.update(getQuery(INSERT_STATEMENT),
taskExecution.getExecutionId(), jobExecution.getId());
} }
private String getQuery(String base) { private String getQuery(String base) {
return StringUtils.replace(base, "%PREFIX%", tablePrefix); return StringUtils.replace(base, "%PREFIX%", this.tablePrefix);
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.listener.support; package org.springframework.cloud.task.batch.listener.support;
import java.util.Map; import java.util.Map;
@@ -25,8 +26,10 @@ import org.springframework.cloud.task.repository.TaskExecution;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
* Map implementation of the {@link TaskBatchDao}. <p> This is intended for * Map implementation of the {@link TaskBatchDao}.
* testing purposes only!</p> * <p>
* This is intended for testing purposes only!
* </p>
* *
* @author Michael Minella * @author Michael Minella
*/ */
@@ -44,8 +47,9 @@ public class MapTaskBatchDao implements TaskBatchDao {
Assert.notNull(taskExecution, "A taskExecution is required"); Assert.notNull(taskExecution, "A taskExecution is required");
Assert.notNull(jobExecution, "A jobExecution is required"); Assert.notNull(jobExecution, "A jobExecution is required");
if(this.relationships.containsKey(taskExecution.getExecutionId())) { if (this.relationships.containsKey(taskExecution.getExecutionId())) {
this.relationships.get(taskExecution.getExecutionId()).add(jobExecution.getId()); this.relationships.get(taskExecution.getExecutionId())
.add(jobExecution.getId());
} }
else { else {
TreeSet<Long> jobExecutionIds = new TreeSet<>(); TreeSet<Long> jobExecutionIds = new TreeSet<>();
@@ -54,4 +58,5 @@ public class MapTaskBatchDao implements TaskBatchDao {
this.relationships.put(taskExecution.getExecutionId(), jobExecutionIds); this.relationships.put(taskExecution.getExecutionId(), jobExecutionIds);
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.partition; package org.springframework.cloud.task.batch.partition;
import java.util.List; import java.util.List;
@@ -33,10 +34,10 @@ public interface CommandLineArgsProvider {
* worker for the specified {@link ExecutionContext}. * worker for the specified {@link ExecutionContext}.
* *
* Note: This method is called once per partition. * Note: This method is called once per partition.
*
* @param executionContext the unique state for the step to be executed. * @param executionContext the unique state for the step to be executed.
* @return a list of formatted command line arguments to be passed to the worker (the * @return a list of formatted command line arguments to be passed to the worker (the
* list will be joined via spaces). * list will be joined via spaces).
*/ */
List<String> getCommandLineArgs(ExecutionContext executionContext); List<String> getCommandLineArgs(ExecutionContext executionContext);
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.partition; package org.springframework.cloud.task.batch.partition;
import java.util.ArrayList; import java.util.ArrayList;
@@ -51,39 +52,57 @@ import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
* <p>A {@link PartitionHandler} implementation that delegates to a {@link TaskLauncher} for * <p>
* each of the workers. The id of the worker's StepExecution is passed as an environment * A {@link PartitionHandler} implementation that delegates to a {@link TaskLauncher} for
* variable to the worker. The worker, bootstrapped by the * each of the workers. The id of the worker's StepExecution is passed as an environment
* variable to the worker. The worker, bootstrapped by the
* {@link DeployerStepExecutionHandler}, looks up the StepExecution in the JobRepository * {@link DeployerStepExecutionHandler}, looks up the StepExecution in the JobRepository
* and executes it. This PartitionHandler polls the JobRepository for the results.</p> * and executes it. This PartitionHandler polls the JobRepository for the results.
* </p>
* *
* <p>If the job fails, the partitions will be re-executed per normal batch rules (steps that * <p>
* If the job fails, the partitions will be re-executed per normal batch rules (steps that
* are complete should do nothing, failed steps should restart based on their * are complete should do nothing, failed steps should restart based on their
* configurations).</p> * configurations).
* </p>
* *
* <p>This PartitionHandler and all of the worker processes must share the same JobRepository * <p>
* data store (aka point the same database).</p> * This PartitionHandler and all of the worker processes must share the same JobRepository
* data store (aka point the same database).
* </p>
* *
* @author Michael Minella * @author Michael Minella
*/ */
public class DeployerPartitionHandler implements PartitionHandler, EnvironmentAware, InitializingBean { public class DeployerPartitionHandler
implements PartitionHandler, EnvironmentAware, InitializingBean {
/**
* ID of Spring Cloud Task job execution.
*/
public static final String SPRING_CLOUD_TASK_JOB_EXECUTION_ID = "spring.cloud.task.job-execution-id";
/**
* ID of Spring Cloud Task step execution.
*/
public static final String SPRING_CLOUD_TASK_STEP_EXECUTION_ID = "spring.cloud.task.step-execution-id";
/**
* Name of Spring Cloud Task step.
*/
public static final String SPRING_CLOUD_TASK_STEP_NAME = "spring.cloud.task.step-name";
/**
* ID of Spring Cloud Task parent execution.
*/
public static final String SPRING_CLOUD_TASK_PARENT_EXECUTION_ID = "spring.cloud.task.parentExecutionId";
/**
* Spring Cloud Task property name.
*/
public static final String SPRING_CLOUD_TASK_NAME = "spring.cloud.task.name";
private static final long DEFAULT_POLL_INTERVAL = 10000; private static final long DEFAULT_POLL_INTERVAL = 10000;
public static final String SPRING_CLOUD_TASK_JOB_EXECUTION_ID =
"spring.cloud.task.job-execution-id";
public static final String SPRING_CLOUD_TASK_STEP_EXECUTION_ID =
"spring.cloud.task.step-execution-id";
public static final String SPRING_CLOUD_TASK_STEP_NAME =
"spring.cloud.task.step-name";
public static final String SPRING_CLOUD_TASK_PARENT_EXECUTION_ID =
"spring.cloud.task.parentExecutionId";
public static final String SPRING_CLOUD_TASK_NAME = "spring.cloud.task.name";
private int maxWorkers = -1; private int maxWorkers = -1;
private int gridSize = 1; private int gridSize = 1;
@@ -118,10 +137,8 @@ public class DeployerPartitionHandler implements PartitionHandler, EnvironmentAw
private boolean defaultArgsAsEnvironmentVars = false; private boolean defaultArgsAsEnvironmentVars = false;
public DeployerPartitionHandler(TaskLauncher taskLauncher, public DeployerPartitionHandler(TaskLauncher taskLauncher, JobExplorer jobExplorer,
JobExplorer jobExplorer, Resource resource, String stepName) {
Resource resource,
String stepName) {
Assert.notNull(taskLauncher, "A taskLauncher is required"); Assert.notNull(taskLauncher, "A taskLauncher is required");
Assert.notNull(jobExplorer, "A jobExplorer is required"); Assert.notNull(jobExplorer, "A jobExplorer is required");
Assert.notNull(resource, "A resource is required"); Assert.notNull(resource, "A resource is required");
@@ -135,17 +152,16 @@ public class DeployerPartitionHandler implements PartitionHandler, EnvironmentAw
/** /**
* Used to provide any environment variables to be set on each worker launched. * Used to provide any environment variables to be set on each worker launched.
*
* @param environmentVariablesProvider an {@link EnvironmentVariablesProvider} * @param environmentVariablesProvider an {@link EnvironmentVariablesProvider}
*/ */
public void setEnvironmentVariablesProvider(EnvironmentVariablesProvider environmentVariablesProvider) { public void setEnvironmentVariablesProvider(
EnvironmentVariablesProvider environmentVariablesProvider) {
this.environmentVariablesProvider = environmentVariablesProvider; this.environmentVariablesProvider = environmentVariablesProvider;
} }
/** /**
* If set to true, the default args that are used internally by Spring Cloud Task and * If set to true, the default args that are used internally by Spring Cloud Task and
* Spring Batch are passed as environment variables instead of command line arguments. * Spring Batch are passed as environment variables instead of command line arguments.
*
* @param defaultArgsAsEnvironmentVars defaults to false * @param defaultArgsAsEnvironmentVars defaults to false
*/ */
public void setDefaultArgsAsEnvironmentVars(boolean defaultArgsAsEnvironmentVars) { public void setDefaultArgsAsEnvironmentVars(boolean defaultArgsAsEnvironmentVars) {
@@ -154,17 +170,16 @@ public class DeployerPartitionHandler implements PartitionHandler, EnvironmentAw
/** /**
* Used to provide any command line arguements to be passed to each worker launched. * Used to provide any command line arguements to be passed to each worker launched.
*
* @param commandLineArgsProvider {@link CommandLineArgsProvider} * @param commandLineArgsProvider {@link CommandLineArgsProvider}
*/ */
public void setCommandLineArgsProvider(CommandLineArgsProvider commandLineArgsProvider) { public void setCommandLineArgsProvider(
CommandLineArgsProvider commandLineArgsProvider) {
this.commandLineArgsProvider = commandLineArgsProvider; this.commandLineArgsProvider = commandLineArgsProvider;
} }
/** /**
* The maximum number of workers to be executing at once. * The maximum number of workers to be executing at once.
* * @param maxWorkers number of workers. Defaults to -1 (unlimited)
* @param maxWorkers number of workers. Defaults to -1 (unlimited)
*/ */
public void setMaxWorkers(int maxWorkers) { public void setMaxWorkers(int maxWorkers) {
Assert.isTrue(maxWorkers != 0, "maxWorkers cannot be 0"); Assert.isTrue(maxWorkers != 0, "maxWorkers cannot be 0");
@@ -172,11 +187,11 @@ public class DeployerPartitionHandler implements PartitionHandler, EnvironmentAw
} }
/** /**
* Approximate size of the pool of worker JVMs available. May be used by the * Approximate size of the pool of worker JVMs available. May be used by the
* {@link StepExecutionSplitter} to determine how many partitions to create (at the * {@link StepExecutionSplitter} to determine how many partitions to create (at the
* discretion of the {@link org.springframework.batch.core.partition.support.Partitioner}). * discretion of the
* * {@link org.springframework.batch.core.partition.support.Partitioner}).
* @param gridSize size of grid. Defaults to 1 * @param gridSize size of grid. Defaults to 1
*/ */
public void setGridSize(int gridSize) { public void setGridSize(int gridSize) {
this.gridSize = gridSize; this.gridSize = gridSize;
@@ -184,25 +199,22 @@ public class DeployerPartitionHandler implements PartitionHandler, EnvironmentAw
/** /**
* The interval to check the job repository for completed steps. * The interval to check the job repository for completed steps.
* * @param pollInterval interval. Defaults to 10 seconds
* @param pollInterval interval. Defaults to 10 seconds
*/ */
public void setPollInterval(long pollInterval) { public void setPollInterval(long pollInterval) {
this.pollInterval = pollInterval; this.pollInterval = pollInterval;
} }
/** /**
* Timeout for the master step. This is a timeout for all workers to complete. * Timeout for the master step. This is a timeout for all workers to complete.
* * @param timeout timeout. Defaults to none (-1).
* @param timeout timeout. Defaults to none (-1).
*/ */
public void setTimeout(long timeout) { public void setTimeout(long timeout) {
this.timeout = timeout; this.timeout = timeout;
} }
/** /**
* Map of deployment properties to be used by the {@link TaskLauncher} * Map of deployment properties to be used by the {@link TaskLauncher}.
*
* @param deploymentProperties properties to be used by the {@link TaskLauncher} * @param deploymentProperties properties to be used by the {@link TaskLauncher}
*/ */
public void setDeploymentProperties(Map<String, String> deploymentProperties) { public void setDeploymentProperties(Map<String, String> deploymentProperties) {
@@ -210,9 +222,8 @@ public class DeployerPartitionHandler implements PartitionHandler, EnvironmentAw
} }
/** /**
* The name of the application to be launched. Useful in environments where * The name of the application to be launched. Useful in environments where
* application deployments are reused (such as CloudFoundry). * application deployments are reused (such as CloudFoundry).
*
* @param applicationName The name of the application to be launched * @param applicationName The name of the application to be launched
*/ */
public void setApplicationName(String applicationName) { public void setApplicationName(String applicationName) {
@@ -223,9 +234,9 @@ public class DeployerPartitionHandler implements PartitionHandler, EnvironmentAw
public void beforeTask(TaskExecution taskExecution) { public void beforeTask(TaskExecution taskExecution) {
this.taskExecution = taskExecution; this.taskExecution = taskExecution;
if(this.commandLineArgsProvider == null) { if (this.commandLineArgsProvider == null) {
SimpleCommandLineArgsProvider provider = new SimpleCommandLineArgsProvider provider = new SimpleCommandLineArgsProvider(
SimpleCommandLineArgsProvider(taskExecution); taskExecution);
this.commandLineArgsProvider = provider; this.commandLineArgsProvider = provider;
} }
@@ -235,8 +246,8 @@ public class DeployerPartitionHandler implements PartitionHandler, EnvironmentAw
public Collection<StepExecution> handle(StepExecutionSplitter stepSplitter, public Collection<StepExecution> handle(StepExecutionSplitter stepSplitter,
StepExecution stepExecution) throws Exception { StepExecution stepExecution) throws Exception {
final Set<StepExecution> tempCandidates = final Set<StepExecution> tempCandidates = stepSplitter.split(stepExecution,
stepSplitter.split(stepExecution, this.gridSize); this.gridSize);
// Following two lines due to https://jira.spring.io/browse/BATCH-2490 // Following two lines due to https://jira.spring.io/browse/BATCH-2490
final Set<StepExecution> candidates = new HashSet<>(tempCandidates.size()); final Set<StepExecution> candidates = new HashSet<>(tempCandidates.size());
@@ -244,7 +255,7 @@ public class DeployerPartitionHandler implements PartitionHandler, EnvironmentAw
int partitions = candidates.size(); int partitions = candidates.size();
logger.debug(String.format("%s partitions were returned", partitions)); this.logger.debug(String.format("%s partitions were returned", partitions));
final Set<StepExecution> executed = new HashSet<>(candidates.size()); final Set<StepExecution> executed = new HashSet<>(candidates.size());
@@ -259,7 +270,8 @@ public class DeployerPartitionHandler implements PartitionHandler, EnvironmentAw
return pollReplies(stepExecution, executed, candidates, partitions); return pollReplies(stepExecution, executed, candidates, partitions);
} }
private void launchWorkers(Set<StepExecution> candidates, Set<StepExecution> executed) { private void launchWorkers(Set<StepExecution> candidates,
Set<StepExecution> executed) {
for (StepExecution execution : candidates) { for (StepExecution execution : candidates) {
if (this.currentWorkers < this.maxWorkers || this.maxWorkers < 0) { if (this.currentWorkers < this.maxWorkers || this.maxWorkers < 0) {
launchWorker(execution); launchWorker(execution);
@@ -273,59 +285,59 @@ public class DeployerPartitionHandler implements PartitionHandler, EnvironmentAw
private void launchWorker(StepExecution workerStepExecution) { private void launchWorker(StepExecution workerStepExecution) {
List<String> arguments = new ArrayList<>(); List<String> arguments = new ArrayList<>();
ExecutionContext copyContext = new ExecutionContext(workerStepExecution.getExecutionContext()); ExecutionContext copyContext = new ExecutionContext(
workerStepExecution.getExecutionContext());
arguments.addAll( arguments.addAll(this.commandLineArgsProvider.getCommandLineArgs(copyContext));
this.commandLineArgsProvider
.getCommandLineArgs(copyContext));
if(!this.defaultArgsAsEnvironmentVars) { if (!this.defaultArgsAsEnvironmentVars) {
arguments.add(formatArgument(SPRING_CLOUD_TASK_JOB_EXECUTION_ID, arguments.add(formatArgument(SPRING_CLOUD_TASK_JOB_EXECUTION_ID,
String.valueOf(workerStepExecution.getJobExecution().getId()))); String.valueOf(workerStepExecution.getJobExecution().getId())));
arguments.add(formatArgument(SPRING_CLOUD_TASK_STEP_EXECUTION_ID, arguments.add(formatArgument(SPRING_CLOUD_TASK_STEP_EXECUTION_ID,
String.valueOf(workerStepExecution.getId()))); String.valueOf(workerStepExecution.getId())));
arguments.add(formatArgument(SPRING_CLOUD_TASK_STEP_NAME, this.stepName)); arguments.add(formatArgument(SPRING_CLOUD_TASK_STEP_NAME, this.stepName));
arguments.add(formatArgument(SPRING_CLOUD_TASK_NAME, String.format("%s_%s_%s", arguments
taskExecution.getTaskName(), .add(formatArgument(SPRING_CLOUD_TASK_NAME,
workerStepExecution.getJobExecution().getJobInstance().getJobName(), String.format("%s_%s_%s", this.taskExecution.getTaskName(),
workerStepExecution.getStepName()))); workerStepExecution.getJobExecution().getJobInstance()
.getJobName(),
workerStepExecution.getStepName())));
arguments.add(formatArgument(SPRING_CLOUD_TASK_PARENT_EXECUTION_ID, arguments.add(formatArgument(SPRING_CLOUD_TASK_PARENT_EXECUTION_ID,
String.valueOf(taskExecution.getExecutionId()))); String.valueOf(this.taskExecution.getExecutionId())));
} }
copyContext = new ExecutionContext(workerStepExecution.getExecutionContext()); copyContext = new ExecutionContext(workerStepExecution.getExecutionContext());
Map<String, String> environmentVariables = this.environmentVariablesProvider.getEnvironmentVariables(copyContext); Map<String, String> environmentVariables = this.environmentVariablesProvider
.getEnvironmentVariables(copyContext);
if(this.defaultArgsAsEnvironmentVars) { if (this.defaultArgsAsEnvironmentVars) {
environmentVariables.put(SPRING_CLOUD_TASK_JOB_EXECUTION_ID, environmentVariables.put(SPRING_CLOUD_TASK_JOB_EXECUTION_ID,
String.valueOf(workerStepExecution.getJobExecution().getId())); String.valueOf(workerStepExecution.getJobExecution().getId()));
environmentVariables.put(SPRING_CLOUD_TASK_STEP_EXECUTION_ID, environmentVariables.put(SPRING_CLOUD_TASK_STEP_EXECUTION_ID,
String.valueOf(workerStepExecution.getId())); String.valueOf(workerStepExecution.getId()));
environmentVariables.put(SPRING_CLOUD_TASK_STEP_NAME, this.stepName); environmentVariables.put(SPRING_CLOUD_TASK_STEP_NAME, this.stepName);
environmentVariables.put(SPRING_CLOUD_TASK_NAME, String.format("%s_%s_%s", environmentVariables
taskExecution.getTaskName(), .put(SPRING_CLOUD_TASK_NAME,
workerStepExecution.getJobExecution().getJobInstance().getJobName(), String.format("%s_%s_%s", this.taskExecution.getTaskName(),
workerStepExecution.getStepName())); workerStepExecution.getJobExecution().getJobInstance()
.getJobName(),
workerStepExecution.getStepName()));
environmentVariables.put(SPRING_CLOUD_TASK_PARENT_EXECUTION_ID, environmentVariables.put(SPRING_CLOUD_TASK_PARENT_EXECUTION_ID,
String.valueOf(taskExecution.getExecutionId())); String.valueOf(this.taskExecution.getExecutionId()));
} }
AppDefinition definition = AppDefinition definition = new AppDefinition(resolveApplicationName(),
new AppDefinition(resolveApplicationName(), environmentVariables);
environmentVariables);
AppDeploymentRequest request = AppDeploymentRequest request = new AppDeploymentRequest(definition, this.resource,
new AppDeploymentRequest(definition, this.deploymentProperties, arguments);
this.resource,
this.deploymentProperties,
arguments);
taskLauncher.launch(request); this.taskLauncher.launch(request);
} }
private String resolveApplicationName() { private String resolveApplicationName() {
if(StringUtils.hasText(this.applicationName)) { if (StringUtils.hasText(this.applicationName)) {
return this.applicationName; return this.applicationName;
} }
else { else {
@@ -338,8 +350,7 @@ public class DeployerPartitionHandler implements PartitionHandler, EnvironmentAw
} }
private Collection<StepExecution> pollReplies(final StepExecution masterStepExecution, private Collection<StepExecution> pollReplies(final StepExecution masterStepExecution,
final Set<StepExecution> executed, final Set<StepExecution> executed, final Set<StepExecution> candidates,
final Set<StepExecution> candidates,
final int size) throws Exception { final int size) throws Exception {
final Collection<StepExecution> result = new ArrayList<>(executed.size()); final Collection<StepExecution> result = new ArrayList<>(executed.size());
@@ -351,13 +362,14 @@ public class DeployerPartitionHandler implements PartitionHandler, EnvironmentAw
for (StepExecution curStepExecution : executed) { for (StepExecution curStepExecution : executed) {
if (!result.contains(curStepExecution)) { if (!result.contains(curStepExecution)) {
StepExecution partitionStepExecution = StepExecution partitionStepExecution = DeployerPartitionHandler.this.jobExplorer
jobExplorer.getStepExecution(masterStepExecution.getJobExecutionId(), curStepExecution.getId()); .getStepExecution(masterStepExecution.getJobExecutionId(),
curStepExecution.getId());
BatchStatus batchStatus = partitionStepExecution.getStatus(); BatchStatus batchStatus = partitionStepExecution.getStatus();
if (batchStatus != null && isComplete(batchStatus)) { if (batchStatus != null && isComplete(batchStatus)) {
result.add(partitionStepExecution); result.add(partitionStepExecution);
currentWorkers--; DeployerPartitionHandler.this.currentWorkers--;
if (!candidates.isEmpty()) { if (!candidates.isEmpty()) {
@@ -382,8 +394,8 @@ public class DeployerPartitionHandler implements PartitionHandler, EnvironmentAw
Poller<Collection<StepExecution>> poller = new DirectPoller<>(this.pollInterval); Poller<Collection<StepExecution>> poller = new DirectPoller<>(this.pollInterval);
Future<Collection<StepExecution>> resultsFuture = poller.poll(callback); Future<Collection<StepExecution>> resultsFuture = poller.poll(callback);
if (timeout >= 0) { if (this.timeout >= 0) {
return resultsFuture.get(timeout, TimeUnit.MILLISECONDS); return resultsFuture.get(this.timeout, TimeUnit.MILLISECONDS);
} }
else { else {
return resultsFuture.get(); return resultsFuture.get();
@@ -391,7 +403,8 @@ public class DeployerPartitionHandler implements PartitionHandler, EnvironmentAw
} }
private boolean isComplete(BatchStatus status) { private boolean isComplete(BatchStatus status) {
return status.equals(BatchStatus.COMPLETED) || status.isGreaterThan(BatchStatus.STARTED); return status.equals(BatchStatus.COMPLETED)
|| status.isGreaterThan(BatchStatus.STARTED);
} }
@Override @Override
@@ -401,10 +414,11 @@ public class DeployerPartitionHandler implements PartitionHandler, EnvironmentAw
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
if(this.environmentVariablesProvider == null) { if (this.environmentVariablesProvider == null) {
this.environmentVariablesProvider = this.environmentVariablesProvider = new SimpleEnvironmentVariablesProvider(
new SimpleEnvironmentVariablesProvider(this.environment); this.environment);
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.partition; package org.springframework.cloud.task.batch.partition;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@@ -34,20 +35,24 @@ import org.springframework.core.env.Environment;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
* <p>A {@link CommandLineRunner} used to execute a {@link Step}. No result is provided * <p>
* A {@link CommandLineRunner} used to execute a {@link Step}. No result is provided
* directly to the associated {@link DeployerPartitionHandler} as it will obtain the step * directly to the associated {@link DeployerPartitionHandler} as it will obtain the step
* results directly from the shared job repository.</p> * results directly from the shared job repository.
* </p>
* *
* <p>The {@link StepExecution} is rehydrated based on the environment variables provided. * <p>
* Specifically, the following variables are required:</p> * The {@link StepExecution} is rehydrated based on the environment variables provided.
* Specifically, the following variables are required:
* </p>
* <ul> * <ul>
* <li>{@link DeployerPartitionHandler#SPRING_CLOUD_TASK_JOB_EXECUTION_ID}: The id of * <li>{@link DeployerPartitionHandler#SPRING_CLOUD_TASK_JOB_EXECUTION_ID}: The id of the
* the JobExecution.</li> * JobExecution.</li>
* <li>{@link DeployerPartitionHandler#SPRING_CLOUD_TASK_STEP_EXECUTION_ID}: The id of * <li>{@link DeployerPartitionHandler#SPRING_CLOUD_TASK_STEP_EXECUTION_ID}: The id of the
* the StepExecution.</li> * StepExecution.</li>
* <li>{@link DeployerPartitionHandler#SPRING_CLOUD_TASK_STEP_NAME}: The id of the * <li>{@link DeployerPartitionHandler#SPRING_CLOUD_TASK_STEP_NAME}: The id of the bean
* bean definition for the Step to execute. The id must be found within the provided * definition for the Step to execute. The id must be found within the provided
* {@link BeanFactory}</li> * {@link BeanFactory}</li>
* </ul> * </ul>
* *
* @author Michael Minella * @author Michael Minella
@@ -65,7 +70,8 @@ public class DeployerStepExecutionHandler implements CommandLineRunner {
private StepLocator stepLocator; private StepLocator stepLocator;
public DeployerStepExecutionHandler(BeanFactory beanFactory, JobExplorer jobExplorer, JobRepository jobRepository) { public DeployerStepExecutionHandler(BeanFactory beanFactory, JobExplorer jobExplorer,
JobRepository jobRepository) {
Assert.notNull(beanFactory, "A beanFactory is required"); Assert.notNull(beanFactory, "A beanFactory is required");
Assert.notNull(jobExplorer, "A jobExplorer is required"); Assert.notNull(jobExplorer, "A jobExplorer is required");
Assert.notNull(jobRepository, "A jobRepository is required"); Assert.notNull(jobRepository, "A jobRepository is required");
@@ -82,38 +88,60 @@ public class DeployerStepExecutionHandler implements CommandLineRunner {
validateRequest(); validateRequest();
Long jobExecutionId = Long.parseLong(environment.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID)); Long jobExecutionId = Long.parseLong(this.environment.getProperty(
Long stepExecutionId = Long.parseLong(environment.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID)); DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID));
StepExecution stepExecution = jobExplorer.getStepExecution(jobExecutionId, stepExecutionId); Long stepExecutionId = Long.parseLong(this.environment.getProperty(
DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID));
StepExecution stepExecution = this.jobExplorer.getStepExecution(jobExecutionId,
stepExecutionId);
if (stepExecution == null) { if (stepExecution == null) {
throw new NoSuchStepException(String.format("No StepExecution could be located for step execution id %s within job execution %s", stepExecutionId, jobExecutionId)); throw new NoSuchStepException(String.format(
"No StepExecution could be located for step execution id %s within job execution %s",
stepExecutionId, jobExecutionId));
} }
String stepName = environment.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME); String stepName = this.environment
Step step = stepLocator.getStep(stepName); .getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME);
Step step = this.stepLocator.getStep(stepName);
try { try {
logger.debug(String.format("Executing step %s with step execution id %s and job execution id %s", stepExecution.getStepName(), stepExecutionId, jobExecutionId)); this.logger.debug(String.format(
"Executing step %s with step execution id %s and job execution id %s",
stepExecution.getStepName(), stepExecutionId, jobExecutionId));
step.execute(stepExecution); step.execute(stepExecution);
} }
catch (JobInterruptedException e) { catch (JobInterruptedException e) {
stepExecution.setStatus(BatchStatus.STOPPED); stepExecution.setStatus(BatchStatus.STOPPED);
jobRepository.update(stepExecution); this.jobRepository.update(stepExecution);
} }
catch (Throwable e) { catch (Throwable e) {
stepExecution.addFailureException(e); stepExecution.addFailureException(e);
stepExecution.setStatus(BatchStatus.FAILED); stepExecution.setStatus(BatchStatus.FAILED);
jobRepository.update(stepExecution); this.jobRepository.update(stepExecution);
} }
} }
private void validateRequest() { private void validateRequest() {
Assert.isTrue(environment.containsProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID), "A job execution id is required"); Assert.isTrue(
Assert.isTrue(environment.containsProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID), "A step execution id is required"); this.environment.containsProperty(
Assert.isTrue(environment.containsProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME), "A step name is required"); DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID),
"A job execution id is required");
Assert.isTrue(
this.environment.containsProperty(
DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID),
"A step execution id is required");
Assert.isTrue(
this.environment.containsProperty(
DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME),
"A step name is required");
Assert.isTrue(this.stepLocator.getStepNames().contains(environment.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME)), "The step requested cannot be found in the provided BeanFactory"); Assert.isTrue(
this.stepLocator.getStepNames()
.contains(this.environment.getProperty(
DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME)),
"The step requested cannot be found in the provided BeanFactory");
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.partition; package org.springframework.cloud.task.batch.partition;
import java.util.Map; import java.util.Map;
@@ -24,19 +25,18 @@ import org.springframework.batch.item.ExecutionContext;
* each worker in a partitioned job. * each worker in a partitioned job.
* *
* @author Michael Minella * @author Michael Minella
*
* @since 1.0.2 * @since 1.0.2
*/ */
public interface EnvironmentVariablesProvider { public interface EnvironmentVariablesProvider {
/** /**
* Provides a {@link Map} of Strings to be used as environment variables. This method * Provides a {@link Map} of Strings to be used as environment variables. This method
* will be called for each worker step. For example, if there are 5 partitions, this * will be called for each worker step. For example, if there are 5 partitions, this
* method will be called 5 times. * method will be called 5 times.
*
* @param executionContext the {@link ExecutionContext} associated with the worker's * @param executionContext the {@link ExecutionContext} associated with the worker's
* step * step
* @return A {@link Map} of values to be used as environment variables * @return A {@link Map} of values to be used as environment variables
*/ */
Map<String, String> getEnvironmentVariables(ExecutionContext executionContext); Map<String, String> getEnvironmentVariables(ExecutionContext executionContext);
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.partition; package org.springframework.cloud.task.batch.partition;
import java.util.Collections; import java.util.Collections;
@@ -21,23 +22,23 @@ import java.util.Map;
import org.springframework.batch.item.ExecutionContext; import org.springframework.batch.item.ExecutionContext;
/** /**
* A simple no-op implementation of the {@link EnvironmentVariablesProvider}. It returns * A simple no-op implementation of the {@link EnvironmentVariablesProvider}. It returns
* an empty {@link Map}. * an empty {@link Map}.
* *
* @author Michael Minella * @author Michael Minella
*
* @since 1.0.2 * @since 1.0.2
*/ */
public class NoOpEnvironmentVariablesProvider implements EnvironmentVariablesProvider { public class NoOpEnvironmentVariablesProvider implements EnvironmentVariablesProvider {
/** /**
*
* @param executionContext the {@link ExecutionContext} associated with the worker's * @param executionContext the {@link ExecutionContext} associated with the worker's
* step * step
* @return an empty {@link Map} * @return an empty {@link Map}
*/ */
@Override @Override
public Map<String, String> getEnvironmentVariables(ExecutionContext executionContext) { public Map<String, String> getEnvironmentVariables(
ExecutionContext executionContext) {
return Collections.emptyMap(); return Collections.emptyMap();
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.partition; package org.springframework.cloud.task.batch.partition;
import java.util.List; import java.util.List;
@@ -38,6 +39,7 @@ public class PassThroughCommandLineArgsProvider implements CommandLineArgsProvid
@Override @Override
public List<String> getCommandLineArgs(ExecutionContext executionContext) { public List<String> getCommandLineArgs(ExecutionContext executionContext) {
return commandLineArgs; return this.commandLineArgs;
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.partition; package org.springframework.cloud.task.batch.partition;
import java.util.ArrayList; import java.util.ArrayList;
@@ -31,7 +32,8 @@ import org.springframework.util.Assert;
* @author Glenn Renfro * @author Glenn Renfro
* @since 1.1.0 * @since 1.1.0
*/ */
public class SimpleCommandLineArgsProvider extends TaskExecutionListenerSupport implements CommandLineArgsProvider { public class SimpleCommandLineArgsProvider extends TaskExecutionListenerSupport
implements CommandLineArgsProvider {
private TaskExecution taskExecution; private TaskExecution taskExecution;
@@ -56,7 +58,6 @@ public class SimpleCommandLineArgsProvider extends TaskExecutionListenerSupport
/** /**
* Additional command line args to be appended. * Additional command line args to be appended.
*
* @param appendedArgs list of arguments * @param appendedArgs list of arguments
* @since 1.2 * @since 1.2
*/ */
@@ -67,17 +68,18 @@ public class SimpleCommandLineArgsProvider extends TaskExecutionListenerSupport
@Override @Override
public List<String> getCommandLineArgs(ExecutionContext executionContext) { public List<String> getCommandLineArgs(ExecutionContext executionContext) {
int listSize = this.taskExecution.getArguments().size() + int listSize = this.taskExecution.getArguments().size()
(this.appendedArgs != null ? this.appendedArgs.size() : 0); + (this.appendedArgs != null ? this.appendedArgs.size() : 0);
List<String> args = new ArrayList<>(listSize); List<String> args = new ArrayList<>(listSize);
args.addAll(this.taskExecution.getArguments()); args.addAll(this.taskExecution.getArguments());
if(this.appendedArgs != null) { if (this.appendedArgs != null) {
args.addAll(this.appendedArgs); args.addAll(this.appendedArgs);
} }
return args; return args;
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.partition; package org.springframework.cloud.task.batch.partition;
import java.util.Arrays; import java.util.Arrays;
@@ -29,12 +30,11 @@ import org.springframework.core.env.PropertySource;
/** /**
* Copies all existing environment variables as made available in the {@link Environment} * Copies all existing environment variables as made available in the {@link Environment}
* only if includeCurrentEnvironment is set to true (default). * only if includeCurrentEnvironment is set to true (default). The
* The <code>environmentProperties</code> option provides the ability to override any * <code>environmentProperties</code> option provides the ability to override any specific
* specific values on an as needed basis. * values on an as needed basis.
* *
* @author Michael Minella * @author Michael Minella
*
* @since 1.0.2 * @since 1.0.2
*/ */
public class SimpleEnvironmentVariablesProvider implements EnvironmentVariablesProvider { public class SimpleEnvironmentVariablesProvider implements EnvironmentVariablesProvider {
@@ -53,28 +53,31 @@ public class SimpleEnvironmentVariablesProvider implements EnvironmentVariablesP
} }
/** /**
* @param environmentProperties a {@link Map} of properties used to override any values * @param environmentProperties a {@link Map} of properties used to override any
* configured in the current {@link Environment} * values configured in the current {@link Environment}
*/ */
public void setEnvironmentProperties(Map<String, String> environmentProperties) { public void setEnvironmentProperties(Map<String, String> environmentProperties) {
this.environmentProperties = environmentProperties; this.environmentProperties = environmentProperties;
} }
/** /**
* Establishes if current environment variables will be included as a part of the provider. * Establishes if current environment variables will be included as a part of the
* @param includeCurrentEnvironment true(default) include local environment properties. False do not include * provider.
* current environment properties. * @param includeCurrentEnvironment true(default) include local environment
* properties. False do not include current environment properties.
*/ */
public void setIncludeCurrentEnvironment(boolean includeCurrentEnvironment) { public void setIncludeCurrentEnvironment(boolean includeCurrentEnvironment) {
this.includeCurrentEnvironment = includeCurrentEnvironment; this.includeCurrentEnvironment = includeCurrentEnvironment;
} }
@Override @Override
public Map<String, String> getEnvironmentVariables(ExecutionContext executionContext) { public Map<String, String> getEnvironmentVariables(
ExecutionContext executionContext) {
Map<String, String> environmentProperties = new HashMap<>(this.environmentProperties.size()); Map<String, String> environmentProperties = new HashMap<>(
this.environmentProperties.size());
if(includeCurrentEnvironment) { if (this.includeCurrentEnvironment) {
environmentProperties.putAll(getCurrentEnvironmentProperties()); environmentProperties.putAll(getCurrentEnvironmentProperties());
} }
@@ -88,9 +91,11 @@ public class SimpleEnvironmentVariablesProvider implements EnvironmentVariablesP
Set<String> keys = new HashSet<>(); Set<String> keys = new HashSet<>();
for (PropertySource<?> propertySource : ((AbstractEnvironment) this.environment).getPropertySources()) { for (PropertySource<?> propertySource : ((AbstractEnvironment) this.environment)
.getPropertySources()) {
if (propertySource instanceof MapPropertySource) { if (propertySource instanceof MapPropertySource) {
keys.addAll(Arrays.asList(((MapPropertySource) propertySource).getPropertyNames())); keys.addAll(Arrays
.asList(((MapPropertySource) propertySource).getPropertyNames()));
} }
} }
@@ -100,4 +105,5 @@ public class SimpleEnvironmentVariablesProvider implements EnvironmentVariablesP
return currentEnvironment; return currentEnvironment;
} }
} }

View File

@@ -1,64 +1,64 @@
{ {
"properties": [ "properties": [
{ {
"defaultValue": true, "defaultValue": true,
"name": "spring.cloud.task.batch.listener.enabled", "name": "spring.cloud.task.batch.listener.enabled",
"description": "This property is used to determine if a task will be linked to the batch jobs that are run.", "description": "This property is used to determine if a task will be linked to the batch jobs that are run.",
"type": "java.lang.Boolean" "type": "java.lang.Boolean"
}, },
{ {
"defaultValue": false, "defaultValue": false,
"name": "spring.cloud.task.batch.fail-on-job-failure", "name": "spring.cloud.task.batch.fail-on-job-failure",
"description": "This property is used to determine if a task app should return with a non zero exit code if a batch job fails.", "description": "This property is used to determine if a task app should return with a non zero exit code if a batch job fails.",
"type": "java.lang.Boolean" "type": "java.lang.Boolean"
}, },
{ {
"defaultValue": true, "defaultValue": true,
"name": "spring.cloud.task.batch.events.enabled", "name": "spring.cloud.task.batch.events.enabled",
"description": "This property is used to determine if a task should listen for batch events.", "description": "This property is used to determine if a task should listen for batch events.",
"type": "java.lang.Boolean" "type": "java.lang.Boolean"
}, },
{ {
"defaultValue": true, "defaultValue": true,
"name": "spring.cloud.task.batch.events.chunk.enabled", "name": "spring.cloud.task.batch.events.chunk.enabled",
"description": "This property is used to determine if a task should listen for batch chunk events.", "description": "This property is used to determine if a task should listen for batch chunk events.",
"type": "java.lang.Boolean" "type": "java.lang.Boolean"
}, },
{ {
"defaultValue": true, "defaultValue": true,
"name": "spring.cloud.task.batch.events.item-process.enabled", "name": "spring.cloud.task.batch.events.item-process.enabled",
"description": "This property is used to determine if a task should listen for batch item processed events.", "description": "This property is used to determine if a task should listen for batch item processed events.",
"type": "java.lang.Boolean" "type": "java.lang.Boolean"
}, },
{ {
"defaultValue": true, "defaultValue": true,
"name": "spring.cloud.task.batch.events.item-read.enabled", "name": "spring.cloud.task.batch.events.item-read.enabled",
"description": "This property is used to determine if a task should listen for batch item read events.", "description": "This property is used to determine if a task should listen for batch item read events.",
"type": "java.lang.Boolean" "type": "java.lang.Boolean"
}, },
{ {
"defaultValue": true, "defaultValue": true,
"name": "spring.cloud.task.batch.events.item-write.enabled", "name": "spring.cloud.task.batch.events.item-write.enabled",
"description": "This property is used to determine if a task should listen for batch item write events.", "description": "This property is used to determine if a task should listen for batch item write events.",
"type": "java.lang.Boolean" "type": "java.lang.Boolean"
}, },
{ {
"defaultValue": true, "defaultValue": true,
"name": "spring.cloud.task.batch.events.job-execution.enabled", "name": "spring.cloud.task.batch.events.job-execution.enabled",
"description": "This property is used to determine if a task should listen for batch job execution events.", "description": "This property is used to determine if a task should listen for batch job execution events.",
"type": "java.lang.Boolean" "type": "java.lang.Boolean"
}, },
{ {
"defaultValue": true, "defaultValue": true,
"name": "spring.cloud.task.batch.events.skip.enabled", "name": "spring.cloud.task.batch.events.skip.enabled",
"description": "This property is used to determine if a task should listen for batch skip events.", "description": "This property is used to determine if a task should listen for batch skip events.",
"type": "java.lang.Boolean" "type": "java.lang.Boolean"
}, },
{ {
"defaultValue": true, "defaultValue": true,
"name": "spring.cloud.task.batch.events.step-execution.enabled", "name": "spring.cloud.task.batch.events.step-execution.enabled",
"description": "This property is used to determine if a task should listen for batch step execution events.", "description": "This property is used to determine if a task should listen for batch step execution events.",
"type": "java.lang.Boolean" "type": "java.lang.Boolean"
} }
] ]
} }

View File

@@ -1,17 +1,17 @@
/* /*
* Copyright 2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.configuration; package org.springframework.cloud.task.batch.configuration;
@@ -35,4 +35,5 @@ import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
@Documented @Documented
@ImportAutoConfiguration @ImportAutoConfiguration
public @interface TaskBatchTest { public @interface TaskBatchTest {
} }

View File

@@ -1,17 +1,17 @@
/* /*
* Copyright 2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.configuration; package org.springframework.cloud.task.batch.configuration;
@@ -33,33 +33,33 @@ import static org.assertj.core.api.Assertions.assertThat;
*/ */
public class TaskJobLauncherAutoConfigurationTests { public class TaskJobLauncherAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner(). private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
withUserConfiguration(TaskBatchExecutionListenerTests.JobConfiguration.class, .withUserConfiguration(TaskBatchExecutionListenerTests.JobConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,
EmbeddedDataSourceConfiguration.class, EmbeddedDataSourceConfiguration.class, BatchAutoConfiguration.class,
BatchAutoConfiguration.class,
TaskJobLauncherAutoConfiguration.class); TaskJobLauncherAutoConfiguration.class);
@Test @Test
public void testAutoBuiltDataSourceWithTaskJobLauncherCLR() { public void testAutoBuiltDataSourceWithTaskJobLauncherCLR() {
this.contextRunner.withPropertyValues("spring.cloud.task.batch.fail-on-job-failure=true").run(context -> { this.contextRunner
assertThat(context).hasSingleBean(TaskJobLauncherCommandLineRunner.class); .withPropertyValues("spring.cloud.task.batch.fail-on-job-failure=true")
assertThat(context.getBean(TaskJobLauncherCommandLineRunner.class) .run(context -> {
.getOrder()) assertThat(context)
.isEqualTo(0); .hasSingleBean(TaskJobLauncherCommandLineRunner.class);
}); assertThat(context.getBean(TaskJobLauncherCommandLineRunner.class)
.getOrder()).isEqualTo(0);
});
} }
@Test @Test
public void testAutoBuiltDataSourceWithTaskJobLauncherCLROrder() { public void testAutoBuiltDataSourceWithTaskJobLauncherCLROrder() {
this.contextRunner. this.contextRunner
withPropertyValues("spring.cloud.task.batch.fail-on-job-failure=true", .withPropertyValues("spring.cloud.task.batch.fail-on-job-failure=true",
"spring.cloud.task.batch.commandLineRunnerOrder=100"). "spring.cloud.task.batch.commandLineRunnerOrder=100")
run(context -> { .run(context -> {
assertThat(context.getBean(TaskJobLauncherCommandLineRunner.class) assertThat(context.getBean(TaskJobLauncherCommandLineRunner.class)
.getOrder()) .getOrder()).isEqualTo(100);
.isEqualTo(100); });
});
} }
@Test @Test
@@ -69,5 +69,5 @@ public class TaskJobLauncherAutoConfigurationTests {
assertThat(context).doesNotHaveBean(TaskJobLauncherCommandLineRunner.class); assertThat(context).doesNotHaveBean(TaskJobLauncherCommandLineRunner.class);
}); });
} }
}
}

View File

@@ -1,23 +1,21 @@
/* /*
* Copyright 2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.handler; package org.springframework.cloud.task.batch.handler;
import org.assertj.core.api.AssertionsForClassTypes;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.jupiter.api.function.Executable; import org.junit.jupiter.api.function.Executable;
@@ -55,13 +53,14 @@ import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/** /**
* @author Glenn Renfro * @author Glenn Renfro
*/ */
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@ContextConfiguration(classes = {TaskJobLauncherCommandLineRunnerCoreTests.BatchConfiguration.class}) @ContextConfiguration(classes = {
TaskJobLauncherCommandLineRunnerCoreTests.BatchConfiguration.class })
public class TaskJobLauncherCommandLineRunnerCoreTests { public class TaskJobLauncherCommandLineRunnerCoreTests {
@Autowired @Autowired
@@ -93,11 +92,11 @@ public class TaskJobLauncherCommandLineRunnerCoreTests {
Tasklet tasklet = (contribution, chunkContext) -> RepeatStatus.FINISHED; Tasklet tasklet = (contribution, chunkContext) -> RepeatStatus.FINISHED;
this.step = this.steps.get("step").tasklet(tasklet).build(); this.step = this.steps.get("step").tasklet(tasklet).build();
this.job = this.jobs.get("job").start(this.step).build(); this.job = this.jobs.get("job").start(this.step).build();
this.runner = new TaskJobLauncherCommandLineRunner(this.jobLauncher, this.jobExplorer, jobRepository, new TaskBatchProperties()); this.runner = new TaskJobLauncherCommandLineRunner(this.jobLauncher,
this.jobExplorer, this.jobRepository, new TaskBatchProperties());
} }
@DirtiesContext @DirtiesContext
@Test @Test
public void basicExecution() throws Exception { public void basicExecution() throws Exception {
@@ -146,7 +145,6 @@ public class TaskJobLauncherCommandLineRunnerCoreTests {
assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(2); assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(2);
} }
@DirtiesContext @DirtiesContext
@Test @Test
public void retryFailedExecutionOnNonRestartableJob() throws Exception { public void retryFailedExecutionOnNonRestartableJob() throws Exception {
@@ -162,9 +160,9 @@ public class TaskJobLauncherCommandLineRunnerCoreTests {
// try to re-run a failed execution // try to re-run a failed execution
Executable executable = () -> this.runner.execute(this.job, Executable executable = () -> this.runner.execute(this.job,
new JobParametersBuilder().addLong("run.id", 1L).toJobParameters()); new JobParametersBuilder().addLong("run.id", 1L).toJobParameters());
Throwable exception = assertThrows(JobRestartException.class, executable); assertThatExceptionOfType(JobRestartException.class)
AssertionsForClassTypes.assertThat(exception.getMessage()) .isThrownBy(executable::execute)
.isEqualTo("JobInstance already exists and is not restartable"); .withMessage("JobInstance already exists and is not restartable");
} }
@DirtiesContext @DirtiesContext
@@ -177,12 +175,11 @@ public class TaskJobLauncherCommandLineRunnerCoreTests {
.addLong("foo", 2L, false).toJobParameters(); .addLong("foo", 2L, false).toJobParameters();
runFailedJob(jobParameters); runFailedJob(jobParameters);
assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(1); assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(1);
runFailedJob(new JobParametersBuilder(jobParameters) runFailedJob(new JobParametersBuilder(jobParameters).addLong("run.id", 1L)
.addLong("run.id", 1L).toJobParameters()); .toJobParameters());
assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(1); assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(1);
} }
@DirtiesContext @DirtiesContext
@Test @Test
public void retryFailedExecutionWithDifferentNonIdentifyingParametersFromPreviousExecution() public void retryFailedExecutionWithDifferentNonIdentifyingParametersFromPreviousExecution()
@@ -195,7 +192,7 @@ public class TaskJobLauncherCommandLineRunnerCoreTests {
runFailedJob(jobParameters); runFailedJob(jobParameters);
assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(1); assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(1);
// try to re-run a failed execution with non identifying parameters // try to re-run a failed execution with non identifying parameters
runFailedJob( new JobParametersBuilder().addLong("run.id", 1L) runFailedJob(new JobParametersBuilder().addLong("run.id", 1L)
.addLong("id", 2L, false).addLong("foo", 3L, false).toJobParameters()); .addLong("id", 2L, false).addLong("foo", 3L, false).toJobParameters());
assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(1); assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(1);
JobInstance jobInstance = this.jobExplorer.getJobInstance(0L); JobInstance jobInstance = this.jobExplorer.getJobInstance(0L);
@@ -216,7 +213,6 @@ public class TaskJobLauncherCommandLineRunnerCoreTests {
assertThat(parameters.getLong("foo")).isEqualTo(3L); assertThat(parameters.getLong("foo")).isEqualTo(3L);
} }
private Tasklet throwingTasklet() { private Tasklet throwingTasklet() {
return (contribution, chunkContext) -> { return (contribution, chunkContext) -> {
throw new RuntimeException("Planned"); throw new RuntimeException("Planned");
@@ -238,13 +234,11 @@ public class TaskJobLauncherCommandLineRunnerCoreTests {
@EnableBatchProcessing @EnableBatchProcessing
protected static class BatchConfiguration implements BatchConfigurer { protected static class BatchConfiguration implements BatchConfigurer {
private ResourcelessTransactionManager transactionManager = private ResourcelessTransactionManager transactionManager = new ResourcelessTransactionManager();
new ResourcelessTransactionManager();
private JobRepository jobRepository; private JobRepository jobRepository;
private MapJobRepositoryFactoryBean jobRepositoryFactory = private MapJobRepositoryFactoryBean jobRepositoryFactory = new MapJobRepositoryFactoryBean(
new MapJobRepositoryFactoryBean(
this.transactionManager); this.transactionManager);
public BatchConfiguration() throws Exception { public BatchConfiguration() throws Exception {
@@ -275,4 +269,5 @@ public class TaskJobLauncherCommandLineRunnerCoreTests {
} }
} }
} }

View File

@@ -1,17 +1,17 @@
/* /*
* Copyright 2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.handler; package org.springframework.cloud.task.batch.handler;
@@ -20,6 +20,7 @@ import java.util.Set;
import javax.sql.DataSource; import javax.sql.DataSource;
import org.assertj.core.api.Condition;
import org.junit.After; import org.junit.After;
import org.junit.Test; import org.junit.Test;
import org.junit.jupiter.api.function.Executable; import org.junit.jupiter.api.function.Executable;
@@ -59,18 +60,18 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor; import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor;
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/** /**
* @author Glenn Renfro * @author Glenn Renfro
*/ */
public class TaskJobLauncherCommandLineRunnerTests { 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 job instance id 1 with jobExecutionId of 1 \n";
private static final String DEFAULT_ERROR_MESSAGE = "The following Jobs have failed: \n" + private ConfigurableApplicationContext applicationContext;
"Job jobA failed during execution for job instance id 1 with jobExecutionId of 1 \n";
@After @After
public void tearDown() { public void tearDown() {
@@ -82,20 +83,22 @@ public class TaskJobLauncherCommandLineRunnerTests {
@Test @Test
public void testTaskJobLauncherCLRSuccessFail() { public void testTaskJobLauncherCLRSuccessFail() {
String[] enabledArgs = new String[] { String[] enabledArgs = new String[] {
"--spring.cloud.task.batch.failOnJobFailure=true"}; "--spring.cloud.task.batch.failOnJobFailure=true" };
validateForFail(DEFAULT_ERROR_MESSAGE, TaskJobLauncherCommandLineRunnerTests.JobWithFailureConfiguration.class, validateForFail(DEFAULT_ERROR_MESSAGE,
TaskJobLauncherCommandLineRunnerTests.JobWithFailureConfiguration.class,
enabledArgs); enabledArgs);
} }
/** /**
* Verifies that the task will return an exit code other than zero if the * Verifies that the task will return an exit code other than zero if the job fails
* job fails with the deprecated EnableTask annotation. * with the deprecated EnableTask annotation.
*/ */
@Test @Test
public void testTaskJobLauncherCLRSuccessFailWithAnnotation() { public void testTaskJobLauncherCLRSuccessFailWithAnnotation() {
String[] enabledArgs = new String[] { String[] enabledArgs = new String[] {
"--spring.cloud.task.batch.failOnJobFailure=true"}; "--spring.cloud.task.batch.failOnJobFailure=true" };
validateForFail(DEFAULT_ERROR_MESSAGE, TaskJobLauncherCommandLineRunnerTests.JobWithFailureAnnotatedConfiguration.class, validateForFail(DEFAULT_ERROR_MESSAGE,
TaskJobLauncherCommandLineRunnerTests.JobWithFailureAnnotatedConfiguration.class,
enabledArgs); enabledArgs);
} }
@@ -103,8 +106,9 @@ public class TaskJobLauncherCommandLineRunnerTests {
public void testTaskJobLauncherCLRSuccessFailWithTaskExecutor() { public void testTaskJobLauncherCLRSuccessFailWithTaskExecutor() {
String[] enabledArgs = new String[] { String[] enabledArgs = new String[] {
"--spring.cloud.task.batch.failOnJobFailure=true", "--spring.cloud.task.batch.failOnJobFailure=true",
"--spring.cloud.task.batch.failOnJobFailurePollInterval=500"}; "--spring.cloud.task.batch.failOnJobFailurePollInterval=500" };
validateForFail(DEFAULT_ERROR_MESSAGE, TaskJobLauncherCommandLineRunnerTests.JobWithFailureTaskExecutorConfiguration.class, validateForFail(DEFAULT_ERROR_MESSAGE,
TaskJobLauncherCommandLineRunnerTests.JobWithFailureTaskExecutorConfiguration.class,
enabledArgs); enabledArgs);
} }
@@ -112,11 +116,12 @@ public class TaskJobLauncherCommandLineRunnerTests {
public void testTaskJobLauncherPickOneJob() { public void testTaskJobLauncherPickOneJob() {
String[] enabledArgs = new String[] { String[] enabledArgs = new String[] {
"--spring.cloud.task.batch.fail-on-job-failure=true", "--spring.cloud.task.batch.fail-on-job-failure=true",
"--spring.cloud.task.batch.jobNames=jobSucceed"}; "--spring.cloud.task.batch.jobNames=jobSucceed" };
boolean isExceptionThrown = false; boolean isExceptionThrown = false;
try { try {
this.applicationContext = SpringApplication this.applicationContext = SpringApplication.run(new Class[] {
.run(new Class[] { TaskJobLauncherCommandLineRunnerTests.JobWithFailureConfiguration.class }, enabledArgs); TaskJobLauncherCommandLineRunnerTests.JobWithFailureConfiguration.class },
enabledArgs);
} }
catch (IllegalStateException exception) { catch (IllegalStateException exception) {
isExceptionThrown = true; isExceptionThrown = true;
@@ -128,40 +133,51 @@ public class TaskJobLauncherCommandLineRunnerTests {
@Test @Test
public void testCommandLineRunnerSetToFalse() { public void testCommandLineRunnerSetToFalse() {
String[] enabledArgs = new String[] {}; String[] enabledArgs = new String[] {};
this.applicationContext = SpringApplication this.applicationContext = SpringApplication.run(
.run(new Class[] { TaskJobLauncherCommandLineRunnerTests.JobConfiguration.class }, enabledArgs); new Class[] {
TaskJobLauncherCommandLineRunnerTests.JobConfiguration.class },
enabledArgs);
validateContext(); validateContext();
assertThat(applicationContext.getBean(JobLauncherCommandLineRunner.class)).isNotNull(); assertThat(this.applicationContext.getBean(JobLauncherCommandLineRunner.class))
.isNotNull();
Executable executable = () -> applicationContext.getBean(TaskJobLauncherCommandLineRunner.class); Executable executable = () -> this.applicationContext
.getBean(TaskJobLauncherCommandLineRunner.class);
Throwable exception = assertThrows(NoSuchBeanDefinitionException.class, executable); assertThatExceptionOfType(NoSuchBeanDefinitionException.class)
assertThat(exception.getMessage()).isEqualTo("No qualifying bean of type " + .isThrownBy(executable::execute).withMessage("No qualifying bean of type "
"'org.springframework.cloud.task.batch.handler.TaskJobLauncherCommandLineRunner' available"); + "'org.springframework.cloud.task.batch.handler.TaskJobLauncherCommandLineRunner' available");
validateContext(); validateContext();
} }
private void validateContext() { private void validateContext() {
TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class); TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class);
Page<TaskExecution> page = taskExplorer.findTaskExecutionsByName("application", PageRequest.of(0, 1)); Page<TaskExecution> page = taskExplorer.findTaskExecutionsByName("application",
PageRequest.of(0, 1));
Set<Long> jobExecutionIds = taskExplorer Set<Long> jobExecutionIds = taskExplorer.getJobExecutionIdsByTaskExecutionId(
.getJobExecutionIdsByTaskExecutionId(page.iterator().next().getExecutionId()); page.iterator().next().getExecutionId());
assertThat(jobExecutionIds.size()).isEqualTo(1); assertThat(jobExecutionIds.size()).isEqualTo(1);
assertThat(taskExplorer.getTaskExecution(jobExecutionIds.iterator().next()).getExecutionId()).isEqualTo(1); assertThat(taskExplorer.getTaskExecution(jobExecutionIds.iterator().next())
.getExecutionId()).isEqualTo(1);
} }
private void validateForFail(String errorMessage, Class clazz, String [] enabledArgs) { private void validateForFail(String errorMessage, Class clazz, String[] enabledArgs) {
Executable executable = () -> this.applicationContext = SpringApplication Executable executable = () -> this.applicationContext = SpringApplication.run(
.run(new Class[] { clazz,PropertyPlaceholderAutoConfiguration.class}, enabledArgs); new Class[] { clazz, PropertyPlaceholderAutoConfiguration.class },
enabledArgs);
Throwable exception = assertThrows(IllegalStateException.class, executable); assertThatExceptionOfType(IllegalStateException.class)
assertThat(exception.getCause().getMessage()).isEqualTo(errorMessage); .isThrownBy(executable::execute).has(new Condition<Throwable>() {
@Override
public boolean matches(Throwable value) {
return errorMessage.equals(value.getCause().getMessage());
}
});
} }
@EnableBatchProcessing @EnableBatchProcessing
@TaskBatchTest @TaskBatchTest
@Import(EmbeddedDataSourceConfiguration.class) @Import(EmbeddedDataSourceConfiguration.class)
@@ -176,25 +192,23 @@ public class TaskJobLauncherCommandLineRunnerTests {
@Bean @Bean
public Job job() { public Job job() {
return jobBuilderFactory.get("job") return this.jobBuilderFactory.get("job")
.start(stepBuilderFactory.get("step1").tasklet(new Tasklet() { .start(this.stepBuilderFactory.get("step1").tasklet(new Tasklet() {
@Override @Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) { public RepeatStatus execute(StepContribution contribution,
ChunkContext chunkContext) {
System.out.println("Executed"); System.out.println("Executed");
return RepeatStatus.FINISHED; return RepeatStatus.FINISHED;
} }
}).build()) }).build()).build();
.build();
} }
} }
@EnableBatchProcessing @EnableBatchProcessing
@ImportAutoConfiguration({ @ImportAutoConfiguration({ PropertyPlaceholderAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, BatchAutoConfiguration.class, TaskBatchAutoConfiguration.class,
BatchAutoConfiguration.class, TaskJobLauncherAutoConfiguration.class, SingleTaskConfiguration.class,
TaskBatchAutoConfiguration.class,
TaskJobLauncherAutoConfiguration.class,
SingleTaskConfiguration.class,
SimpleTaskAutoConfiguration.class }) SimpleTaskAutoConfiguration.class })
@Import(EmbeddedDataSourceConfiguration.class) @Import(EmbeddedDataSourceConfiguration.class)
@EnableTask @EnableTask
@@ -208,50 +222,54 @@ public class TaskJobLauncherCommandLineRunnerTests {
@Bean @Bean
public Job jobFail() { public Job jobFail() {
return jobBuilderFactory.get("jobA") return this.jobBuilderFactory.get("jobA")
.start(stepBuilderFactory.get("step1").tasklet(new Tasklet() { .start(this.stepBuilderFactory.get("step1").tasklet(new Tasklet() {
@Override @Override
public RepeatStatus execute(StepContribution contribution, public RepeatStatus execute(StepContribution contribution,
ChunkContext chunkContext) ChunkContext chunkContext) throws Exception {
throws Exception {
System.out.println("Executed"); System.out.println("Executed");
throw new IllegalStateException("WHOOPS"); throw new IllegalStateException("WHOOPS");
} }
}).build()) }).build()).build();
.build();
} }
@Bean @Bean
public Job jobFun() { public Job jobFun() {
return jobBuilderFactory.get("jobSucceed") return this.jobBuilderFactory.get("jobSucceed").start(
.start(stepBuilderFactory.get("step1Succeed").tasklet(new Tasklet() { this.stepBuilderFactory.get("step1Succeed").tasklet(new Tasklet() {
@Override @Override
public RepeatStatus execute(StepContribution contribution, public RepeatStatus execute(StepContribution contribution,
ChunkContext chunkContext) { ChunkContext chunkContext) {
System.out.println("Executed"); System.out.println("Executed");
return RepeatStatus.FINISHED; return RepeatStatus.FINISHED;
} }
}).build()) }).build()).build();
.build();
} }
} }
@EnableTask @EnableTask
public static class JobWithFailureAnnotatedConfiguration extends JobWithFailureConfiguration{ public static class JobWithFailureAnnotatedConfiguration
extends JobWithFailureConfiguration {
} }
public static class JobWithFailureTaskExecutorConfiguration extends JobWithFailureConfiguration{ public static class JobWithFailureTaskExecutorConfiguration
extends JobWithFailureConfiguration {
@Bean @Bean
public BatchConfigurer batchConfigurer(DataSource dataSource) { public BatchConfigurer batchConfigurer(DataSource dataSource) {
return new TestBatchConfigurer(dataSource); return new TestBatchConfigurer(dataSource);
} }
} }
private static class TestBatchConfigurer extends DefaultBatchConfigurer{ private static class TestBatchConfigurer extends DefaultBatchConfigurer {
public TestBatchConfigurer(DataSource dataSource) {
TestBatchConfigurer(DataSource dataSource) {
super(dataSource); super(dataSource);
} }
protected JobLauncher createJobLauncher() throws Exception { protected JobLauncher createJobLauncher() throws Exception {
SimpleJobLauncher jobLauncher = new SimpleJobLauncher(); SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
jobLauncher.setJobRepository(getJobRepository()); jobLauncher.setJobRepository(getJobRepository());
@@ -259,5 +277,7 @@ public class TaskJobLauncherCommandLineRunnerTests {
jobLauncher.afterPropertiesSet(); jobLauncher.afterPropertiesSet();
return jobLauncher; return jobLauncher;
} }
} }
} }

View File

@@ -1,22 +1,23 @@
/* /*
* Copyright 2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.listener; package org.springframework.cloud.task.batch.listener;
import java.util.Set; import java.util.Set;
import javax.sql.DataSource; import javax.sql.DataSource;
import org.junit.After; import org.junit.After;
@@ -56,8 +57,8 @@ public class PrefixTests {
@Test @Test
public void testPrefix() { public void testPrefix() {
this.applicationContext = SpringApplication.run( this.applicationContext = SpringApplication.run(JobConfiguration.class,
JobConfiguration.class, "--spring.cloud.task.tablePrefix=FOO_"); "--spring.cloud.task.tablePrefix=FOO_");
TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class); TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class);
@@ -80,22 +81,19 @@ public class PrefixTests {
@Bean @Bean
public Job job() { public Job job() {
return jobBuilderFactory.get("job") return this.jobBuilderFactory.get("job").start(this.stepBuilderFactory
.start(stepBuilderFactory.get("step1") .get("step1").tasklet((contribution, chunkContext) -> {
.tasklet((contribution, chunkContext) -> {
System.out.println("Executed"); System.out.println("Executed");
return RepeatStatus.FINISHED; return RepeatStatus.FINISHED;
}).build()) }).build()).build();
.build();
} }
@Bean @Bean
public DataSource dataSource() { public DataSource dataSource() {
return new EmbeddedDatabaseBuilder() return new EmbeddedDatabaseBuilder().addScript("classpath:schema-h2.sql")
.addScript("classpath:schema-h2.sql") .setType(EmbeddedDatabaseType.H2).build();
.setType(EmbeddedDatabaseType.H2)
.build();
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.listener; package org.springframework.cloud.task.batch.listener;
import java.util.ArrayList; import java.util.ArrayList;
@@ -61,7 +62,7 @@ import org.springframework.data.domain.PageRequest;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import static org.junit.Assert.assertEquals; import static org.assertj.core.api.Assertions.assertThat;
/** /**
* @author Michael Minella * @author Michael Minella
@@ -75,15 +76,14 @@ public class TaskBatchExecutionListenerTests {
@After @After
public void tearDown() { public void tearDown() {
if(this.applicationContext != null && this.applicationContext.isActive()) { if (this.applicationContext != null && this.applicationContext.isActive()) {
this.applicationContext.close(); this.applicationContext.close();
} }
} }
@Test @Test
public void testAutobuiltDataSource() { public void testAutobuiltDataSource() {
this.applicationContext = SpringApplication.run(JobConfiguration.class , this.applicationContext = SpringApplication.run(JobConfiguration.class, ARGS);
ARGS);
validateContext(); validateContext();
} }
@@ -96,28 +96,28 @@ public class TaskBatchExecutionListenerTests {
@Test(expected = AssertionError.class) @Test(expected = AssertionError.class)
public void testNoAutoConfigurationEnable() { public void testNoAutoConfigurationEnable() {
this.applicationContext = SpringApplication.run(JobConfiguration.class , this.applicationContext = SpringApplication.run(JobConfiguration.class,
"--spring.cloud.task.batch.listener.enable=false"); "--spring.cloud.task.batch.listener.enable=false");
validateContext(); validateContext();
} }
@Test(expected = AssertionError.class) @Test(expected = AssertionError.class)
public void testNoAutoConfigurationBothDisabled() { public void testNoAutoConfigurationBothDisabled() {
this.applicationContext = SpringApplication.run(JobConfiguration.class , this.applicationContext = SpringApplication.run(JobConfiguration.class,
"--spring.cloud.task.batch.listener.enable=false --spring.cloud.task.batch.listener.enabled=false"); "--spring.cloud.task.batch.listener.enable=false --spring.cloud.task.batch.listener.enabled=false");
validateContext(); validateContext();
} }
@Test @Test
public void testAutoConfigurationEnable() { public void testAutoConfigurationEnable() {
this.applicationContext = SpringApplication.run(JobConfiguration.class , this.applicationContext = SpringApplication.run(JobConfiguration.class,
"--spring.cloud.task.batch.listener.enable=true"); "--spring.cloud.task.batch.listener.enable=true");
validateContext(); validateContext();
} }
@Test @Test
public void testAutoConfigurationEnabled() { public void testAutoConfigurationEnabled() {
this.applicationContext = SpringApplication.run(JobConfiguration.class , this.applicationContext = SpringApplication.run(JobConfiguration.class,
"--spring.cloud.task.batch.listener.enabled=true"); "--spring.cloud.task.batch.listener.enabled=true");
validateContext(); validateContext();
} }
@@ -132,26 +132,34 @@ public class TaskBatchExecutionListenerTests {
private void validateContext() { private void validateContext() {
TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class); TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class);
Page<TaskExecution> page = taskExplorer.findTaskExecutionsByName("application", PageRequest.of(0, 1)); Page<TaskExecution> page = taskExplorer.findTaskExecutionsByName("application",
PageRequest.of(0, 1));
Set<Long> jobExecutionIds = taskExplorer.getJobExecutionIdsByTaskExecutionId(page.iterator().next().getExecutionId()); Set<Long> jobExecutionIds = taskExplorer.getJobExecutionIdsByTaskExecutionId(
page.iterator().next().getExecutionId());
assertEquals(1, jobExecutionIds.size()); assertThat(jobExecutionIds.size()).isEqualTo(1);
assertEquals(1, taskExplorer.getTaskExecution(jobExecutionIds.iterator().next()).getExecutionId()); assertThat(taskExplorer.getTaskExecution(jobExecutionIds.iterator().next())
.getExecutionId()).isEqualTo(1);
} }
@Test @Test
public void testMultipleDataSources() { public void testMultipleDataSources() {
this.applicationContext = SpringApplication.run(JobConfigurationMultipleDataSources.class, ARGS); this.applicationContext = SpringApplication
.run(JobConfigurationMultipleDataSources.class, ARGS);
TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class); TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class);
Page<TaskExecution> page = taskExplorer.findTaskExecutionsByName("application", PageRequest.of(0, 1)); Page<TaskExecution> page = taskExplorer.findTaskExecutionsByName("application",
PageRequest.of(0, 1));
Set<Long> jobExecutionIds = taskExplorer.getJobExecutionIdsByTaskExecutionId(page.iterator().next().getExecutionId()); Set<Long> jobExecutionIds = taskExplorer.getJobExecutionIdsByTaskExecutionId(
page.iterator().next().getExecutionId());
assertEquals(1, jobExecutionIds.size()); assertThat(jobExecutionIds.size()).isEqualTo(1);
assertEquals(1, taskExplorer.getTaskExecution(jobExecutionIds.iterator().next()).getExecutionId()); assertThat(taskExplorer.getTaskExecution(jobExecutionIds.iterator().next())
.getExecutionId()).isEqualTo(1);
} }
@Test @Test
@@ -160,11 +168,13 @@ public class TaskBatchExecutionListenerTests {
TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class); TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class);
Page<TaskExecution> page = taskExplorer.findTaskExecutionsByName("application", PageRequest.of(0, 1)); Page<TaskExecution> page = taskExplorer.findTaskExecutionsByName("application",
PageRequest.of(0, 1));
Set<Long> jobExecutionIds = taskExplorer.getJobExecutionIdsByTaskExecutionId(page.iterator().next().getExecutionId()); Set<Long> jobExecutionIds = taskExplorer.getJobExecutionIdsByTaskExecutionId(
page.iterator().next().getExecutionId());
assertEquals(0, jobExecutionIds.size()); assertThat(jobExecutionIds.size()).isEqualTo(0);
} }
@Test @Test
@@ -173,28 +183,39 @@ public class TaskBatchExecutionListenerTests {
TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class); TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class);
Page<TaskExecution> page = taskExplorer.findTaskExecutionsByName("application", PageRequest.of(0, 1)); Page<TaskExecution> page = taskExplorer.findTaskExecutionsByName("application",
PageRequest.of(0, 1));
Set<Long> jobExecutionIds = taskExplorer.getJobExecutionIdsByTaskExecutionId(page.iterator().next().getExecutionId()); Set<Long> jobExecutionIds = taskExplorer.getJobExecutionIdsByTaskExecutionId(
page.iterator().next().getExecutionId());
assertEquals(1, jobExecutionIds.size()); assertThat(jobExecutionIds.size()).isEqualTo(1);
assertEquals(1, (long) taskExplorer.getTaskExecutionIdByJobExecutionId(jobExecutionIds.iterator().next())); assertThat((long) taskExplorer
.getTaskExecutionIdByJobExecutionId(jobExecutionIds.iterator().next()))
.isEqualTo(1);
} }
@Test @Test
public void testMultipleJobs() { public void testMultipleJobs() {
this.applicationContext = SpringApplication.run(MultipleJobConfiguration.class, ARGS); this.applicationContext = SpringApplication.run(MultipleJobConfiguration.class,
ARGS);
TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class); TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class);
Page<TaskExecution> page = taskExplorer.findTaskExecutionsByName("application", PageRequest.of(0, 1)); Page<TaskExecution> page = taskExplorer.findTaskExecutionsByName("application",
PageRequest.of(0, 1));
Set<Long> jobExecutionIds = taskExplorer.getJobExecutionIdsByTaskExecutionId(page.iterator().next().getExecutionId()); Set<Long> jobExecutionIds = taskExplorer.getJobExecutionIdsByTaskExecutionId(
page.iterator().next().getExecutionId());
assertEquals(2, jobExecutionIds.size()); assertThat(jobExecutionIds.size()).isEqualTo(2);
Iterator<Long> jobExecutionIdsIterator = jobExecutionIds.iterator(); Iterator<Long> jobExecutionIdsIterator = jobExecutionIds.iterator();
assertEquals(1, (long) taskExplorer.getTaskExecutionIdByJobExecutionId(jobExecutionIdsIterator.next())); assertThat((long) taskExplorer
assertEquals(1, (long) taskExplorer.getTaskExecutionIdByJobExecutionId(jobExecutionIdsIterator.next())); .getTaskExecutionIdByJobExecutionId(jobExecutionIdsIterator.next()))
.isEqualTo(1);
assertThat((long) taskExplorer
.getTaskExecutionIdByJobExecutionId(jobExecutionIdsIterator.next()))
.isEqualTo(1);
} }
@Test @Test
@@ -204,27 +225,26 @@ public class TaskBatchExecutionListenerTests {
jobNames.add("job2"); jobNames.add("job2");
jobNames.add("TESTOBJECT"); jobNames.add("TESTOBJECT");
TaskBatchExecutionListenerBeanPostProcessor beanPostProcessor = TaskBatchExecutionListenerBeanPostProcessor beanPostProcessor = beanPostProcessor(
beanPostProcessor(jobNames); jobNames);
SimpleJob testObject = new SimpleJob(); SimpleJob testObject = new SimpleJob();
SimpleJob bean = (SimpleJob) beanPostProcessor. SimpleJob bean = (SimpleJob) beanPostProcessor
postProcessBeforeInitialization(testObject,"TESTOBJECT"); .postProcessBeforeInitialization(testObject, "TESTOBJECT");
assertEquals(testObject,bean); assertThat(bean).isEqualTo(testObject);
} }
@Test @Test
public void testBatchExecutionListenerBeanPostProcessorWithEmptyJobNames() { public void testBatchExecutionListenerBeanPostProcessorWithEmptyJobNames() {
TaskBatchExecutionListenerBeanPostProcessor beanPostProcessor = TaskBatchExecutionListenerBeanPostProcessor beanPostProcessor = beanPostProcessor(
beanPostProcessor(Collections.emptyList()); Collections.emptyList());
SimpleJob testObject = new SimpleJob(); SimpleJob testObject = new SimpleJob();
SimpleJob bean = (SimpleJob) beanPostProcessor. SimpleJob bean = (SimpleJob) beanPostProcessor
postProcessBeforeInitialization(testObject,"TESTOBJECT"); .postProcessBeforeInitialization(testObject, "TESTOBJECT");
assertEquals(testObject,bean); assertThat(bean).isEqualTo(testObject);
} }
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void testBatchExecutionListenerBeanPostProcessorNullJobNames() { public void testBatchExecutionListenerBeanPostProcessorNullJobNames() {
beanPostProcessor(null); beanPostProcessor(null);
@@ -232,16 +252,14 @@ public class TaskBatchExecutionListenerTests {
private TaskBatchExecutionListenerBeanPostProcessor beanPostProcessor( private TaskBatchExecutionListenerBeanPostProcessor beanPostProcessor(
List<String> jobNames) { List<String> jobNames) {
this.applicationContext = SpringApplication.run(new Class[] {JobConfiguration.class, this.applicationContext = SpringApplication.run(new Class[] {
PropertyPlaceholderAutoConfiguration.class, EmbeddedDataSourceConfiguration.class, JobConfiguration.class, PropertyPlaceholderAutoConfiguration.class,
BatchAutoConfiguration.class, EmbeddedDataSourceConfiguration.class, BatchAutoConfiguration.class,
TaskBatchAutoConfiguration.class, TaskBatchAutoConfiguration.class, SimpleTaskAutoConfiguration.class,
SimpleTaskAutoConfiguration.class,
SingleTaskConfiguration.class }, ARGS); SingleTaskConfiguration.class }, ARGS);
TaskBatchExecutionListenerBeanPostProcessor beanPostProcessor = TaskBatchExecutionListenerBeanPostProcessor beanPostProcessor = this.applicationContext
this.applicationContext.getBean( .getBean(TaskBatchExecutionListenerBeanPostProcessor.class);
TaskBatchExecutionListenerBeanPostProcessor.class);
beanPostProcessor.setJobNames(jobNames); beanPostProcessor.setJobNames(jobNames);
return beanPostProcessor; return beanPostProcessor;
@@ -269,16 +287,17 @@ public class TaskBatchExecutionListenerTests {
@Bean @Bean
public Job job() { public Job job() {
return jobBuilderFactory.get("job") return this.jobBuilderFactory.get("job")
.start(stepBuilderFactory.get("step1").tasklet(new Tasklet() { .start(this.stepBuilderFactory.get("step1").tasklet(new Tasklet() {
@Override @Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { public RepeatStatus execute(StepContribution contribution,
ChunkContext chunkContext) throws Exception {
System.out.println("Executed"); System.out.println("Executed");
return RepeatStatus.FINISHED; return RepeatStatus.FINISHED;
} }
}).build()) }).build()).build();
.build();
} }
} }
@EnableBatchProcessing @EnableBatchProcessing
@@ -298,14 +317,18 @@ public class TaskBatchExecutionListenerTests {
return new FactoryBean<Job>() { return new FactoryBean<Job>() {
@Override @Override
public Job getObject() throws Exception { public Job getObject() throws Exception {
return jobBuilderFactory.get("job") return JobFactoryBeanConfiguration.this.jobBuilderFactory.get("job")
.start(stepBuilderFactory.get("step1").tasklet(new Tasklet() { .start(JobFactoryBeanConfiguration.this.stepBuilderFactory
@Override .get("step1").tasklet(new Tasklet() {
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { @Override
System.out.println("Executed"); public RepeatStatus execute(
return RepeatStatus.FINISHED; StepContribution contribution,
} ChunkContext chunkContext)
}).build()) throws Exception {
System.out.println("Executed");
return RepeatStatus.FINISHED;
}
}).build())
.build(); .build();
} }
@@ -320,6 +343,7 @@ public class TaskBatchExecutionListenerTests {
} }
}; };
} }
} }
@EnableBatchProcessing @EnableBatchProcessing
@@ -336,34 +360,31 @@ public class TaskBatchExecutionListenerTests {
@Bean @Bean
public Job job() { public Job job() {
return jobBuilderFactory.get("job") return this.jobBuilderFactory.get("job")
.start(stepBuilderFactory.get("step1").tasklet(new Tasklet() { .start(this.stepBuilderFactory.get("step1").tasklet(new Tasklet() {
@Override @Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { public RepeatStatus execute(StepContribution contribution,
ChunkContext chunkContext) throws Exception {
System.out.println("Executed"); System.out.println("Executed");
return RepeatStatus.FINISHED; return RepeatStatus.FINISHED;
} }
}).build()) }).build()).build();
.build();
} }
@Bean @Bean
@Primary @Primary
public DataSource myDataSource() { public DataSource myDataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder() EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2) .setType(EmbeddedDatabaseType.H2).setName("myDataSource");
.setName("myDataSource");
return builder.build(); return builder.build();
} }
@Bean @Bean
public DataSource incorrectDataSource() { public DataSource incorrectDataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder() EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2) .setType(EmbeddedDatabaseType.H2).setName("incorrectDataSource");
.setName("incorrectDataSource");
return builder.build(); return builder.build();
} }
@Bean @Bean
public TaskConfigurer taskConfigurer() { public TaskConfigurer taskConfigurer() {
@@ -374,6 +395,7 @@ public class TaskBatchExecutionListenerTests {
public DefaultBatchConfigurer batchConfigurer() { public DefaultBatchConfigurer batchConfigurer() {
return new DefaultBatchConfigurer(myDataSource()); return new DefaultBatchConfigurer(myDataSource());
} }
} }
@EnableBatchProcessing @EnableBatchProcessing
@@ -390,28 +412,30 @@ public class TaskBatchExecutionListenerTests {
@Bean @Bean
public Job job1() { public Job job1() {
return jobBuilderFactory.get("job1") return this.jobBuilderFactory.get("job1").start(
.start(stepBuilderFactory.get("job1step1").tasklet(new Tasklet() { this.stepBuilderFactory.get("job1step1").tasklet(new Tasklet() {
@Override @Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { public RepeatStatus execute(StepContribution contribution,
ChunkContext chunkContext) throws Exception {
System.out.println("Executed job1"); System.out.println("Executed job1");
return RepeatStatus.FINISHED; return RepeatStatus.FINISHED;
} }
}).build()) }).build()).build();
.build();
} }
@Bean @Bean
public Job job2() { public Job job2() {
return jobBuilderFactory.get("job2") return this.jobBuilderFactory.get("job2").start(
.start(stepBuilderFactory.get("job2step1").tasklet(new Tasklet() { this.stepBuilderFactory.get("job2step1").tasklet(new Tasklet() {
@Override @Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { public RepeatStatus execute(StepContribution contribution,
ChunkContext chunkContext) throws Exception {
System.out.println("Executed job2"); System.out.println("Executed job2");
return RepeatStatus.FINISHED; return RepeatStatus.FINISHED;
} }
}).build()) }).build()).build();
.build();
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016-2017 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.partition; package org.springframework.cloud.task.batch.partition;
import java.util.ArrayList; import java.util.ArrayList;
@@ -50,9 +51,7 @@ import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.mock.env.MockEnvironment; import org.springframework.mock.env.MockEnvironment;
import static org.junit.Assert.assertEquals; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any; import static org.mockito.Mockito.any;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
@@ -64,6 +63,9 @@ import static org.mockito.Mockito.when;
*/ */
public class DeployerPartitionHandlerTests { public class DeployerPartitionHandlerTests {
@Captor
ArgumentCaptor<AppDeploymentRequest> appDeploymentRequestArgumentCaptor;
@Mock @Mock
private TaskLauncher taskLauncher; private TaskLauncher taskLauncher;
@@ -81,8 +83,6 @@ public class DeployerPartitionHandlerTests {
private Environment environment; private Environment environment;
@Captor ArgumentCaptor<AppDeploymentRequest> appDeploymentRequestArgumentCaptor;
@Before @Before
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
@@ -91,27 +91,33 @@ public class DeployerPartitionHandlerTests {
@Test @Test
public void testConstructorValidation() { public void testConstructorValidation() {
validateConstructorValidation(null, null, null, null, "A taskLauncher is required"); validateConstructorValidation(null, null, null, null,
validateConstructorValidation(this.taskLauncher, null, null, null, "A jobExplorer is required"); "A taskLauncher is required");
validateConstructorValidation(this.taskLauncher, this.jobExplorer, null, null, "A resource is required"); validateConstructorValidation(this.taskLauncher, null, null, null,
validateConstructorValidation(this.taskLauncher, this.jobExplorer, this.resource, null, "A step name is required"); "A jobExplorer is required");
validateConstructorValidation(this.taskLauncher, this.jobExplorer, null, null,
"A resource is required");
validateConstructorValidation(this.taskLauncher, this.jobExplorer, this.resource,
null, "A step name is required");
new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step-name"); new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource,
"step-name");
} }
@Test @Test
public void testNoPartitions() throws Exception { public void testNoPartitions() throws Exception {
DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1"); DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher,
this.jobExplorer, this.resource, "step1");
handler.setEnvironment(this.environment); handler.setEnvironment(this.environment);
StepExecution stepExecution = new StepExecution("step1", new JobExecution(1L)); StepExecution stepExecution = new StepExecution("step1", new JobExecution(1L));
when(this.splitter.split(stepExecution, 1)).thenReturn(new HashSet<StepExecution>()); when(this.splitter.split(stepExecution, 1)).thenReturn(new HashSet<>());
Collection<StepExecution> results = handler.handle(this.splitter, stepExecution); Collection<StepExecution> results = handler.handle(this.splitter, stepExecution);
verify(this.taskLauncher, never()).launch((AppDeploymentRequest) any()); verify(this.taskLauncher, never()).launch((AppDeploymentRequest) any());
assertTrue(results.isEmpty()); assertThat(results.isEmpty()).isTrue();
} }
@Test @Test
@@ -121,9 +127,11 @@ public class DeployerPartitionHandlerTests {
JobExecution jobExecution = masterStepExecution.getJobExecution(); JobExecution jobExecution = masterStepExecution.getJobExecution();
StepExecution workerStepExecutionStart = getStepExecutionStart(jobExecution, 4L); StepExecution workerStepExecutionStart = getStepExecutionStart(jobExecution, 4L);
StepExecution workerStepExecutionFinish = getStepExecutionFinish(workerStepExecutionStart, BatchStatus.COMPLETED); StepExecution workerStepExecutionFinish = getStepExecutionFinish(
workerStepExecutionStart, BatchStatus.COMPLETED);
DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1"); DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher,
this.jobExplorer, this.resource, "step1");
handler.setEnvironment(this.environment); handler.setEnvironment(this.environment);
TaskExecution taskExecution = new TaskExecution(); TaskExecution taskExecution = new TaskExecution();
@@ -133,32 +141,40 @@ public class DeployerPartitionHandlerTests {
stepExecutions.add(workerStepExecutionStart); stepExecutions.add(workerStepExecutionStart);
when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions); when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions);
when(this.jobExplorer.getStepExecution(1L, 4L)).thenReturn(workerStepExecutionFinish); when(this.jobExplorer.getStepExecution(1L, 4L))
.thenReturn(workerStepExecutionFinish);
handler.afterPropertiesSet(); handler.afterPropertiesSet();
handler.beforeTask(taskExecution); handler.beforeTask(taskExecution);
Collection<StepExecution> results = handler.handle(this.splitter, masterStepExecution); Collection<StepExecution> results = handler.handle(this.splitter,
masterStepExecution);
verify(this.taskLauncher).launch(this.appDeploymentRequestArgumentCaptor.capture()); verify(this.taskLauncher)
.launch(this.appDeploymentRequestArgumentCaptor.capture());
AppDeploymentRequest request = this.appDeploymentRequestArgumentCaptor.getValue(); AppDeploymentRequest request = this.appDeploymentRequestArgumentCaptor.getValue();
assertEquals(this.resource, request.getResource()); assertThat(request.getResource()).isEqualTo(this.resource);
assertEquals(0, request.getDeploymentProperties().size()); assertThat(request.getDeploymentProperties().size()).isEqualTo(0);
AppDefinition appDefinition = request.getDefinition(); AppDefinition appDefinition = request.getDefinition();
assertEquals("partitionedJobTask", appDefinition.getName()); assertThat(appDefinition.getName()).isEqualTo("partitionedJobTask");
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID, "1"))); assertThat(request.getCommandlineArguments().contains(formatArgs(
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID, "4"))); DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID, "1")))
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME, "step1"))); .isTrue();
assertThat(request.getCommandlineArguments().contains(formatArgs(
DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID, "4")))
.isTrue();
assertThat(request.getCommandlineArguments().contains(formatArgs(
DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME, "step1"))).isTrue();
assertEquals(1, results.size()); assertThat(results.size()).isEqualTo(1);
StepExecution resultStepExecution = results.iterator().next(); StepExecution resultStepExecution = results.iterator().next();
assertEquals(BatchStatus.COMPLETED, resultStepExecution.getStatus()); assertThat(resultStepExecution.getStatus()).isEqualTo(BatchStatus.COMPLETED);
assertEquals("step1:partition1", resultStepExecution.getStepName()); assertThat(resultStepExecution.getStepName()).isEqualTo("step1:partition1");
} }
@Test @Test
@@ -168,49 +184,64 @@ public class DeployerPartitionHandlerTests {
JobExecution jobExecution = masterStepExecution.getJobExecution(); JobExecution jobExecution = masterStepExecution.getJobExecution();
StepExecution workerStepExecutionStart = getStepExecutionStart(jobExecution, 4L); StepExecution workerStepExecutionStart = getStepExecutionStart(jobExecution, 4L);
StepExecution workerStepExecutionFinish = getStepExecutionFinish(workerStepExecutionStart, BatchStatus.COMPLETED); StepExecution workerStepExecutionFinish = getStepExecutionFinish(
workerStepExecutionStart, BatchStatus.COMPLETED);
DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1"); DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher,
this.jobExplorer, this.resource, "step1");
handler.setEnvironment(this.environment); handler.setEnvironment(this.environment);
handler.setDefaultArgsAsEnvironmentVars(true); handler.setDefaultArgsAsEnvironmentVars(true);
TaskExecution taskExecution = new TaskExecution(55, null, null, null, TaskExecution taskExecution = new TaskExecution(55, null, null, null, null, null,
null, null, new ArrayList<String>(), null, null); new ArrayList<>(), null, null);
taskExecution.setTaskName("partitionedJobTask"); taskExecution.setTaskName("partitionedJobTask");
Set<StepExecution> stepExecutions = new HashSet<>(); Set<StepExecution> stepExecutions = new HashSet<>();
stepExecutions.add(workerStepExecutionStart); stepExecutions.add(workerStepExecutionStart);
when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions); when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions);
when(this.jobExplorer.getStepExecution(1L, 4L)).thenReturn(workerStepExecutionFinish); when(this.jobExplorer.getStepExecution(1L, 4L))
.thenReturn(workerStepExecutionFinish);
handler.afterPropertiesSet(); handler.afterPropertiesSet();
handler.beforeTask(taskExecution); handler.beforeTask(taskExecution);
Collection<StepExecution> results = handler.handle(this.splitter, masterStepExecution); Collection<StepExecution> results = handler.handle(this.splitter,
masterStepExecution);
verify(this.taskLauncher).launch(this.appDeploymentRequestArgumentCaptor.capture()); verify(this.taskLauncher)
.launch(this.appDeploymentRequestArgumentCaptor.capture());
AppDeploymentRequest request = this.appDeploymentRequestArgumentCaptor.getValue(); AppDeploymentRequest request = this.appDeploymentRequestArgumentCaptor.getValue();
assertEquals(this.resource, request.getResource()); assertThat(request.getResource()).isEqualTo(this.resource);
assertEquals(0, request.getDeploymentProperties().size()); assertThat(request.getDeploymentProperties().size()).isEqualTo(0);
AppDefinition appDefinition = request.getDefinition(); AppDefinition appDefinition = request.getDefinition();
assertEquals("partitionedJobTask", appDefinition.getName()); assertThat(appDefinition.getName()).isEqualTo("partitionedJobTask");
assertTrue(request.getCommandlineArguments().isEmpty()); assertThat(request.getCommandlineArguments().isEmpty()).isTrue();
assertEquals("1", request.getDefinition().getProperties().get(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID)); assertThat(request.getDefinition().getProperties()
assertEquals("4", request.getDefinition().getProperties().get(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID)); .get(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID))
assertEquals("step1", request.getDefinition().getProperties().get(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME)); .isEqualTo("1");
assertEquals("partitionedJobTask_partitionedJob_step1:partition1", request.getDefinition().getProperties().get(DeployerPartitionHandler.SPRING_CLOUD_TASK_NAME)); assertThat(request.getDefinition().getProperties()
assertEquals("55", request.getDefinition().getProperties().get(DeployerPartitionHandler.SPRING_CLOUD_TASK_PARENT_EXECUTION_ID)); .get(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID))
.isEqualTo("4");
assertThat(request.getDefinition().getProperties()
.get(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME))
.isEqualTo("step1");
assertThat(request.getDefinition().getProperties()
.get(DeployerPartitionHandler.SPRING_CLOUD_TASK_NAME))
.isEqualTo("partitionedJobTask_partitionedJob_step1:partition1");
assertThat(request.getDefinition().getProperties()
.get(DeployerPartitionHandler.SPRING_CLOUD_TASK_PARENT_EXECUTION_ID))
.isEqualTo("55");
assertEquals(1, results.size()); assertThat(results.size()).isEqualTo(1);
StepExecution resultStepExecution = results.iterator().next(); StepExecution resultStepExecution = results.iterator().next();
assertEquals(BatchStatus.COMPLETED, resultStepExecution.getStatus()); assertThat(resultStepExecution.getStatus()).isEqualTo(BatchStatus.COMPLETED);
assertEquals("step1:partition1", resultStepExecution.getStepName()); assertThat(resultStepExecution.getStepName()).isEqualTo("step1:partition1");
} }
@Test @Test
@@ -220,13 +251,15 @@ public class DeployerPartitionHandlerTests {
JobExecution jobExecution = masterStepExecution.getJobExecution(); JobExecution jobExecution = masterStepExecution.getJobExecution();
StepExecution workerStepExecutionStart = getStepExecutionStart(jobExecution, 4L); StepExecution workerStepExecutionStart = getStepExecutionStart(jobExecution, 4L);
StepExecution workerStepExecutionFinish = getStepExecutionFinish(workerStepExecutionStart, BatchStatus.COMPLETED); StepExecution workerStepExecutionFinish = getStepExecutionFinish(
workerStepExecutionStart, BatchStatus.COMPLETED);
DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1"); DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher,
this.jobExplorer, this.resource, "step1");
handler.setEnvironment(this.environment); handler.setEnvironment(this.environment);
TaskExecution taskExecution = new TaskExecution(55, null, null, null, TaskExecution taskExecution = new TaskExecution(55, null, null, null, null, null,
null, null, new ArrayList<String>(), null, null); new ArrayList<>(), null, null);
taskExecution.setTaskName("partitionedJobTask"); taskExecution.setTaskName("partitionedJobTask");
@@ -234,7 +267,8 @@ public class DeployerPartitionHandlerTests {
stepExecutions.add(workerStepExecutionStart); stepExecutions.add(workerStepExecutionStart);
when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions); when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions);
when(this.jobExplorer.getStepExecution(1L, 4L)).thenReturn(workerStepExecutionFinish); when(this.jobExplorer.getStepExecution(1L, 4L))
.thenReturn(workerStepExecutionFinish);
handler.afterPropertiesSet(); handler.afterPropertiesSet();
@@ -242,10 +276,13 @@ public class DeployerPartitionHandlerTests {
handler.handle(this.splitter, masterStepExecution); handler.handle(this.splitter, masterStepExecution);
verify(this.taskLauncher).launch(this.appDeploymentRequestArgumentCaptor.capture()); verify(this.taskLauncher)
.launch(this.appDeploymentRequestArgumentCaptor.capture());
AppDeploymentRequest request = this.appDeploymentRequestArgumentCaptor.getValue(); AppDeploymentRequest request = this.appDeploymentRequestArgumentCaptor.getValue();
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_PARENT_EXECUTION_ID, "55"))); assertThat(request.getCommandlineArguments().contains(formatArgs(
DeployerPartitionHandler.SPRING_CLOUD_TASK_PARENT_EXECUTION_ID, "55")))
.isTrue();
} }
@Test @Test
@@ -255,15 +292,19 @@ public class DeployerPartitionHandlerTests {
JobExecution jobExecution = masterStepExecution.getJobExecution(); JobExecution jobExecution = masterStepExecution.getJobExecution();
StepExecution workerStepExecutionStart1 = getStepExecutionStart(jobExecution, 4L); StepExecution workerStepExecutionStart1 = getStepExecutionStart(jobExecution, 4L);
StepExecution workerStepExecutionFinish1 = getStepExecutionFinish(workerStepExecutionStart1, BatchStatus.COMPLETED); StepExecution workerStepExecutionFinish1 = getStepExecutionFinish(
workerStepExecutionStart1, BatchStatus.COMPLETED);
StepExecution workerStepExecutionStart2 = getStepExecutionStart(jobExecution, 5L); StepExecution workerStepExecutionStart2 = getStepExecutionStart(jobExecution, 5L);
StepExecution workerStepExecutionFinish2 = getStepExecutionFinish(workerStepExecutionStart2, BatchStatus.COMPLETED); StepExecution workerStepExecutionFinish2 = getStepExecutionFinish(
workerStepExecutionStart2, BatchStatus.COMPLETED);
StepExecution workerStepExecutionStart3 = getStepExecutionStart(jobExecution, 6L); StepExecution workerStepExecutionStart3 = getStepExecutionStart(jobExecution, 6L);
StepExecution workerStepExecutionFinish3 = getStepExecutionFinish(workerStepExecutionStart3, BatchStatus.COMPLETED); StepExecution workerStepExecutionFinish3 = getStepExecutionFinish(
workerStepExecutionStart3, BatchStatus.COMPLETED);
DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1"); DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher,
this.jobExplorer, this.resource, "step1");
handler.setEnvironment(this.environment); handler.setEnvironment(this.environment);
TaskExecution taskExecution = new TaskExecution(); TaskExecution taskExecution = new TaskExecution();
@@ -277,18 +318,24 @@ public class DeployerPartitionHandlerTests {
when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions); when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions);
when(this.jobExplorer.getStepExecution(1L, 4L)).thenReturn(workerStepExecutionFinish1); when(this.jobExplorer.getStepExecution(1L, 4L))
when(this.jobExplorer.getStepExecution(1L, 5L)).thenReturn(workerStepExecutionFinish2); .thenReturn(workerStepExecutionFinish1);
when(this.jobExplorer.getStepExecution(1L, 6L)).thenReturn(workerStepExecutionFinish3); when(this.jobExplorer.getStepExecution(1L, 5L))
.thenReturn(workerStepExecutionFinish2);
when(this.jobExplorer.getStepExecution(1L, 6L))
.thenReturn(workerStepExecutionFinish3);
handler.afterPropertiesSet(); handler.afterPropertiesSet();
handler.beforeTask(taskExecution); handler.beforeTask(taskExecution);
Collection<StepExecution> results = handler.handle(this.splitter, masterStepExecution); Collection<StepExecution> results = handler.handle(this.splitter,
masterStepExecution);
verify(this.taskLauncher, times(3)).launch(this.appDeploymentRequestArgumentCaptor.capture()); verify(this.taskLauncher, times(3))
.launch(this.appDeploymentRequestArgumentCaptor.capture());
List<AppDeploymentRequest> allValues = this.appDeploymentRequestArgumentCaptor.getAllValues(); List<AppDeploymentRequest> allValues = this.appDeploymentRequestArgumentCaptor
.getAllValues();
validateAppDeploymentRequests(allValues, 3); validateAppDeploymentRequests(allValues, 3);
@@ -302,15 +349,19 @@ public class DeployerPartitionHandlerTests {
JobExecution jobExecution = masterStepExecution.getJobExecution(); JobExecution jobExecution = masterStepExecution.getJobExecution();
StepExecution workerStepExecutionStart1 = getStepExecutionStart(jobExecution, 4L); StepExecution workerStepExecutionStart1 = getStepExecutionStart(jobExecution, 4L);
StepExecution workerStepExecutionFinish1 = getStepExecutionFinish(workerStepExecutionStart1, BatchStatus.COMPLETED); StepExecution workerStepExecutionFinish1 = getStepExecutionFinish(
workerStepExecutionStart1, BatchStatus.COMPLETED);
StepExecution workerStepExecutionStart2 = getStepExecutionStart(jobExecution, 5L); StepExecution workerStepExecutionStart2 = getStepExecutionStart(jobExecution, 5L);
StepExecution workerStepExecutionFinish2 = getStepExecutionFinish(workerStepExecutionStart2, BatchStatus.COMPLETED); StepExecution workerStepExecutionFinish2 = getStepExecutionFinish(
workerStepExecutionStart2, BatchStatus.COMPLETED);
StepExecution workerStepExecutionStart3 = getStepExecutionStart(jobExecution, 6L); StepExecution workerStepExecutionStart3 = getStepExecutionStart(jobExecution, 6L);
StepExecution workerStepExecutionFinish3 = getStepExecutionFinish(workerStepExecutionStart3, BatchStatus.COMPLETED); StepExecution workerStepExecutionFinish3 = getStepExecutionFinish(
workerStepExecutionStart3, BatchStatus.COMPLETED);
DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1"); DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher,
this.jobExplorer, this.resource, "step1");
handler.setEnvironment(this.environment); handler.setEnvironment(this.environment);
handler.setMaxWorkers(2); handler.setMaxWorkers(2);
@@ -325,18 +376,24 @@ public class DeployerPartitionHandlerTests {
when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions); when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions);
when(this.jobExplorer.getStepExecution(1L, 4L)).thenReturn(workerStepExecutionFinish1); when(this.jobExplorer.getStepExecution(1L, 4L))
when(this.jobExplorer.getStepExecution(1L, 5L)).thenReturn(workerStepExecutionFinish2); .thenReturn(workerStepExecutionFinish1);
when(this.jobExplorer.getStepExecution(1L, 6L)).thenReturn(workerStepExecutionFinish3); when(this.jobExplorer.getStepExecution(1L, 5L))
.thenReturn(workerStepExecutionFinish2);
when(this.jobExplorer.getStepExecution(1L, 6L))
.thenReturn(workerStepExecutionFinish3);
handler.afterPropertiesSet(); handler.afterPropertiesSet();
handler.beforeTask(taskExecution); handler.beforeTask(taskExecution);
Collection<StepExecution> results = handler.handle(this.splitter, masterStepExecution); Collection<StepExecution> results = handler.handle(this.splitter,
masterStepExecution);
verify(this.taskLauncher, times(3)).launch(this.appDeploymentRequestArgumentCaptor.capture()); verify(this.taskLauncher, times(3))
.launch(this.appDeploymentRequestArgumentCaptor.capture());
List<AppDeploymentRequest> allValues = this.appDeploymentRequestArgumentCaptor.getAllValues(); List<AppDeploymentRequest> allValues = this.appDeploymentRequestArgumentCaptor
.getAllValues();
validateAppDeploymentRequests(allValues, 3); validateAppDeploymentRequests(allValues, 3);
@@ -350,15 +407,19 @@ public class DeployerPartitionHandlerTests {
JobExecution jobExecution = masterStepExecution.getJobExecution(); JobExecution jobExecution = masterStepExecution.getJobExecution();
StepExecution workerStepExecutionStart1 = getStepExecutionStart(jobExecution, 4L); StepExecution workerStepExecutionStart1 = getStepExecutionStart(jobExecution, 4L);
StepExecution workerStepExecutionFinish1 = getStepExecutionFinish(workerStepExecutionStart1, BatchStatus.COMPLETED); StepExecution workerStepExecutionFinish1 = getStepExecutionFinish(
workerStepExecutionStart1, BatchStatus.COMPLETED);
StepExecution workerStepExecutionStart2 = getStepExecutionStart(jobExecution, 5L); StepExecution workerStepExecutionStart2 = getStepExecutionStart(jobExecution, 5L);
StepExecution workerStepExecutionFinish2 = getStepExecutionFinish(workerStepExecutionStart2, BatchStatus.FAILED); StepExecution workerStepExecutionFinish2 = getStepExecutionFinish(
workerStepExecutionStart2, BatchStatus.FAILED);
StepExecution workerStepExecutionStart3 = getStepExecutionStart(jobExecution, 6L); StepExecution workerStepExecutionStart3 = getStepExecutionStart(jobExecution, 6L);
StepExecution workerStepExecutionFinish3 = getStepExecutionFinish(workerStepExecutionStart3, BatchStatus.COMPLETED); StepExecution workerStepExecutionFinish3 = getStepExecutionFinish(
workerStepExecutionStart3, BatchStatus.COMPLETED);
DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1"); DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher,
this.jobExplorer, this.resource, "step1");
handler.setEnvironment(this.environment); handler.setEnvironment(this.environment);
handler.setMaxWorkers(2); handler.setMaxWorkers(2);
@@ -373,18 +434,24 @@ public class DeployerPartitionHandlerTests {
when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions); when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions);
when(this.jobExplorer.getStepExecution(1L, 4L)).thenReturn(workerStepExecutionFinish1); when(this.jobExplorer.getStepExecution(1L, 4L))
when(this.jobExplorer.getStepExecution(1L, 5L)).thenReturn(workerStepExecutionFinish2); .thenReturn(workerStepExecutionFinish1);
when(this.jobExplorer.getStepExecution(1L, 6L)).thenReturn(workerStepExecutionFinish3); when(this.jobExplorer.getStepExecution(1L, 5L))
.thenReturn(workerStepExecutionFinish2);
when(this.jobExplorer.getStepExecution(1L, 6L))
.thenReturn(workerStepExecutionFinish3);
handler.afterPropertiesSet(); handler.afterPropertiesSet();
handler.beforeTask(taskExecution); handler.beforeTask(taskExecution);
Collection<StepExecution> results = handler.handle(this.splitter, masterStepExecution); Collection<StepExecution> results = handler.handle(this.splitter,
masterStepExecution);
verify(this.taskLauncher, times(3)).launch(this.appDeploymentRequestArgumentCaptor.capture()); verify(this.taskLauncher, times(3))
.launch(this.appDeploymentRequestArgumentCaptor.capture());
List<AppDeploymentRequest> allValues = this.appDeploymentRequestArgumentCaptor.getAllValues(); List<AppDeploymentRequest> allValues = this.appDeploymentRequestArgumentCaptor
.getAllValues();
validateAppDeploymentRequests(allValues, 3); validateAppDeploymentRequests(allValues, 3);
@@ -395,13 +462,13 @@ public class DeployerPartitionHandlerTests {
StepExecution curResult = resultsIterator.next(); StepExecution curResult = resultsIterator.next();
if (curResult.getStepName().equals("step1:partition2")) { if (curResult.getStepName().equals("step1:partition2")) {
assertEquals(BatchStatus.FAILED, curResult.getStatus()); assertThat(curResult.getStatus()).isEqualTo(BatchStatus.FAILED);
} }
else { else {
assertEquals(BatchStatus.COMPLETED, curResult.getStatus()); assertThat(curResult.getStatus()).isEqualTo(BatchStatus.COMPLETED);
} }
assertTrue(!names.contains(curResult.getStepName())); assertThat(!names.contains(curResult.getStepName())).isTrue();
names.add(curResult.getStepName()); names.add(curResult.getStepName());
} }
} }
@@ -413,15 +480,18 @@ public class DeployerPartitionHandlerTests {
JobExecution jobExecution = masterStepExecution.getJobExecution(); JobExecution jobExecution = masterStepExecution.getJobExecution();
StepExecution workerStepExecutionStart = getStepExecutionStart(jobExecution, 4L); StepExecution workerStepExecutionStart = getStepExecutionStart(jobExecution, 4L);
StepExecution workerStepExecutionFinish = getStepExecutionFinish(workerStepExecutionStart, BatchStatus.COMPLETED); StepExecution workerStepExecutionFinish = getStepExecutionFinish(
workerStepExecutionStart, BatchStatus.COMPLETED);
DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1"); DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher,
this.jobExplorer, this.resource, "step1");
Map<String, String> environmentParameters = new HashMap<>(2); Map<String, String> environmentParameters = new HashMap<>(2);
environmentParameters.put("foo", "bar"); environmentParameters.put("foo", "bar");
environmentParameters.put("baz", "qux"); environmentParameters.put("baz", "qux");
SimpleEnvironmentVariablesProvider environmentVariablesProvider = new SimpleEnvironmentVariablesProvider(this.environment); SimpleEnvironmentVariablesProvider environmentVariablesProvider = new SimpleEnvironmentVariablesProvider(
this.environment);
environmentVariablesProvider.setEnvironmentProperties(environmentParameters); environmentVariablesProvider.setEnvironmentProperties(environmentParameters);
handler.setEnvironmentVariablesProvider(environmentVariablesProvider); handler.setEnvironmentVariablesProvider(environmentVariablesProvider);
@@ -432,33 +502,41 @@ public class DeployerPartitionHandlerTests {
stepExecutions.add(workerStepExecutionStart); stepExecutions.add(workerStepExecutionStart);
when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions); when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions);
when(this.jobExplorer.getStepExecution(1L, 4L)).thenReturn(workerStepExecutionFinish); when(this.jobExplorer.getStepExecution(1L, 4L))
.thenReturn(workerStepExecutionFinish);
handler.afterPropertiesSet(); handler.afterPropertiesSet();
handler.beforeTask(taskExecution); handler.beforeTask(taskExecution);
Collection<StepExecution> results = handler.handle(this.splitter, masterStepExecution); Collection<StepExecution> results = handler.handle(this.splitter,
masterStepExecution);
verify(this.taskLauncher).launch(this.appDeploymentRequestArgumentCaptor.capture()); verify(this.taskLauncher)
.launch(this.appDeploymentRequestArgumentCaptor.capture());
AppDeploymentRequest request = this.appDeploymentRequestArgumentCaptor.getValue(); AppDeploymentRequest request = this.appDeploymentRequestArgumentCaptor.getValue();
assertEquals(this.resource, request.getResource()); assertThat(request.getResource()).isEqualTo(this.resource);
assertEquals(2, request.getDefinition().getProperties().size()); assertThat(request.getDefinition().getProperties().size()).isEqualTo(2);
assertEquals("bar", request.getDefinition().getProperties().get("foo")); assertThat(request.getDefinition().getProperties().get("foo")).isEqualTo("bar");
assertEquals("qux", request.getDefinition().getProperties().get("baz")); assertThat(request.getDefinition().getProperties().get("baz")).isEqualTo("qux");
AppDefinition appDefinition = request.getDefinition(); AppDefinition appDefinition = request.getDefinition();
assertEquals("partitionedJobTask", appDefinition.getName()); assertThat(appDefinition.getName()).isEqualTo("partitionedJobTask");
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID, "1"))); assertThat(request.getCommandlineArguments().contains(formatArgs(
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID, "4"))); DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID, "1")))
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME, "step1"))); .isTrue();
assertThat(request.getCommandlineArguments().contains(formatArgs(
DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID, "4")))
.isTrue();
assertThat(request.getCommandlineArguments().contains(formatArgs(
DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME, "step1"))).isTrue();
assertEquals(1, results.size()); assertThat(results.size()).isEqualTo(1);
StepExecution resultStepExecution = results.iterator().next(); StepExecution resultStepExecution = results.iterator().next();
assertEquals(BatchStatus.COMPLETED, resultStepExecution.getStatus()); assertThat(resultStepExecution.getStatus()).isEqualTo(BatchStatus.COMPLETED);
assertEquals("step1:partition1", resultStepExecution.getStepName()); assertThat(resultStepExecution.getStepName()).isEqualTo("step1:partition1");
} }
@Test @Test
@@ -471,16 +549,19 @@ public class DeployerPartitionHandlerTests {
JobExecution jobExecution = masterStepExecution.getJobExecution(); JobExecution jobExecution = masterStepExecution.getJobExecution();
StepExecution workerStepExecutionStart = getStepExecutionStart(jobExecution, 4L); StepExecution workerStepExecutionStart = getStepExecutionStart(jobExecution, 4L);
StepExecution workerStepExecutionFinish = getStepExecutionFinish(workerStepExecutionStart, BatchStatus.COMPLETED); StepExecution workerStepExecutionFinish = getStepExecutionFinish(
workerStepExecutionStart, BatchStatus.COMPLETED);
DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1"); DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher,
this.jobExplorer, this.resource, "step1");
handler.setEnvironment(this.environment); handler.setEnvironment(this.environment);
Map<String, String> environmentParameters = new HashMap<>(2); Map<String, String> environmentParameters = new HashMap<>(2);
environmentParameters.put("foo", "bar"); environmentParameters.put("foo", "bar");
environmentParameters.put("baz", "qux"); environmentParameters.put("baz", "qux");
SimpleEnvironmentVariablesProvider environmentVariablesProvider = new SimpleEnvironmentVariablesProvider(this.environment); SimpleEnvironmentVariablesProvider environmentVariablesProvider = new SimpleEnvironmentVariablesProvider(
this.environment);
environmentVariablesProvider.setEnvironmentProperties(environmentParameters); environmentVariablesProvider.setEnvironmentProperties(environmentParameters);
handler.setEnvironmentVariablesProvider(environmentVariablesProvider); handler.setEnvironmentVariablesProvider(environmentVariablesProvider);
@@ -491,34 +572,43 @@ public class DeployerPartitionHandlerTests {
stepExecutions.add(workerStepExecutionStart); stepExecutions.add(workerStepExecutionStart);
when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions); when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions);
when(this.jobExplorer.getStepExecution(1L, 4L)).thenReturn(workerStepExecutionFinish); when(this.jobExplorer.getStepExecution(1L, 4L))
.thenReturn(workerStepExecutionFinish);
handler.afterPropertiesSet(); handler.afterPropertiesSet();
handler.beforeTask(taskExecution); handler.beforeTask(taskExecution);
Collection<StepExecution> results = handler.handle(this.splitter, masterStepExecution); Collection<StepExecution> results = handler.handle(this.splitter,
masterStepExecution);
verify(this.taskLauncher).launch(this.appDeploymentRequestArgumentCaptor.capture()); verify(this.taskLauncher)
.launch(this.appDeploymentRequestArgumentCaptor.capture());
AppDeploymentRequest request = this.appDeploymentRequestArgumentCaptor.getValue(); AppDeploymentRequest request = this.appDeploymentRequestArgumentCaptor.getValue();
assertEquals(this.resource, request.getResource()); assertThat(request.getResource()).isEqualTo(this.resource);
assertEquals(3, request.getDefinition().getProperties().size()); assertThat(request.getDefinition().getProperties().size()).isEqualTo(3);
assertEquals("bar", request.getDefinition().getProperties().get("foo")); assertThat(request.getDefinition().getProperties().get("foo")).isEqualTo("bar");
assertEquals("qux", request.getDefinition().getProperties().get("baz")); assertThat(request.getDefinition().getProperties().get("baz")).isEqualTo("qux");
assertEquals("batch", request.getDefinition().getProperties().get("task")); assertThat(request.getDefinition().getProperties().get("task"))
.isEqualTo("batch");
AppDefinition appDefinition = request.getDefinition(); AppDefinition appDefinition = request.getDefinition();
assertEquals("partitionedJobTask", appDefinition.getName()); assertThat(appDefinition.getName()).isEqualTo("partitionedJobTask");
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID, "1"))); assertThat(request.getCommandlineArguments().contains(formatArgs(
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID, "4"))); DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID, "1")))
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME, "step1"))); .isTrue();
assertThat(request.getCommandlineArguments().contains(formatArgs(
DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID, "4")))
.isTrue();
assertThat(request.getCommandlineArguments().contains(formatArgs(
DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME, "step1"))).isTrue();
assertEquals(1, results.size()); assertThat(results.size()).isEqualTo(1);
StepExecution resultStepExecution = results.iterator().next(); StepExecution resultStepExecution = results.iterator().next();
assertEquals(BatchStatus.COMPLETED, resultStepExecution.getStatus()); assertThat(resultStepExecution.getStatus()).isEqualTo(BatchStatus.COMPLETED);
assertEquals("step1:partition1", resultStepExecution.getStepName()); assertThat(resultStepExecution.getStepName()).isEqualTo("step1:partition1");
} }
@Test @Test
@@ -528,12 +618,15 @@ public class DeployerPartitionHandlerTests {
JobExecution jobExecution = masterStepExecution.getJobExecution(); JobExecution jobExecution = masterStepExecution.getJobExecution();
StepExecution workerStepExecutionStart1 = getStepExecutionStart(jobExecution, 4L); StepExecution workerStepExecutionStart1 = getStepExecutionStart(jobExecution, 4L);
StepExecution workerStepExecutionFinish1 = getStepExecutionFinish(workerStepExecutionStart1, BatchStatus.COMPLETED); StepExecution workerStepExecutionFinish1 = getStepExecutionFinish(
workerStepExecutionStart1, BatchStatus.COMPLETED);
StepExecution workerStepExecutionStart2 = getStepExecutionStart(jobExecution, 5L); StepExecution workerStepExecutionStart2 = getStepExecutionStart(jobExecution, 5L);
StepExecution workerStepExecutionFinish2 = getStepExecutionFinish(workerStepExecutionStart2, BatchStatus.COMPLETED); StepExecution workerStepExecutionFinish2 = getStepExecutionFinish(
workerStepExecutionStart2, BatchStatus.COMPLETED);
DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1"); DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher,
this.jobExplorer, this.resource, "step1");
handler.setEnvironment(this.environment); handler.setEnvironment(this.environment);
handler.setPollInterval(20000L); handler.setPollInterval(20000L);
@@ -547,26 +640,33 @@ public class DeployerPartitionHandlerTests {
stepExecutions.add(workerStepExecutionStart2); stepExecutions.add(workerStepExecutionStart2);
when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions); when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions);
when(this.jobExplorer.getStepExecution(1L, 4L)).thenReturn(workerStepExecutionFinish1); when(this.jobExplorer.getStepExecution(1L, 4L))
when(this.jobExplorer.getStepExecution(1L, 5L)).thenReturn(workerStepExecutionFinish2); .thenReturn(workerStepExecutionFinish1);
when(this.jobExplorer.getStepExecution(1L, 5L))
.thenReturn(workerStepExecutionFinish2);
handler.afterPropertiesSet(); handler.afterPropertiesSet();
handler.beforeTask(taskExecution); handler.beforeTask(taskExecution);
Date startTime = new Date(); Date startTime = new Date();
Collection<StepExecution> results = handler.handle(this.splitter, masterStepExecution); Collection<StepExecution> results = handler.handle(this.splitter,
masterStepExecution);
Date endTime = new Date(); Date endTime = new Date();
verify(this.taskLauncher, times(2)).launch(this.appDeploymentRequestArgumentCaptor.capture()); verify(this.taskLauncher, times(2))
.launch(this.appDeploymentRequestArgumentCaptor.capture());
List<AppDeploymentRequest> allRequests = this.appDeploymentRequestArgumentCaptor.getAllValues(); List<AppDeploymentRequest> allRequests = this.appDeploymentRequestArgumentCaptor
.getAllValues();
validateAppDeploymentRequests(allRequests, 2); validateAppDeploymentRequests(allRequests, 2);
validateStepExecutionResults(results); validateStepExecutionResults(results);
assertTrue("Time difference was too small: " + (endTime.getTime() - startTime.getTime()), assertThat(endTime.getTime() - startTime.getTime() >= 19999)
endTime.getTime() - startTime.getTime() >= 19999); .as("Time difference was too small: "
+ (endTime.getTime() - startTime.getTime()))
.isTrue();
} }
@Test(expected = TimeoutException.class) @Test(expected = TimeoutException.class)
@@ -576,12 +676,15 @@ public class DeployerPartitionHandlerTests {
JobExecution jobExecution = masterStepExecution.getJobExecution(); JobExecution jobExecution = masterStepExecution.getJobExecution();
StepExecution workerStepExecutionStart1 = getStepExecutionStart(jobExecution, 4L); StepExecution workerStepExecutionStart1 = getStepExecutionStart(jobExecution, 4L);
StepExecution workerStepExecutionFinish1 = getStepExecutionFinish(workerStepExecutionStart1, BatchStatus.COMPLETED); StepExecution workerStepExecutionFinish1 = getStepExecutionFinish(
workerStepExecutionStart1, BatchStatus.COMPLETED);
StepExecution workerStepExecutionStart2 = getStepExecutionStart(jobExecution, 5L); StepExecution workerStepExecutionStart2 = getStepExecutionStart(jobExecution, 5L);
StepExecution workerStepExecutionFinish2 = getStepExecutionFinish(workerStepExecutionStart2, BatchStatus.COMPLETED); StepExecution workerStepExecutionFinish2 = getStepExecutionFinish(
workerStepExecutionStart2, BatchStatus.COMPLETED);
DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1"); DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher,
this.jobExplorer, this.resource, "step1");
handler.setEnvironment(this.environment); handler.setEnvironment(this.environment);
handler.setPollInterval(20000L); handler.setPollInterval(20000L);
@@ -596,8 +699,10 @@ public class DeployerPartitionHandlerTests {
stepExecutions.add(workerStepExecutionStart2); stepExecutions.add(workerStepExecutionStart2);
when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions); when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions);
when(this.jobExplorer.getStepExecution(1L, 4L)).thenReturn(workerStepExecutionFinish1); when(this.jobExplorer.getStepExecution(1L, 4L))
when(this.jobExplorer.getStepExecution(1L, 5L)).thenReturn(workerStepExecutionFinish2); .thenReturn(workerStepExecutionFinish1);
when(this.jobExplorer.getStepExecution(1L, 5L))
.thenReturn(workerStepExecutionFinish2);
handler.afterPropertiesSet(); handler.afterPropertiesSet();
@@ -613,12 +718,15 @@ public class DeployerPartitionHandlerTests {
JobExecution jobExecution = masterStepExecution.getJobExecution(); JobExecution jobExecution = masterStepExecution.getJobExecution();
StepExecution workerStepExecutionStart1 = getStepExecutionStart(jobExecution, 4L); StepExecution workerStepExecutionStart1 = getStepExecutionStart(jobExecution, 4L);
StepExecution workerStepExecutionFinish1 = getStepExecutionFinish(workerStepExecutionStart1, BatchStatus.COMPLETED); StepExecution workerStepExecutionFinish1 = getStepExecutionFinish(
workerStepExecutionStart1, BatchStatus.COMPLETED);
StepExecution workerStepExecutionStart2 = getStepExecutionStart(jobExecution, 5L); StepExecution workerStepExecutionStart2 = getStepExecutionStart(jobExecution, 5L);
StepExecution workerStepExecutionFinish2 = getStepExecutionFinish(workerStepExecutionStart2, BatchStatus.COMPLETED); StepExecution workerStepExecutionFinish2 = getStepExecutionFinish(
workerStepExecutionStart2, BatchStatus.COMPLETED);
DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1"); DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher,
this.jobExplorer, this.resource, "step1");
handler.setEnvironment(this.environment); handler.setEnvironment(this.environment);
handler.setGridSize(2); handler.setGridSize(2);
@@ -631,18 +739,23 @@ public class DeployerPartitionHandlerTests {
stepExecutions.add(workerStepExecutionStart2); stepExecutions.add(workerStepExecutionStart2);
when(this.splitter.split(masterStepExecution, 2)).thenReturn(stepExecutions); when(this.splitter.split(masterStepExecution, 2)).thenReturn(stepExecutions);
when(this.jobExplorer.getStepExecution(1L, 4L)).thenReturn(workerStepExecutionFinish1); when(this.jobExplorer.getStepExecution(1L, 4L))
when(this.jobExplorer.getStepExecution(1L, 5L)).thenReturn(workerStepExecutionFinish2); .thenReturn(workerStepExecutionFinish1);
when(this.jobExplorer.getStepExecution(1L, 5L))
.thenReturn(workerStepExecutionFinish2);
handler.afterPropertiesSet(); handler.afterPropertiesSet();
handler.beforeTask(taskExecution); handler.beforeTask(taskExecution);
Collection<StepExecution> results = handler.handle(this.splitter, masterStepExecution); Collection<StepExecution> results = handler.handle(this.splitter,
masterStepExecution);
verify(this.taskLauncher, times(2)).launch(this.appDeploymentRequestArgumentCaptor.capture()); verify(this.taskLauncher, times(2))
.launch(this.appDeploymentRequestArgumentCaptor.capture());
List<AppDeploymentRequest> allRequests = this.appDeploymentRequestArgumentCaptor.getAllValues(); List<AppDeploymentRequest> allRequests = this.appDeploymentRequestArgumentCaptor
.getAllValues();
validateAppDeploymentRequests(allRequests, 2); validateAppDeploymentRequests(allRequests, 2);
@@ -656,9 +769,11 @@ public class DeployerPartitionHandlerTests {
JobExecution jobExecution = masterStepExecution.getJobExecution(); JobExecution jobExecution = masterStepExecution.getJobExecution();
StepExecution workerStepExecutionStart = getStepExecutionStart(jobExecution, 4L); StepExecution workerStepExecutionStart = getStepExecutionStart(jobExecution, 4L);
StepExecution workerStepExecutionFinish = getStepExecutionFinish(workerStepExecutionStart, BatchStatus.COMPLETED); StepExecution workerStepExecutionFinish = getStepExecutionFinish(
workerStepExecutionStart, BatchStatus.COMPLETED);
DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1"); DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher,
this.jobExplorer, this.resource, "step1");
handler.setEnvironment(this.environment); handler.setEnvironment(this.environment);
Map<String, String> deploymentProperties = new HashMap<>(2); Map<String, String> deploymentProperties = new HashMap<>(2);
@@ -674,48 +789,59 @@ public class DeployerPartitionHandlerTests {
stepExecutions.add(workerStepExecutionStart); stepExecutions.add(workerStepExecutionStart);
when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions); when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions);
when(this.jobExplorer.getStepExecution(1L, 4L)).thenReturn(workerStepExecutionFinish); when(this.jobExplorer.getStepExecution(1L, 4L))
.thenReturn(workerStepExecutionFinish);
handler.afterPropertiesSet(); handler.afterPropertiesSet();
handler.beforeTask(taskExecution); handler.beforeTask(taskExecution);
Collection<StepExecution> results = handler.handle(this.splitter, masterStepExecution); Collection<StepExecution> results = handler.handle(this.splitter,
masterStepExecution);
verify(this.taskLauncher).launch(this.appDeploymentRequestArgumentCaptor.capture()); verify(this.taskLauncher)
.launch(this.appDeploymentRequestArgumentCaptor.capture());
AppDeploymentRequest request = this.appDeploymentRequestArgumentCaptor.getValue(); AppDeploymentRequest request = this.appDeploymentRequestArgumentCaptor.getValue();
assertEquals(this.resource, request.getResource()); assertThat(request.getResource()).isEqualTo(this.resource);
assertEquals(2, request.getDeploymentProperties().size()); assertThat(request.getDeploymentProperties().size()).isEqualTo(2);
assertEquals("bar", request.getDeploymentProperties().get("foo")); assertThat(request.getDeploymentProperties().get("foo")).isEqualTo("bar");
assertEquals("qux", request.getDeploymentProperties().get("baz")); assertThat(request.getDeploymentProperties().get("baz")).isEqualTo("qux");
AppDefinition appDefinition = request.getDefinition(); AppDefinition appDefinition = request.getDefinition();
assertEquals("partitionedJobTask", appDefinition.getName()); assertThat(appDefinition.getName()).isEqualTo("partitionedJobTask");
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID, "1"))); assertThat(request.getCommandlineArguments().contains(formatArgs(
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID, "4"))); DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID, "1")))
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME, "step1"))); .isTrue();
assertThat(request.getCommandlineArguments().contains(formatArgs(
DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID, "4")))
.isTrue();
assertThat(request.getCommandlineArguments().contains(formatArgs(
DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME, "step1"))).isTrue();
assertEquals(1, results.size()); assertThat(results.size()).isEqualTo(1);
StepExecution resultStepExecution = results.iterator().next(); StepExecution resultStepExecution = results.iterator().next();
assertEquals(BatchStatus.COMPLETED, resultStepExecution.getStatus()); assertThat(resultStepExecution.getStatus()).isEqualTo(BatchStatus.COMPLETED);
assertEquals("step1:partition1", resultStepExecution.getStepName()); assertThat(resultStepExecution.getStepName()).isEqualTo("step1:partition1");
} }
private String formatArgs(String key, String value) { private String formatArgs(String key, String value) {
return String.format("--%s=%s", key, value); return String.format("--%s=%s", key, value);
} }
private StepExecution getStepExecutionFinish(StepExecution stepExecutionStart, BatchStatus status) { private StepExecution getStepExecutionFinish(StepExecution stepExecutionStart,
StepExecution workerStepExecutionFinish = new StepExecution(stepExecutionStart.getStepName(), stepExecutionStart.getJobExecution()); BatchStatus status) {
StepExecution workerStepExecutionFinish = new StepExecution(
stepExecutionStart.getStepName(), stepExecutionStart.getJobExecution());
workerStepExecutionFinish.setId(stepExecutionStart.getId()); workerStepExecutionFinish.setId(stepExecutionStart.getId());
workerStepExecutionFinish.setStatus(status); workerStepExecutionFinish.setStatus(status);
return workerStepExecutionFinish; return workerStepExecutionFinish;
} }
private StepExecution getStepExecutionStart(JobExecution jobExecution, long id) { private StepExecution getStepExecutionStart(JobExecution jobExecution, long id) {
StepExecution workerStepExecutionStart = new StepExecution("step1:partition" + (id - 3), jobExecution); StepExecution workerStepExecutionStart = new StepExecution(
"step1:partition" + (id - 3), jobExecution);
workerStepExecutionStart.setId(id); workerStepExecutionStart.setId(id);
return workerStepExecutionStart; return workerStepExecutionStart;
} }
@@ -738,14 +864,15 @@ public class DeployerPartitionHandlerTests {
while (resultsIterator.hasNext()) { while (resultsIterator.hasNext()) {
StepExecution curResult = resultsIterator.next(); StepExecution curResult = resultsIterator.next();
assertEquals(BatchStatus.COMPLETED, curResult.getStatus()); assertThat(curResult.getStatus()).isEqualTo(BatchStatus.COMPLETED);
assertTrue(!names.contains(curResult.getStepName())); assertThat(!names.contains(curResult.getStepName())).isTrue();
names.add(curResult.getStepName()); names.add(curResult.getStepName());
} }
} }
private void validateAppDeploymentRequests(List<AppDeploymentRequest> allRequests, int numberOfPartitions) { private void validateAppDeploymentRequests(List<AppDeploymentRequest> allRequests,
int numberOfPartitions) {
Collections.sort(allRequests, new Comparator<AppDeploymentRequest>() { Collections.sort(allRequests, new Comparator<AppDeploymentRequest>() {
@Override @Override
public int compare(AppDeploymentRequest o1, AppDeploymentRequest o2) { public int compare(AppDeploymentRequest o1, AppDeploymentRequest o2) {
@@ -753,7 +880,8 @@ public class DeployerPartitionHandlerTests {
String o1Command = ""; String o1Command = "";
for (String commandlineArgument : commandlineArguments) { for (String commandlineArgument : commandlineArguments) {
if(commandlineArgument.contains(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID)) { if (commandlineArgument.contains(
DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID)) {
o1Command = commandlineArgument; o1Command = commandlineArgument;
break; break;
} }
@@ -763,7 +891,8 @@ public class DeployerPartitionHandlerTests {
String o2Command = ""; String o2Command = "";
for (String commandlineArgument : commandlineArguments) { for (String commandlineArgument : commandlineArguments) {
if(commandlineArgument.contains(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID)) { if (commandlineArgument.contains(
DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID)) {
o2Command = commandlineArgument; o2Command = commandlineArgument;
break; break;
} }
@@ -775,23 +904,33 @@ public class DeployerPartitionHandlerTests {
for (int i = 4; i < (numberOfPartitions + 4); i++) { for (int i = 4; i < (numberOfPartitions + 4); i++) {
AppDeploymentRequest request = allRequests.get(i - 4); AppDeploymentRequest request = allRequests.get(i - 4);
assertEquals(this.resource, request.getResource()); assertThat(request.getResource()).isEqualTo(this.resource);
assertEquals(0, request.getDeploymentProperties().size()); assertThat(request.getDeploymentProperties().size()).isEqualTo(0);
AppDefinition appDefinition = request.getDefinition(); AppDefinition appDefinition = request.getDefinition();
assertEquals("partitionedJobTask", appDefinition.getName()); assertThat(appDefinition.getName()).isEqualTo("partitionedJobTask");
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID, "1"))); assertThat(request.getCommandlineArguments().contains(formatArgs(
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID, String.valueOf(i)))); DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID, "1")))
assertTrue(request.getCommandlineArguments().contains(formatArgs(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME, "step1"))); .isTrue();
assertThat(request.getCommandlineArguments()
.contains(formatArgs(
DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID,
String.valueOf(i)))).isTrue();
assertThat(request.getCommandlineArguments().contains(formatArgs(
DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME, "step1")))
.isTrue();
} }
} }
private void validateConstructorValidation(TaskLauncher taskLauncher, JobExplorer jobExplorer, Resource resource, String stepName, String expectedMessage) { private void validateConstructorValidation(TaskLauncher taskLauncher,
JobExplorer jobExplorer, Resource resource, String stepName,
String expectedMessage) {
try { try {
new DeployerPartitionHandler(taskLauncher, jobExplorer, resource, stepName); new DeployerPartitionHandler(taskLauncher, jobExplorer, resource, stepName);
} }
catch (IllegalArgumentException iae) { catch (IllegalArgumentException iae) {
assertEquals(expectedMessage, iae.getMessage()); assertThat(iae.getMessage()).isEqualTo(expectedMessage);
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.partition; package org.springframework.cloud.task.batch.partition;
import org.junit.Before; import org.junit.Before;
@@ -35,7 +36,7 @@ import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.util.ReflectionTestUtils;
import static org.junit.Assert.assertEquals; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.verifyZeroInteractions;
@@ -70,7 +71,8 @@ public class DeployerStepExecutionHandlerTests {
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
this.handler = new DeployerStepExecutionHandler(this.beanFactory, this.jobExplorer, this.jobRepository); this.handler = new DeployerStepExecutionHandler(this.beanFactory,
this.jobExplorer, this.jobRepository);
ReflectionTestUtils.setField(this.handler, "environment", this.environment); ReflectionTestUtils.setField(this.handler, "environment", this.environment);
} }
@@ -78,69 +80,116 @@ public class DeployerStepExecutionHandlerTests {
@Test @Test
public void testConstructorValidation() { public void testConstructorValidation() {
validateConstructorValidation(null, null, null, "A beanFactory is required"); validateConstructorValidation(null, null, null, "A beanFactory is required");
validateConstructorValidation(this.beanFactory, null, null, "A jobExplorer is required"); validateConstructorValidation(this.beanFactory, null, null,
validateConstructorValidation(this.beanFactory, this.jobExplorer, null, "A jobRepository is required"); "A jobExplorer is required");
validateConstructorValidation(this.beanFactory, this.jobExplorer, null,
"A jobRepository is required");
new DeployerStepExecutionHandler(this.beanFactory, this.jobExplorer, this.jobRepository); new DeployerStepExecutionHandler(this.beanFactory, this.jobExplorer,
this.jobRepository);
} }
@Test @Test
public void testValidationOfRequestValuesExist() throws Exception { public void testValidationOfRequestValuesExist() throws Exception {
validateEnvironmentConfiguration("A job execution id is required", new String[0]); validateEnvironmentConfiguration("A job execution id is required", new String[0]);
validateEnvironmentConfiguration("A step execution id is required", new String[] {DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID}); validateEnvironmentConfiguration("A step execution id is required", new String[] {
validateEnvironmentConfiguration("A step name is required", new String[] {DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID, DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID}); DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID });
validateEnvironmentConfiguration("A step name is required",
new String[] {
DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID,
DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID });
} }
@Test @Test
public void testValidationOfRequestStepFound() throws Exception { public void testValidationOfRequestStepFound() throws Exception {
when(this.environment.containsProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID)).thenReturn(true); when(this.environment.containsProperty(
when(this.environment.containsProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID)).thenReturn(true); DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID))
when(this.environment.containsProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME)).thenReturn(true); .thenReturn(true);
when(this.environment.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME)).thenReturn("foo"); when(this.environment.containsProperty(
when(this.beanFactory.getBeanNamesForType(Step.class)).thenReturn(new String[] {"bar", "baz"}); DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID))
.thenReturn(true);
when(this.environment
.containsProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME))
.thenReturn(true);
when(this.environment
.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME))
.thenReturn("foo");
when(this.beanFactory.getBeanNamesForType(Step.class))
.thenReturn(new String[] { "bar", "baz" });
try { try {
this.handler.run(); this.handler.run();
} }
catch (IllegalArgumentException iae) { catch (IllegalArgumentException iae) {
assertEquals("The step requested cannot be found in the provided BeanFactory", iae.getMessage()); assertThat(iae.getMessage()).isEqualTo(
"The step requested cannot be found in the provided BeanFactory");
} }
} }
@Test @Test
public void testMissingStepExecution() throws Exception { public void testMissingStepExecution() throws Exception {
when(this.environment.containsProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID)).thenReturn(true); when(this.environment.containsProperty(
when(this.environment.containsProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID)).thenReturn(true); DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID))
when(this.environment.containsProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME)).thenReturn(true); .thenReturn(true);
when(this.environment.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME)).thenReturn("foo"); when(this.environment.containsProperty(
when(this.beanFactory.getBeanNamesForType(Step.class)).thenReturn(new String[] {"foo", "bar", "baz"}); DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID))
when(this.environment.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID)).thenReturn("2"); .thenReturn(true);
when(this.environment.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID)).thenReturn("1"); when(this.environment
.containsProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME))
.thenReturn(true);
when(this.environment
.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME))
.thenReturn("foo");
when(this.beanFactory.getBeanNamesForType(Step.class))
.thenReturn(new String[] { "foo", "bar", "baz" });
when(this.environment.getProperty(
DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID))
.thenReturn("2");
when(this.environment
.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID))
.thenReturn("1");
try { try {
this.handler.run(); this.handler.run();
} }
catch (NoSuchStepException nsse) { catch (NoSuchStepException nsse) {
assertEquals("No StepExecution could be located for step execution id 2 within job execution 1", nsse.getMessage()); assertThat(nsse.getMessage()).isEqualTo(
"No StepExecution could be located for step execution id 2 within job execution 1");
} }
} }
@Test @Test
public void testRunSuccessful() throws Exception { public void testRunSuccessful() throws Exception {
StepExecution workerStep = new StepExecution("workerStep", new JobExecution(1L), 2L); StepExecution workerStep = new StepExecution("workerStep", new JobExecution(1L),
2L);
when(this.environment.containsProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID)).thenReturn(true); when(this.environment.containsProperty(
when(this.environment.containsProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID)).thenReturn(true); DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID))
when(this.environment.containsProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME)).thenReturn(true); .thenReturn(true);
when(this.environment.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME)).thenReturn("workerStep"); when(this.environment.containsProperty(
when(this.beanFactory.getBeanNamesForType(Step.class)).thenReturn(new String[] {"workerStep", "foo", "bar"}); DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID))
when(this.environment.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID)).thenReturn("2"); .thenReturn(true);
when(this.environment.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID)).thenReturn("1"); when(this.environment
.containsProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME))
.thenReturn(true);
when(this.environment
.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME))
.thenReturn("workerStep");
when(this.beanFactory.getBeanNamesForType(Step.class))
.thenReturn(new String[] { "workerStep", "foo", "bar" });
when(this.environment.getProperty(
DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID))
.thenReturn("2");
when(this.environment
.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID))
.thenReturn("1");
when(this.jobExplorer.getStepExecution(1L, 2L)).thenReturn(workerStep); when(this.jobExplorer.getStepExecution(1L, 2L)).thenReturn(workerStep);
when(this.environment.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME)).thenReturn("workerStep"); when(this.environment
.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME))
.thenReturn("workerStep");
when(this.beanFactory.getBean("workerStep", Step.class)).thenReturn(this.step); when(this.beanFactory.getBean("workerStep", Step.class)).thenReturn(this.step);
handler.run(); this.handler.run();
verify(this.step).execute(workerStep); verify(this.step).execute(workerStep);
verifyZeroInteractions(this.jobRepository); verifyZeroInteractions(this.jobRepository);
@@ -148,51 +197,87 @@ public class DeployerStepExecutionHandlerTests {
@Test @Test
public void testJobInterruptedException() throws Exception { public void testJobInterruptedException() throws Exception {
StepExecution workerStep = new StepExecution("workerStep", new JobExecution(1L), 2L); StepExecution workerStep = new StepExecution("workerStep", new JobExecution(1L),
2L);
when(this.environment.containsProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID)).thenReturn(true); when(this.environment.containsProperty(
when(this.environment.containsProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID)).thenReturn(true); DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID))
when(this.environment.containsProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME)).thenReturn(true); .thenReturn(true);
when(this.environment.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME)).thenReturn("workerStep"); when(this.environment.containsProperty(
when(this.beanFactory.getBeanNamesForType(Step.class)).thenReturn(new String[] {"workerStep", "foo", "bar"}); DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID))
when(this.environment.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID)).thenReturn("2"); .thenReturn(true);
when(this.environment.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID)).thenReturn("1"); when(this.environment
.containsProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME))
.thenReturn(true);
when(this.environment
.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME))
.thenReturn("workerStep");
when(this.beanFactory.getBeanNamesForType(Step.class))
.thenReturn(new String[] { "workerStep", "foo", "bar" });
when(this.environment.getProperty(
DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID))
.thenReturn("2");
when(this.environment
.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID))
.thenReturn("1");
when(this.jobExplorer.getStepExecution(1L, 2L)).thenReturn(workerStep); when(this.jobExplorer.getStepExecution(1L, 2L)).thenReturn(workerStep);
when(this.environment.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME)).thenReturn("workerStep"); when(this.environment
.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME))
.thenReturn("workerStep");
when(this.beanFactory.getBean("workerStep", Step.class)).thenReturn(this.step); when(this.beanFactory.getBean("workerStep", Step.class)).thenReturn(this.step);
doThrow(new JobInterruptedException("expected")).when(this.step).execute(workerStep); doThrow(new JobInterruptedException("expected")).when(this.step)
.execute(workerStep);
handler.run(); this.handler.run();
verify(this.jobRepository).update(this.stepExecutionArgumentCaptor.capture()); verify(this.jobRepository).update(this.stepExecutionArgumentCaptor.capture());
assertEquals(BatchStatus.STOPPED, this.stepExecutionArgumentCaptor.getValue().getStatus()); assertThat(this.stepExecutionArgumentCaptor.getValue().getStatus())
.isEqualTo(BatchStatus.STOPPED);
} }
@Test @Test
public void testRuntimeException() throws Exception { public void testRuntimeException() throws Exception {
StepExecution workerStep = new StepExecution("workerStep", new JobExecution(1L), 2L); StepExecution workerStep = new StepExecution("workerStep", new JobExecution(1L),
2L);
when(this.environment.containsProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID)).thenReturn(true); when(this.environment.containsProperty(
when(this.environment.containsProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID)).thenReturn(true); DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID))
when(this.environment.containsProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME)).thenReturn(true); .thenReturn(true);
when(this.environment.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME)).thenReturn("workerStep"); when(this.environment.containsProperty(
when(this.beanFactory.getBeanNamesForType(Step.class)).thenReturn(new String[] {"workerStep", "foo", "bar"}); DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID))
when(this.environment.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID)).thenReturn("2"); .thenReturn(true);
when(this.environment.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID)).thenReturn("1"); when(this.environment
.containsProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME))
.thenReturn(true);
when(this.environment
.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME))
.thenReturn("workerStep");
when(this.beanFactory.getBeanNamesForType(Step.class))
.thenReturn(new String[] { "workerStep", "foo", "bar" });
when(this.environment.getProperty(
DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID))
.thenReturn("2");
when(this.environment
.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID))
.thenReturn("1");
when(this.jobExplorer.getStepExecution(1L, 2L)).thenReturn(workerStep); when(this.jobExplorer.getStepExecution(1L, 2L)).thenReturn(workerStep);
when(this.environment.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME)).thenReturn("workerStep"); when(this.environment
.getProperty(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME))
.thenReturn("workerStep");
when(this.beanFactory.getBean("workerStep", Step.class)).thenReturn(this.step); when(this.beanFactory.getBean("workerStep", Step.class)).thenReturn(this.step);
doThrow(new RuntimeException("expected")).when(this.step).execute(workerStep); doThrow(new RuntimeException("expected")).when(this.step).execute(workerStep);
handler.run(); this.handler.run();
verify(this.jobRepository).update(this.stepExecutionArgumentCaptor.capture()); verify(this.jobRepository).update(this.stepExecutionArgumentCaptor.capture());
assertEquals(BatchStatus.FAILED, this.stepExecutionArgumentCaptor.getValue().getStatus()); assertThat(this.stepExecutionArgumentCaptor.getValue().getStatus())
.isEqualTo(BatchStatus.FAILED);
} }
private void validateEnvironmentConfiguration(String errorMessage, String[] properties) throws Exception { private void validateEnvironmentConfiguration(String errorMessage,
String[] properties) throws Exception {
for (String property : properties) { for (String property : properties) {
when(this.environment.containsProperty(property)).thenReturn(true); when(this.environment.containsProperty(property)).thenReturn(true);
@@ -202,17 +287,18 @@ public class DeployerStepExecutionHandlerTests {
this.handler.run(); this.handler.run();
} }
catch (IllegalArgumentException iae) { catch (IllegalArgumentException iae) {
assertEquals(errorMessage, iae.getMessage()); assertThat(iae.getMessage()).isEqualTo(errorMessage);
} }
} }
private void validateConstructorValidation(BeanFactory beanFactory,
private void validateConstructorValidation(BeanFactory beanFactory, JobExplorer jobExplorer, JobRepository jobRepository, String message) { JobExplorer jobExplorer, JobRepository jobRepository, String message) {
try { try {
new DeployerStepExecutionHandler(beanFactory, jobExplorer, jobRepository); new DeployerStepExecutionHandler(beanFactory, jobExplorer, jobRepository);
} }
catch (IllegalArgumentException iae) { catch (IllegalArgumentException iae) {
assertEquals(message, iae.getMessage()); assertThat(iae.getMessage()).isEqualTo(message);
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,13 +13,15 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.partition; package org.springframework.cloud.task.batch.partition;
import java.util.Map; import java.util.Map;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.*;
import static org.assertj.core.api.Assertions.assertThat;
/** /**
* @author Michael Minella * @author Michael Minella
@@ -35,11 +37,14 @@ public class NoOpEnvironmentVariablesProviderTests {
@Test @Test
public void test() { public void test() {
Map<String, String> environmentVariables = this.provider.getEnvironmentVariables(null); Map<String, String> environmentVariables = this.provider
assertNotNull(environmentVariables); .getEnvironmentVariables(null);
assertTrue(environmentVariables.isEmpty()); assertThat(environmentVariables).isNotNull();
assertThat(environmentVariables.isEmpty()).isTrue();
Map<String, String> environmentVariables2 = this.provider.getEnvironmentVariables(null); Map<String, String> environmentVariables2 = this.provider
assertTrue(environmentVariables == environmentVariables2); .getEnvironmentVariables(null);
assertThat(environmentVariables == environmentVariables2).isTrue();
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,13 +13,15 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.partition; package org.springframework.cloud.task.batch.partition;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.*;
import static org.assertj.core.api.Assertions.assertThat;
/** /**
* @author Michael Minella * @author Michael Minella
@@ -39,8 +41,9 @@ public class PassThroughCommandLineArgsProviderTests {
List<String> commandLineArgs = provider.getCommandLineArgs(null); List<String> commandLineArgs = provider.getCommandLineArgs(null);
assertEquals("foo", commandLineArgs.get(0)); assertThat(commandLineArgs.get(0)).isEqualTo("foo");
assertEquals("bar", commandLineArgs.get(1)); assertThat(commandLineArgs.get(1)).isEqualTo("bar");
assertEquals("baz", commandLineArgs.get(2)); assertThat(commandLineArgs.get(2)).isEqualTo("baz");
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.batch.partition; package org.springframework.cloud.task.batch.partition;
import java.util.ArrayList; import java.util.ArrayList;
@@ -23,7 +24,7 @@ import org.junit.Test;
import org.springframework.cloud.task.repository.TaskExecution; import org.springframework.cloud.task.repository.TaskExecution;
import static org.junit.Assert.assertEquals; import static org.assertj.core.api.Assertions.assertThat;
/** /**
* @author Michael Minella * @author Michael Minella
@@ -35,13 +36,14 @@ public class SimpleCommandLineArgsProviderTests {
TaskExecution taskExecution = new TaskExecution(); TaskExecution taskExecution = new TaskExecution();
taskExecution.setArguments(Arrays.asList("foo", "bar", "baz")); taskExecution.setArguments(Arrays.asList("foo", "bar", "baz"));
SimpleCommandLineArgsProvider provider = new SimpleCommandLineArgsProvider(taskExecution); SimpleCommandLineArgsProvider provider = new SimpleCommandLineArgsProvider(
taskExecution);
List<String> commandLineArgs = provider.getCommandLineArgs(null); List<String> commandLineArgs = provider.getCommandLineArgs(null);
assertEquals("foo", commandLineArgs.get(0)); assertThat(commandLineArgs.get(0)).isEqualTo("foo");
assertEquals("bar", commandLineArgs.get(1)); assertThat(commandLineArgs.get(1)).isEqualTo("bar");
assertEquals("baz", commandLineArgs.get(2)); assertThat(commandLineArgs.get(2)).isEqualTo("baz");
} }
@Test @Test
@@ -54,17 +56,18 @@ public class SimpleCommandLineArgsProviderTests {
TaskExecution taskExecution = new TaskExecution(); TaskExecution taskExecution = new TaskExecution();
taskExecution.setArguments(Arrays.asList("foo", "bar", "baz")); taskExecution.setArguments(Arrays.asList("foo", "bar", "baz"));
SimpleCommandLineArgsProvider provider = new SimpleCommandLineArgsProvider(taskExecution); SimpleCommandLineArgsProvider provider = new SimpleCommandLineArgsProvider(
taskExecution);
provider.setAppendedArgs(appendedValues); provider.setAppendedArgs(appendedValues);
List<String> commandLineArgs = provider.getCommandLineArgs(null); List<String> commandLineArgs = provider.getCommandLineArgs(null);
assertEquals("foo", commandLineArgs.get(0)); assertThat(commandLineArgs.get(0)).isEqualTo("foo");
assertEquals("bar", commandLineArgs.get(1)); assertThat(commandLineArgs.get(1)).isEqualTo("bar");
assertEquals("baz", commandLineArgs.get(2)); assertThat(commandLineArgs.get(2)).isEqualTo("baz");
assertEquals("one", commandLineArgs.get(3)); assertThat(commandLineArgs.get(3)).isEqualTo("one");
assertEquals("two", commandLineArgs.get(4)); assertThat(commandLineArgs.get(4)).isEqualTo("two");
assertEquals("three", commandLineArgs.get(5)); assertThat(commandLineArgs.get(5)).isEqualTo("three");
} }
@Test @Test
@@ -73,14 +76,16 @@ public class SimpleCommandLineArgsProviderTests {
TaskExecution taskExecution = new TaskExecution(); TaskExecution taskExecution = new TaskExecution();
taskExecution.setArguments(Arrays.asList("foo", "bar", "baz")); taskExecution.setArguments(Arrays.asList("foo", "bar", "baz"));
SimpleCommandLineArgsProvider provider = new SimpleCommandLineArgsProvider(taskExecution); SimpleCommandLineArgsProvider provider = new SimpleCommandLineArgsProvider(
taskExecution);
provider.setAppendedArgs(null); provider.setAppendedArgs(null);
List<String> commandLineArgs = provider.getCommandLineArgs(null); List<String> commandLineArgs = provider.getCommandLineArgs(null);
assertEquals(3, commandLineArgs.size()); assertThat(commandLineArgs.size()).isEqualTo(3);
assertEquals("foo", commandLineArgs.get(0)); assertThat(commandLineArgs.get(0)).isEqualTo("foo");
assertEquals("bar", commandLineArgs.get(1)); assertThat(commandLineArgs.get(1)).isEqualTo("bar");
assertEquals("baz", commandLineArgs.get(2)); assertThat(commandLineArgs.get(2)).isEqualTo("baz");
} }
} }

View File

@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -36,13 +36,14 @@ import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
/** /**
* Default implementation of the TaskConfigurer interface. If no {@link TaskConfigurer} * Default implementation of the TaskConfigurer interface. If no {@link TaskConfigurer}
* implementation is present, then this configuration will be used. * implementation is present, then this configuration will be used. The following defaults
* The following defaults will be used: * will be used:
* <ul> * <ul>
* <li>{@link SimpleTaskRepository} is the default {@link TaskRepository} returned. * <li>{@link SimpleTaskRepository} is the default {@link TaskRepository} returned. If a
* If a data source is present then a data will be stored in the database {@link JdbcTaskExecutionDao} else it will * data source is present then a data will be stored in the database
* be stored in a map {@link MapTaskExecutionDao}. * {@link JdbcTaskExecutionDao} else it will be stored in a map
* {@link MapTaskExecutionDao}.
* </ul> * </ul>
* *
* @author Glenn Renfro * @author Glenn Renfro
@@ -67,12 +68,11 @@ public class DefaultTaskConfigurer implements TaskConfigurer {
} }
/** /**
* Initializes the DefaultTaskConfigurer and sets the default table prefix * Initializes the DefaultTaskConfigurer and sets the default table prefix to
* to {@link TaskProperties#DEFAULT_TABLE_PREFIX}. * {@link TaskProperties#DEFAULT_TABLE_PREFIX}.
*
* @param dataSource references the {@link DataSource} to be used as the Task * @param dataSource references the {@link DataSource} to be used as the Task
* repository. If none is provided, a Map will be used (not recommended for * repository. If none is provided, a Map will be used (not recommended for production
* production use. * use.
*/ */
public DefaultTaskConfigurer(DataSource dataSource) { public DefaultTaskConfigurer(DataSource dataSource) {
this(dataSource, TaskProperties.DEFAULT_TABLE_PREFIX, null); this(dataSource, TaskProperties.DEFAULT_TABLE_PREFIX, null);
@@ -80,9 +80,8 @@ public class DefaultTaskConfigurer implements TaskConfigurer {
/** /**
* Initializes the DefaultTaskConfigurer. * Initializes the DefaultTaskConfigurer.
* * @param tablePrefix the prefix to apply to the task table names used by task
* @param tablePrefix the prefix to apply to the task table names used by * infrastructure.
* task infrastructure.
*/ */
public DefaultTaskConfigurer(String tablePrefix) { public DefaultTaskConfigurer(String tablePrefix) {
this(null, tablePrefix, null); this(null, tablePrefix, null);
@@ -90,23 +89,23 @@ public class DefaultTaskConfigurer implements TaskConfigurer {
/** /**
* Initializes the DefaultTaskConfigurer. * Initializes the DefaultTaskConfigurer.
*
* @param dataSource references the {@link DataSource} to be used as the Task * @param dataSource references the {@link DataSource} to be used as the Task
* repository. If none is provided, a Map will be used (not recommended for * repository. If none is provided, a Map will be used (not recommended for production
* production use. * use.
* @param tablePrefix the prefix to apply to the task table names used by * @param tablePrefix the prefix to apply to the task table names used by task
* task infrastructure. * infrastructure.
* @param context the context to be used. * @param context the context to be used.
*/ */
public DefaultTaskConfigurer(DataSource dataSource, String tablePrefix, ApplicationContext context) { public DefaultTaskConfigurer(DataSource dataSource, String tablePrefix,
ApplicationContext context) {
this.dataSource = dataSource; this.dataSource = dataSource;
this.context = context; this.context = context;
TaskExecutionDaoFactoryBean taskExecutionDaoFactoryBean; TaskExecutionDaoFactoryBean taskExecutionDaoFactoryBean;
if(this.dataSource != null) { if (this.dataSource != null) {
taskExecutionDaoFactoryBean = new taskExecutionDaoFactoryBean = new TaskExecutionDaoFactoryBean(this.dataSource,
TaskExecutionDaoFactoryBean(this.dataSource, tablePrefix); tablePrefix);
} }
else { else {
taskExecutionDaoFactoryBean = new TaskExecutionDaoFactoryBean(); taskExecutionDaoFactoryBean = new TaskExecutionDaoFactoryBean();
@@ -137,22 +136,27 @@ public class DefaultTaskConfigurer implements TaskConfigurer {
if (isDataSourceAvailable()) { if (isDataSourceAvailable()) {
try { try {
Class.forName("javax.persistence.EntityManager"); Class.forName("javax.persistence.EntityManager");
if (this.context != null && this.context.getBeanNamesForType(EntityManager.class).length > 0) { if (this.context != null && this.context
logger.debug("EntityManager was found, using JpaTransactionManager"); .getBeanNamesForType(EntityManager.class).length > 0) {
logger.debug(
"EntityManager was found, using JpaTransactionManager");
this.transactionManager = new JpaTransactionManager(); this.transactionManager = new JpaTransactionManager();
} }
} }
catch (ClassNotFoundException ignore) { catch (ClassNotFoundException ignore) {
logger.debug("No EntityManager was found, using DataSourceTransactionManager"); logger.debug(
"No EntityManager was found, using DataSourceTransactionManager");
} }
finally { finally {
if (this.transactionManager == null) { if (this.transactionManager == null) {
this.transactionManager = new DataSourceTransactionManager(this.dataSource); this.transactionManager = new DataSourceTransactionManager(
this.dataSource);
} }
} }
} }
else { else {
logger.debug("No DataSource was found, using ResourcelessTransactionManager"); logger.debug(
"No DataSource was found, using ResourcelessTransactionManager");
this.transactionManager = new ResourcelessTransactionManager(); this.transactionManager = new ResourcelessTransactionManager();
} }
} }
@@ -163,4 +167,5 @@ public class DefaultTaskConfigurer implements TaskConfigurer {
private boolean isDataSourceAvailable() { private boolean isDataSourceAvailable() {
return this.dataSource != null; return this.dataSource != null;
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -23,13 +23,12 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import org.springframework.cloud.task.repository.TaskRepository;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
/** /**
* <p> * <p>
* Enables the {@link org.springframework.cloud.task.listener.TaskLifecycleListener} * Enables the {@link org.springframework.cloud.task.listener.TaskLifecycleListener} so
* so that the features of Spring Cloud Task will be applied. * that the features of Spring Cloud Task will be applied.
* *
* <pre class="code"> * <pre class="code">
* &#064;Configuration * &#064;Configuration
@@ -39,13 +38,14 @@ import org.springframework.context.annotation.Import;
* &#064;Bean * &#064;Bean
* public MyCommandLineRunner myCommandLineRunner() { * public MyCommandLineRunner myCommandLineRunner() {
* return new MyCommandLineRunner() * return new MyCommandLineRunner()
* } * }
* } * }
* </pre> * </pre>
* *
* Note that only one of your configuration classes needs to have the <code>&#064;EnableTask</code> * Note that only one of your configuration classes needs to have the
* annotation. Once you have an <code>&#064;EnableTask</code> class in your configuration * <code>&#064;EnableTask</code> annotation. Once you have an
* the task will have the Spring Cloud Task features available. * <code>&#064;EnableTask</code> class in your configuration the task will have the Spring
* Cloud Task features available.
* *
* @author Glenn Renfro * @author Glenn Renfro
* *
@@ -56,4 +56,5 @@ import org.springframework.context.annotation.Import;
@Inherited @Inherited
@Import(TaskLifecycleConfiguration.class) @Import(TaskLifecycleConfiguration.class)
public @interface EnableTask { public @interface EnableTask {
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -54,10 +54,13 @@ import org.springframework.util.CollectionUtils;
@Configuration @Configuration
@EnableTransactionManagement @EnableTransactionManagement
@EnableConfigurationProperties(TaskProperties.class) @EnableConfigurationProperties(TaskProperties.class)
// @checkstyle:off
@ConditionalOnProperty(prefix = "spring.cloud.task.autoconfiguration", name = "enabled", havingValue = "true", matchIfMissing = true) @ConditionalOnProperty(prefix = "spring.cloud.task.autoconfiguration", name = "enabled", havingValue = "true", matchIfMissing = true)
// @checkstyle:on
public class SimpleTaskAutoConfiguration { public class SimpleTaskAutoConfiguration {
protected static final Log logger = LogFactory.getLog(SimpleTaskAutoConfiguration.class); protected static final Log logger = LogFactory
.getLog(SimpleTaskAutoConfiguration.class);
@Autowired(required = false) @Autowired(required = false)
private Collection<DataSource> dataSources; private Collection<DataSource> dataSources;
@@ -80,7 +83,7 @@ public class SimpleTaskAutoConfiguration {
private TaskExplorer taskExplorer; private TaskExplorer taskExplorer;
@Bean @Bean
public TaskRepository taskRepository(){ public TaskRepository taskRepository() {
return this.taskRepository; return this.taskRepository;
} }
@@ -104,7 +107,7 @@ public class SimpleTaskAutoConfiguration {
public TaskRepositoryInitializer taskRepositoryInitializer() { public TaskRepositoryInitializer taskRepositoryInitializer() {
TaskRepositoryInitializer taskRepositoryInitializer = new TaskRepositoryInitializer(); TaskRepositoryInitializer taskRepositoryInitializer = new TaskRepositoryInitializer();
DataSource initializerDataSource = getDefaultConfigurer().getTaskDataSource(); DataSource initializerDataSource = getDefaultConfigurer().getTaskDataSource();
if(initializerDataSource != null) { if (initializerDataSource != null) {
taskRepositoryInitializer.setDataSource(initializerDataSource); taskRepositoryInitializer.setDataSource(initializerDataSource);
} }
@@ -116,7 +119,7 @@ public class SimpleTaskAutoConfiguration {
*/ */
@PostConstruct @PostConstruct
protected void initialize() { protected void initialize() {
if (initialized) { if (this.initialized) {
return; return;
} }
@@ -128,7 +131,7 @@ public class SimpleTaskAutoConfiguration {
this.taskRepository = taskConfigurer.getTaskRepository(); this.taskRepository = taskConfigurer.getTaskRepository();
this.platformTransactionManager = taskConfigurer.getTransactionManager(); this.platformTransactionManager = taskConfigurer.getTransactionManager();
this.taskExplorer = taskConfigurer.getTaskExplorer(); this.taskExplorer = taskConfigurer.getTaskExplorer();
initialized = true; this.initialized = true;
} }
private TaskConfigurer getDefaultConfigurer() { private TaskConfigurer getDefaultConfigurer() {
@@ -138,36 +141,44 @@ public class SimpleTaskAutoConfiguration {
if (configurers < 1) { if (configurers < 1) {
TaskConfigurer taskConfigurer; TaskConfigurer taskConfigurer;
if(!CollectionUtils.isEmpty(this.dataSources) && this.dataSources.size() == 1) { if (!CollectionUtils.isEmpty(this.dataSources)
&& this.dataSources.size() == 1) {
taskConfigurer = new DefaultTaskConfigurer( taskConfigurer = new DefaultTaskConfigurer(
this.dataSources.iterator().next(), this.dataSources.iterator().next(),
taskProperties.getTablePrefix(), context); this.taskProperties.getTablePrefix(), this.context);
} }
else { else {
taskConfigurer = new DefaultTaskConfigurer(taskProperties.getTablePrefix()); taskConfigurer = new DefaultTaskConfigurer(
this.taskProperties.getTablePrefix());
} }
this.context.getBeanFactory().registerSingleton("taskConfigurer", taskConfigurer); this.context.getBeanFactory().registerSingleton("taskConfigurer",
taskConfigurer);
return taskConfigurer; return taskConfigurer;
} }
else { else {
if(configurers == 1) { if (configurers == 1) {
return this.context.getBean(TaskConfigurer.class); return this.context.getBean(TaskConfigurer.class);
} }
else { else {
throw new IllegalStateException("Expected one TaskConfigurer but found " + configurers); throw new IllegalStateException(
"Expected one TaskConfigurer but found " + configurers);
} }
} }
} }
private void verifyEnvironment() { private void verifyEnvironment() {
int configurers = this.context.getBeanNamesForType(TaskConfigurer.class).length; int configurers = this.context.getBeanNamesForType(TaskConfigurer.class).length;
// retrieve the count of dataSources (without instantiating them) excluding DataSource proxy beans // retrieve the count of dataSources (without instantiating them) excluding
long dataSources = Arrays.stream(this.context.getBeanNamesForType(DataSource.class)) // DataSource proxy beans
long dataSources = Arrays
.stream(this.context.getBeanNamesForType(DataSource.class))
.filter((name -> !ScopedProxyUtils.isScopedTarget(name))).count(); .filter((name -> !ScopedProxyUtils.isScopedTarget(name))).count();
if(configurers == 0 && dataSources > 1) { if (configurers == 0 && dataSources > 1) {
throw new IllegalStateException("To use the default TaskConfigurer the context must contain no more than" + throw new IllegalStateException(
" one DataSource, found " + dataSources); "To use the default TaskConfigurer the context must contain no more than"
+ " one DataSource, found " + dataSources);
} }
} }
} }

View File

@@ -1,17 +1,17 @@
/* /*
* Copyright 2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.configuration; package org.springframework.cloud.task.configuration;
@@ -39,10 +39,10 @@ import org.springframework.integration.support.leader.LockRegistryLeaderInitiato
import org.springframework.integration.support.locks.LockRegistry; import org.springframework.integration.support.locks.LockRegistry;
/** /**
* When spring.cloud.task.single-instance-enabled is set to true this listener will create a lock for the task * When spring.cloud.task.single-instance-enabled is set to true this listener will create
* based on the spring.cloud.task.name. If a lock already exists this Listener will throw * a lock for the task based on the spring.cloud.task.name. If a lock already exists this
* a TaskExecutionException. If this listener is added manually, then it should * Listener will throw a TaskExecutionException. If this listener is added manually, then
* be added as the first listener in the chain. * it should be added as the first listener in the chain.
* *
* @author Glenn Renfro * @author Glenn Renfro
* @since 2.0.0 * @since 2.0.0
@@ -68,19 +68,18 @@ public class SingleInstanceTaskListener implements ApplicationListener<Applicati
private TaskProperties taskProperties; private TaskProperties taskProperties;
public SingleInstanceTaskListener(LockRegistry lockRegistry, public SingleInstanceTaskListener(LockRegistry lockRegistry,
TaskNameResolver taskNameResolver, TaskNameResolver taskNameResolver, TaskProperties taskProperties,
TaskProperties taskProperties,
ApplicationEventPublisher applicationEventPublisher) { ApplicationEventPublisher applicationEventPublisher) {
this.lockRegistry = lockRegistry; this.lockRegistry = lockRegistry;
this.taskNameResolver = taskNameResolver; this.taskNameResolver = taskNameResolver;
this.taskProperties = taskProperties; this.taskProperties = taskProperties;
this.lockRegistryLeaderInitiator = new LockRegistryLeaderInitiator(this.lockRegistry); this.lockRegistryLeaderInitiator = new LockRegistryLeaderInitiator(
this.lockRegistry);
this.applicationEventPublisher = applicationEventPublisher; this.applicationEventPublisher = applicationEventPublisher;
} }
public SingleInstanceTaskListener(DataSource dataSource, public SingleInstanceTaskListener(DataSource dataSource,
TaskNameResolver taskNameResolver, TaskNameResolver taskNameResolver, TaskProperties taskProperties,
TaskProperties taskProperties,
ApplicationEventPublisher applicationEventPublisher) { ApplicationEventPublisher applicationEventPublisher) {
this.taskNameResolver = taskNameResolver; this.taskNameResolver = taskNameResolver;
this.applicationEventPublisher = applicationEventPublisher; this.applicationEventPublisher = applicationEventPublisher;
@@ -90,14 +89,15 @@ public class SingleInstanceTaskListener implements ApplicationListener<Applicati
@BeforeTask @BeforeTask
public void lockTask(TaskExecution taskExecution) { public void lockTask(TaskExecution taskExecution) {
if(this.lockRegistry == null ) { if (this.lockRegistry == null) {
this.lockRegistry = getDefaultLockRegistry(taskExecution.getExecutionId()); this.lockRegistry = getDefaultLockRegistry(taskExecution.getExecutionId());
} }
this.lockRegistryLeaderInitiator = new LockRegistryLeaderInitiator( this.lockRegistryLeaderInitiator = new LockRegistryLeaderInitiator(
this.lockRegistry, this.lockRegistry,
new DefaultCandidate(String.valueOf(taskExecution.getExecutionId()), new DefaultCandidate(String.valueOf(taskExecution.getExecutionId()),
taskNameResolver.getTaskName())); this.taskNameResolver.getTaskName()));
this.lockRegistryLeaderInitiator.setApplicationEventPublisher(this.applicationEventPublisher); this.lockRegistryLeaderInitiator
.setApplicationEventPublisher(this.applicationEventPublisher);
this.lockRegistryLeaderInitiator.setPublishFailedEvents(true); this.lockRegistryLeaderInitiator.setPublishFailedEvents(true);
this.lockRegistryLeaderInitiator.start(); this.lockRegistryLeaderInitiator.start();
while (!this.lockReady) { while (!this.lockReady) {
@@ -115,7 +115,8 @@ public class SingleInstanceTaskListener implements ApplicationListener<Applicati
this.lockRegistryLeaderInitiator.destroy(); this.lockRegistryLeaderInitiator.destroy();
} }
catch (Exception exception) { catch (Exception exception) {
throw new TaskExecutionException("Failed to destroy lock.", exception); throw new TaskExecutionException("Failed to destroy lock.",
exception);
} }
throw new TaskExecutionException(errorMessage); throw new TaskExecutionException(errorMessage);
} }
@@ -128,7 +129,8 @@ public class SingleInstanceTaskListener implements ApplicationListener<Applicati
} }
@FailedTask @FailedTask
public void unlockTaskOnError(TaskExecution taskExecution, Throwable throwable) throws Exception { public void unlockTaskOnError(TaskExecution taskExecution, Throwable throwable)
throws Exception {
this.lockRegistryLeaderInitiator.destroy(); this.lockRegistryLeaderInitiator.destroy();
} }
@@ -142,13 +144,13 @@ public class SingleInstanceTaskListener implements ApplicationListener<Applicati
} }
} }
private LockRegistry getDefaultLockRegistry( long executionId) { private LockRegistry getDefaultLockRegistry(long executionId) {
DefaultLockRepository lockRepository = DefaultLockRepository lockRepository = new DefaultLockRepository(this.dataSource,
new DefaultLockRepository(this.dataSource, String.valueOf( String.valueOf(executionId));
executionId));
lockRepository.setPrefix(this.taskProperties.getTablePrefix()); lockRepository.setPrefix(this.taskProperties.getTablePrefix());
lockRepository.setTimeToLive(this.taskProperties.getSingleInstanceLockTtl()); lockRepository.setTimeToLive(this.taskProperties.getSingleInstanceLockTtl());
lockRepository.afterPropertiesSet(); lockRepository.afterPropertiesSet();
return new JdbcLockRegistry(lockRepository); return new JdbcLockRegistry(lockRepository);
} }
} }

View File

@@ -1,17 +1,17 @@
/* /*
* Copyright 2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.configuration; package org.springframework.cloud.task.configuration;
@@ -47,17 +47,15 @@ public class SingleTaskConfiguration {
@Autowired @Autowired
private TaskConfigurer taskConfigurer; private TaskConfigurer taskConfigurer;
@Bean @Bean
public SingleInstanceTaskListener taskListener(TaskNameResolver resolver) { public SingleInstanceTaskListener taskListener(TaskNameResolver resolver) {
if (taskConfigurer.getTaskDataSource() == null) { if (this.taskConfigurer.getTaskDataSource() == null) {
return new SingleInstanceTaskListener(new PassThruLockRegistry(), return new SingleInstanceTaskListener(new PassThruLockRegistry(), resolver,
resolver, this.taskProperties, this.applicationEventPublisher); this.taskProperties, this.applicationEventPublisher);
} }
return new SingleInstanceTaskListener(taskConfigurer.getTaskDataSource(), return new SingleInstanceTaskListener(this.taskConfigurer.getTaskDataSource(),
resolver, resolver, this.taskProperties, this.applicationEventPublisher);
this.taskProperties,
this.applicationEventPublisher);
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -23,10 +23,9 @@ import org.springframework.cloud.task.repository.TaskRepository;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
/** /**
* Provides a strategy interface for providing configuration * Provides a strategy interface for providing configuration customization to the task
* customization to the task system. Users should not directly use getter methods * system. Users should not directly use getter methods from a <code>TaskConfigurer</code>
* from a <code>TaskConfigurer</code> directly unless they are using it to supply the implementations * directly unless they are using it to supply the implementations for Spring Beans.
* for Spring Beans.
* *
* @author Glenn Renfro * @author Glenn Renfro
*/ */
@@ -34,7 +33,6 @@ public interface TaskConfigurer {
/** /**
* Create a {@link TaskRepository} for the Task. * Create a {@link TaskRepository} for the Task.
*
* @return A TaskRepository * @return A TaskRepository
*/ */
TaskRepository getTaskRepository(); TaskRepository getTaskRepository();
@@ -42,23 +40,22 @@ public interface TaskConfigurer {
/** /**
* Create a {@link PlatformTransactionManager} for use with the * Create a {@link PlatformTransactionManager} for use with the
* <code>TaskRepository</code>. * <code>TaskRepository</code>.
*
* @return A <code>PlatformTransactionManager</code> * @return A <code>PlatformTransactionManager</code>
*/ */
PlatformTransactionManager getTransactionManager(); PlatformTransactionManager getTransactionManager();
/** /**
* Create a {@link TaskExplorer} for the task. * Create a {@link TaskExplorer} for the task.
*
* @return a <code>TaskExplorer</code> * @return a <code>TaskExplorer</code>
*/ */
TaskExplorer getTaskExplorer(); TaskExplorer getTaskExplorer();
/** /**
* Retrieves the {@link DataSource} that will be used for task operations. If a * Retrieves the {@link DataSource} that will be used for task operations. If a
* DataSource is not being used for the implemented TaskConfigurer this * DataSource is not being used for the implemented TaskConfigurer this method will
* method will return null. * return null.
* @return {@link DataSource} that will be used for task operations. * @return {@link DataSource} that will be used for task operations.
*/ */
DataSource getTaskDataSource(); DataSource getTaskDataSource();
} }

View File

@@ -1,17 +1,17 @@
/* /*
* Copyright 2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.configuration; package org.springframework.cloud.task.configuration;
@@ -43,7 +43,8 @@ import org.springframework.context.annotation.Configuration;
@Configuration @Configuration
public class TaskLifecycleConfiguration { public class TaskLifecycleConfiguration {
protected static final Log logger = LogFactory.getLog(TaskLifecycleConfiguration.class); protected static final Log logger = LogFactory
.getLog(TaskLifecycleConfiguration.class);
private TaskProperties taskProperties; private TaskProperties taskProperties;
@@ -63,10 +64,8 @@ public class TaskLifecycleConfiguration {
@Autowired @Autowired
public TaskLifecycleConfiguration(TaskProperties taskProperties, public TaskLifecycleConfiguration(TaskProperties taskProperties,
ConfigurableApplicationContext context, ConfigurableApplicationContext context, TaskRepository taskRepository,
TaskRepository taskRepository, TaskExplorer taskExplorer, TaskNameResolver taskNameResolver,
TaskExplorer taskExplorer,
TaskNameResolver taskNameResolver,
ObjectProvider<ApplicationArguments> applicationArguments) { ObjectProvider<ApplicationArguments> applicationArguments) {
this.taskProperties = taskProperties; this.taskProperties = taskProperties;
@@ -88,15 +87,13 @@ public class TaskLifecycleConfiguration {
@PostConstruct @PostConstruct
protected void initialize() { protected void initialize() {
if (!this.initialized) { if (!this.initialized) {
this.taskLifecycleListener = this.taskLifecycleListener = new TaskLifecycleListener(this.taskRepository,
new TaskLifecycleListener(this.taskRepository, this.taskNameResolver, this.applicationArguments, this.taskExplorer,
this.taskNameResolver, this.taskProperties,
this.applicationArguments, new TaskListenerExecutorObjectFactory(this.context));
this.taskExplorer,
this.taskProperties,
new TaskListenerExecutorObjectFactory(context));
this.initialized = true; this.initialized = true;
} }
} }
} }

View File

@@ -1,22 +1,21 @@
/* /*
* Copyright 2016-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.configuration; package org.springframework.cloud.task.configuration;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@@ -32,11 +31,14 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "spring.cloud.task") @ConfigurationProperties(prefix = "spring.cloud.task")
public class TaskProperties { public class TaskProperties {
/**
* Default table prefix for Spring Cloud Task.
*/
public static final String DEFAULT_TABLE_PREFIX = "TASK_";
private static final int DEFAULT_CHECK_INTERVAL = 500; private static final int DEFAULT_CHECK_INTERVAL = 500;
private static final Log logger = LogFactory.getLog(TaskProperties.class); private static final Log logger = LogFactory.getLog(TaskProperties.class);
public static final String DEFAULT_TABLE_PREFIX = "TASK_";
/** /**
* An id that can be associated with a task. * An id that can be associated with a task.
@@ -49,8 +51,8 @@ public class TaskProperties {
private Long executionid; private Long executionid;
/** /**
* The id of the parent task execution id that launched this task execution. * The id of the parent task execution id that launched this task execution. Defaults
* Defaults to null if task execution had no parent. * to null if task execution had no parent.
*/ */
private Long parentExecutionId; private Long parentExecutionId;
@@ -60,35 +62,34 @@ public class TaskProperties {
private String tablePrefix = DEFAULT_TABLE_PREFIX; private String tablePrefix = DEFAULT_TABLE_PREFIX;
/** /**
* When set to true the context is closed at the end of the task. Else * When set to true the context is closed at the end of the task. Else the context
* the context remains open. * remains open.
*/ */
private Boolean closecontextEnabled = false; private Boolean closecontextEnabled = false;
/** /**
* When set to true it * When set to true it will check to see if a task execution with the same task name
* will check to see if a task execution with the same task name is already * is already running. If a task is still running then it will throw a
* running. If a task is still running then it will throw a * {@link org.springframework.cloud.task.listener.TaskExecutionException}. When task
* {@link org.springframework.cloud.task.listener.TaskExecutionException}. * execution ends the lock is released.
* When task execution ends the lock is released.
*/ */
private boolean singleInstanceEnabled = false; private boolean singleInstanceEnabled = false;
/** /**
* Declares the maximum amount of time (in millis) that a task execution can * Declares the maximum amount of time (in millis) that a task execution can hold a
* hold a lock to prevent another task from executing with a specific task * lock to prevent another task from executing with a specific task name when the
* name when the single-instance-enabled is set to true. Default time is: Integer.MAX_VALUE. * single-instance-enabled is set to true. Default time is: Integer.MAX_VALUE.
*/ */
private int singleInstanceLockTtl = Integer.MAX_VALUE; private int singleInstanceLockTtl = Integer.MAX_VALUE;
/** /**
* Declares the time (in millis) that a task execution will wait between * Declares the time (in millis) that a task execution will wait between checks.
* checks. Default time is: 500 millis. * Default time is: 500 millis.
*/ */
private int singleInstanceLockCheckInterval = DEFAULT_CHECK_INTERVAL; private int singleInstanceLockCheckInterval = DEFAULT_CHECK_INTERVAL;
public String getExternalExecutionId() { public String getExternalExecutionId() {
return externalExecutionId; return this.externalExecutionId;
} }
public void setExternalExecutionId(String externalExecutionId) { public void setExternalExecutionId(String externalExecutionId) {
@@ -96,7 +97,7 @@ public class TaskProperties {
} }
public Long getExecutionid() { public Long getExecutionid() {
return executionid; return this.executionid;
} }
public void setExecutionid(Long executionid) { public void setExecutionid(Long executionid) {
@@ -104,7 +105,7 @@ public class TaskProperties {
} }
public Boolean getClosecontextEnabled() { public Boolean getClosecontextEnabled() {
return closecontextEnabled; return this.closecontextEnabled;
} }
public void setClosecontextEnabled(Boolean closecontextEnabled) { public void setClosecontextEnabled(Boolean closecontextEnabled) {
@@ -112,7 +113,7 @@ public class TaskProperties {
} }
public String getTablePrefix() { public String getTablePrefix() {
return tablePrefix; return this.tablePrefix;
} }
public void setTablePrefix(String tablePrefix) { public void setTablePrefix(String tablePrefix) {
@@ -120,7 +121,7 @@ public class TaskProperties {
} }
public Long getParentExecutionId() { public Long getParentExecutionId() {
return parentExecutionId; return this.parentExecutionId;
} }
public void setParentExecutionId(Long parentExecutionId) { public void setParentExecutionId(Long parentExecutionId) {
@@ -128,7 +129,7 @@ public class TaskProperties {
} }
public boolean getSingleInstanceEnabled() { public boolean getSingleInstanceEnabled() {
return singleInstanceEnabled; return this.singleInstanceEnabled;
} }
public void setSingleInstanceEnabled(boolean singleInstanceEnabled) { public void setSingleInstanceEnabled(boolean singleInstanceEnabled) {
@@ -136,7 +137,7 @@ public class TaskProperties {
} }
public int getSingleInstanceLockTtl() { public int getSingleInstanceLockTtl() {
return singleInstanceLockTtl; return this.singleInstanceLockTtl;
} }
public void setSingleInstanceLockTtl(int singleInstanceLockTtl) { public void setSingleInstanceLockTtl(int singleInstanceLockTtl) {
@@ -144,10 +145,11 @@ public class TaskProperties {
} }
public int getSingleInstanceLockCheckInterval() { public int getSingleInstanceLockCheckInterval() {
return singleInstanceLockCheckInterval; return this.singleInstanceLockCheckInterval;
} }
public void setSingleInstanceLockCheckInterval(int singleInstanceLockCheckInterval) { public void setSingleInstanceLockCheckInterval(int singleInstanceLockCheckInterval) {
this.singleInstanceLockCheckInterval = singleInstanceLockCheckInterval; this.singleInstanceLockCheckInterval = singleInstanceLockCheckInterval;
} }
} }

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2015-2019 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.
*/
/** /**
* Interfaces for configuring Spring Cloud Task and a default implementations. * Interfaces for configuring Spring Cloud Task and a default implementations.
*/ */

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -18,15 +18,16 @@ package org.springframework.cloud.task.listener;
/** /**
* Base Exception for any Task issues. * Base Exception for any Task issues.
*
* @author Glenn Renfro * @author Glenn Renfro
*/ */
public class TaskException extends RuntimeException { public class TaskException extends RuntimeException {
public TaskException(String message, Throwable e){ public TaskException(String message, Throwable e) {
super(message, e); super(message, e);
} }
public TaskException(String message){ public TaskException(String message) {
super(message); super(message);
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -23,11 +23,12 @@ package org.springframework.cloud.task.listener;
*/ */
public class TaskExecutionException extends TaskException { public class TaskExecutionException extends TaskException {
public TaskExecutionException(String message){ public TaskExecutionException(String message) {
super(message); super(message);
} }
public TaskExecutionException(String message, Throwable throwable){ public TaskExecutionException(String message, Throwable throwable) {
super(message, throwable); super(message, throwable);
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -21,29 +21,32 @@ import org.springframework.cloud.task.repository.TaskRepository;
/** /**
* The listener interface for receiving task execution events. * The listener interface for receiving task execution events.
*
* @author Glenn Renfro * @author Glenn Renfro
*/ */
public interface TaskExecutionListener { public interface TaskExecutionListener {
/** /**
* Invoked after the {@link TaskExecution} has been stored in the {@link TaskRepository}. * Invoked after the {@link TaskExecution} has been stored in the
* {@link TaskRepository}.
* @param taskExecution instance containing the information about the current task. * @param taskExecution instance containing the information about the current task.
*/ */
void onTaskStartup(TaskExecution taskExecution); void onTaskStartup(TaskExecution taskExecution);
/** /**
* Invoked before the {@link TaskExecution} has been updated in the {@link TaskRepository} * Invoked before the {@link TaskExecution} has been updated in the
* upon task end. * {@link TaskRepository} upon task end.
* @param taskExecution instance containing the information about the current task. * @param taskExecution instance containing the information about the current task.
*/ */
void onTaskEnd(TaskExecution taskExecution); void onTaskEnd(TaskExecution taskExecution);
/** /**
* Invoked if an uncaught exception occurs during a task execution. This invocation * Invoked if an uncaught exception occurs during a task execution. This invocation
* will occur before the {@link TaskExecution} has been updated in the {@link TaskRepository} * will occur before the {@link TaskExecution} has been updated in the
* and before the onTaskEnd is called. * {@link TaskRepository} and before the onTaskEnd is called.
* @param taskExecution instance containing the information about the current task. * @param taskExecution instance containing the information about the current task.
* @param throwable the uncaught exception that was thrown during task execution. * @param throwable the uncaught exception that was thrown during task execution.
*/ */
void onTaskFailed(TaskExecution taskExecution, Throwable throwable); void onTaskFailed(TaskExecution taskExecution, Throwable throwable);
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2017 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.listener; package org.springframework.cloud.task.listener;
import org.springframework.cloud.task.repository.TaskExecution; import org.springframework.cloud.task.repository.TaskExecution;
@@ -25,6 +26,7 @@ import org.springframework.cloud.task.repository.TaskExecution;
* @since 1.2 * @since 1.2
*/ */
public class TaskExecutionListenerSupport implements TaskExecutionListener { public class TaskExecutionListenerSupport implements TaskExecutionListener {
@Override @Override
public void onTaskStartup(TaskExecution taskExecution) { public void onTaskStartup(TaskExecution taskExecution) {
@@ -39,4 +41,5 @@ public class TaskExecutionListenerSupport implements TaskExecutionListener {
public void onTaskFailed(TaskExecution taskExecution, Throwable throwable) { public void onTaskFailed(TaskExecution taskExecution, Throwable throwable) {
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.listener; package org.springframework.cloud.task.listener;
import java.io.PrintWriter; import java.io.PrintWriter;
@@ -49,33 +50,42 @@ import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
* Monitors the lifecycle of a task. This listener will record both the start and end of * Monitors the lifecycle of a task. This listener will record both the start and end of a
* a task in the registered {@link TaskRepository}. * task in the registered {@link TaskRepository}.
* *
* The following events are used to identify the start and end of a task: * The following events are used to identify the start and end of a task:
* *
* <ul> * <ul>
* <li>{@link SmartLifecycle#start()} - Used to identify the start of a task. A task * <li>{@link SmartLifecycle#start()} - Used to identify the start of a task. A task is
* is expected to contain a single application context.</li> * expected to contain a single application context.</li>
* <li>{@link ApplicationReadyEvent} - Used to identify the successful end of a task.</li> * <li>{@link ApplicationReadyEvent} - Used to identify the successful end of a task.</li>
* <li>{@link ApplicationFailedEvent} - Used to identify the failure of a task.</li> * <li>{@link ApplicationFailedEvent} - Used to identify the failure of a task.</li>
* <li>{@link SmartLifecycle#stop()} - Used to identify the end of a task, * <li>{@link SmartLifecycle#stop()} - Used to identify the end of a task, if the
* if the {@link ApplicationReadyEvent} or {@link ApplicationFailedEvent} * {@link ApplicationReadyEvent} or {@link ApplicationFailedEvent} is not emitted. This
* is not emitted. This can occur if an error occurs while executing a BeforeTask. * can occur if an error occurs while executing a BeforeTask.</li>
* </li>
* </ul> * </ul>
* *
* <b>Note:</b> By default, the context will close at the completion of the task unless other non-daemon * <b>Note:</b> By default, the context will close at the completion of the task unless
* threads keep it running. Programatic closing of the context can be configured via the * other non-daemon threads keep it running. Programatic closing of the context can be
* property <code>spring.cloud.task.closecontext.enabled</code> (defaults to false). * configured via the property <code>spring.cloud.task.closecontext.enabled</code>
* If the <code>spring.cloud.task.closecontext.enabled</code> is set to true, * (defaults to false). If the <code>spring.cloud.task.closecontext.enabled</code> is set
* then the context will be closed upon task completion regardless if non-daemon threads are still running. * to true, then the context will be closed upon task completion regardless if non-daemon
* Also if the context did not start, the FailedTask and TaskEnd may not have all the dependencies met. * threads are still running. Also if the context did not start, the FailedTask and
* TaskEnd may not have all the dependencies met.
* *
* @author Michael Minella * @author Michael Minella
* @author Glenn Renfro * @author Glenn Renfro
*/ */
public class TaskLifecycleListener implements ApplicationListener<ApplicationEvent>, SmartLifecycle, DisposableBean { public class TaskLifecycleListener
implements ApplicationListener<ApplicationEvent>, SmartLifecycle, DisposableBean {
private static final Log logger = LogFactory.getLog(TaskLifecycleListener.class);
private final TaskRepository taskRepository;
private final TaskExplorer taskExplorer;
private final TaskListenerExecutorObjectFactory taskListenerExecutorObjectFactory;
@Autowired @Autowired
private ConfigurableApplicationContext context; private ConfigurableApplicationContext context;
@@ -85,14 +95,6 @@ public class TaskLifecycleListener implements ApplicationListener<ApplicationEve
private List<TaskExecutionListener> taskExecutionListeners; private List<TaskExecutionListener> taskExecutionListeners;
private static final Log logger = LogFactory.getLog(TaskLifecycleListener.class);
private final TaskRepository taskRepository;
private final TaskExplorer taskExplorer;
private final TaskListenerExecutorObjectFactory taskListenerExecutorObjectFactory;
private TaskExecution taskExecution; private TaskExecution taskExecution;
private TaskProperties taskProperties; private TaskProperties taskProperties;
@@ -115,22 +117,25 @@ public class TaskLifecycleListener implements ApplicationListener<ApplicationEve
/** /**
* @param taskRepository {@link TaskRepository} to record executions. * @param taskRepository {@link TaskRepository} to record executions.
* @param taskNameResolver {@link TaskNameResolver} used to determine task name for task execution. * @param taskNameResolver {@link TaskNameResolver} used to determine task name for
* @param applicationArguments {@link ApplicationArguments} to be used for task execution. * task execution.
* @param applicationArguments {@link ApplicationArguments} to be used for task
* execution.
* @param taskExplorer {@link TaskExplorer} to be used for task execution. * @param taskExplorer {@link TaskExplorer} to be used for task execution.
* @param taskProperties {@link TaskProperties} to be used for the task execution. * @param taskProperties {@link TaskProperties} to be used for the task execution.
* @param taskListenerExecutorObjectFactory {@link TaskListenerExecutorObjectFactory} to initialize TaskListenerExecutor for a task * @param taskListenerExecutorObjectFactory {@link TaskListenerExecutorObjectFactory}
* to initialize TaskListenerExecutor for a task
*/ */
public TaskLifecycleListener(TaskRepository taskRepository, public TaskLifecycleListener(TaskRepository taskRepository,
TaskNameResolver taskNameResolver, TaskNameResolver taskNameResolver, ApplicationArguments applicationArguments,
ApplicationArguments applicationArguments, TaskExplorer taskExplorer, TaskExplorer taskExplorer, TaskProperties taskProperties,
TaskProperties taskProperties,
TaskListenerExecutorObjectFactory taskListenerExecutorObjectFactory) { TaskListenerExecutorObjectFactory taskListenerExecutorObjectFactory) {
Assert.notNull(taskRepository, "A taskRepository is required"); Assert.notNull(taskRepository, "A taskRepository is required");
Assert.notNull(taskNameResolver, "A taskNameResolver is required"); Assert.notNull(taskNameResolver, "A taskNameResolver is required");
Assert.notNull(taskExplorer, "A taskExplorer is required"); Assert.notNull(taskExplorer, "A taskExplorer is required");
Assert.notNull(taskProperties, "TaskProperties is required"); Assert.notNull(taskProperties, "TaskProperties is required");
Assert.notNull(taskListenerExecutorObjectFactory, "A TaskListenerExecutorObjectFactory is required"); Assert.notNull(taskListenerExecutorObjectFactory,
"A TaskListenerExecutorObjectFactory is required");
this.taskRepository = taskRepository; this.taskRepository = taskRepository;
this.taskNameResolver = taskNameResolver; this.taskNameResolver = taskNameResolver;
@@ -141,25 +146,25 @@ public class TaskLifecycleListener implements ApplicationListener<ApplicationEve
} }
/** /**
* Utilizes {@link ApplicationEvent}s to determine the end and failure of a * Utilizes {@link ApplicationEvent}s to determine the end and failure of a task.
* task. Specifically: * Specifically:
* <ul> * <ul>
* <li>{@link ApplicationReadyEvent} - Successful end of a task</li> * <li>{@link ApplicationReadyEvent} - Successful end of a task</li>
* <li>{@link ApplicationFailedEvent} - Failure of a task</li> * <li>{@link ApplicationFailedEvent} - Failure of a task</li>
* </ul> * </ul>
*
* @param applicationEvent The application being listened for. * @param applicationEvent The application being listened for.
*/ */
@Override @Override
public void onApplicationEvent(ApplicationEvent applicationEvent) { public void onApplicationEvent(ApplicationEvent applicationEvent) {
if(applicationEvent instanceof ApplicationFailedEvent) { if (applicationEvent instanceof ApplicationFailedEvent) {
this.applicationFailedException = ((ApplicationFailedEvent) applicationEvent).getException(); this.applicationFailedException = ((ApplicationFailedEvent) applicationEvent)
.getException();
doTaskEnd(); doTaskEnd();
} }
else if(applicationEvent instanceof ExitCodeEvent){ else if (applicationEvent instanceof ExitCodeEvent) {
this.exitCodeEvent = (ExitCodeEvent) applicationEvent; this.exitCodeEvent = (ExitCodeEvent) applicationEvent;
} }
else if(applicationEvent instanceof ApplicationReadyEvent) { else if (applicationEvent instanceof ApplicationReadyEvent) {
doTaskEnd(); doTaskEnd();
} }
} }
@@ -174,37 +179,41 @@ public class TaskLifecycleListener implements ApplicationListener<ApplicationEve
} }
private void doTaskEnd() { private void doTaskEnd() {
if((this.listenerFailed || this.started) && !this.finished) { if ((this.listenerFailed || this.started) && !this.finished) {
this.taskExecution.setEndTime(new Date()); this.taskExecution.setEndTime(new Date());
if(this.applicationFailedException != null) { if (this.applicationFailedException != null) {
this.taskExecution.setErrorMessage(stackTraceToString(this.applicationFailedException)); this.taskExecution.setErrorMessage(
stackTraceToString(this.applicationFailedException));
} }
this.taskExecution.setExitCode(calcExitStatus()); this.taskExecution.setExitCode(calcExitStatus());
if (this.applicationFailedException != null) { if (this.applicationFailedException != null) {
setExitMessage(invokeOnTaskError(this.taskExecution, this.applicationFailedException)); setExitMessage(invokeOnTaskError(this.taskExecution,
this.applicationFailedException));
} }
setExitMessage(invokeOnTaskEnd(this.taskExecution)); setExitMessage(invokeOnTaskEnd(this.taskExecution));
this.taskRepository.completeTaskExecution(this.taskExecution.getExecutionId(), this.taskExecution.getExitCode(), this.taskRepository.completeTaskExecution(this.taskExecution.getExecutionId(),
this.taskExecution.getEndTime(), this.taskExecution.getExitMessage(), this.taskExecution.getErrorMessage()); this.taskExecution.getExitCode(), this.taskExecution.getEndTime(),
this.taskExecution.getExitMessage(),
this.taskExecution.getErrorMessage());
this.finished = true; this.finished = true;
if(this.taskProperties.getClosecontextEnabled() && this.context.isActive()) { if (this.taskProperties.getClosecontextEnabled() && this.context.isActive()) {
this.context.close(); this.context.close();
} }
} }
else if(!this.started){ else if (!this.started) {
logger.error("An event to end a task has been received for a task that has " + logger.error("An event to end a task has been received for a task that has "
"not yet started."); + "not yet started.");
} }
} }
private void setExitMessage(TaskExecution taskExecutionParam) { private void setExitMessage(TaskExecution taskExecutionParam) {
if(taskExecutionParam.getExitMessage() != null) { if (taskExecutionParam.getExitMessage() != null) {
this.taskExecution.setExitMessage(taskExecutionParam.getExitMessage()); this.taskExecution.setExitMessage(taskExecutionParam.getExitMessage());
} }
} }
@@ -218,10 +227,12 @@ public class TaskLifecycleListener implements ApplicationListener<ApplicationEve
Throwable exception = this.listenerException; Throwable exception = this.listenerException;
if (exception instanceof TaskExecutionException) { if (exception instanceof TaskExecutionException) {
TaskExecutionException taskExecutionException = (TaskExecutionException) exception; TaskExecutionException taskExecutionException = (TaskExecutionException) exception;
if (taskExecutionException.getCause() instanceof InvocationTargetException) { if (taskExecutionException
.getCause() instanceof InvocationTargetException) {
InvocationTargetException invocationTargetException = (InvocationTargetException) taskExecutionException InvocationTargetException invocationTargetException = (InvocationTargetException) taskExecutionException
.getCause(); .getCause();
if(invocationTargetException != null && invocationTargetException.getTargetException() != null) { if (invocationTargetException != null
&& invocationTargetException.getTargetException() != null) {
exception = invocationTargetException.getTargetException(); exception = invocationTargetException.getTargetException();
} }
} }
@@ -240,25 +251,32 @@ public class TaskLifecycleListener implements ApplicationListener<ApplicationEve
private void doTaskStart() { private void doTaskStart() {
try { try {
if(!this.started) { if (!this.started) {
this.taskExecutionListeners = new ArrayList<>(); this.taskExecutionListeners = new ArrayList<>();
this.taskListenerExecutorObjectFactory.getObject(); this.taskListenerExecutorObjectFactory.getObject();
if(!CollectionUtils.isEmpty(this.taskExecutionListenersFromContext)) { if (!CollectionUtils.isEmpty(this.taskExecutionListenersFromContext)) {
this.taskExecutionListeners.addAll(this.taskExecutionListenersFromContext); this.taskExecutionListeners
.addAll(this.taskExecutionListenersFromContext);
} }
this.taskExecutionListeners.add(this.taskListenerExecutorObjectFactory.getObject()); this.taskExecutionListeners
.add(this.taskListenerExecutorObjectFactory.getObject());
List<String> args = new ArrayList<>(0); List<String> args = new ArrayList<>(0);
if(this.applicationArguments != null) { if (this.applicationArguments != null) {
args = Arrays.asList(this.applicationArguments.getSourceArgs()); args = Arrays.asList(this.applicationArguments.getSourceArgs());
} }
if(this.taskProperties.getExecutionid() != null) { if (this.taskProperties.getExecutionid() != null) {
TaskExecution taskExecution = this.taskExplorer.getTaskExecution(this.taskProperties.getExecutionid()); TaskExecution taskExecution = this.taskExplorer
Assert.notNull(taskExecution, String.format("Invalid TaskExecution, ID %s not found", this.taskProperties.getExecutionid())); .getTaskExecution(this.taskProperties.getExecutionid());
Assert.notNull(taskExecution,
String.format("Invalid TaskExecution, ID %s not found",
this.taskProperties.getExecutionid()));
Assert.isNull(taskExecution.getEndTime(), String.format( Assert.isNull(taskExecution.getEndTime(), String.format(
"Invalid TaskExecution, ID %s task is already complete", this.taskProperties.getExecutionid())); "Invalid TaskExecution, ID %s task is already complete",
this.taskExecution = this.taskRepository.startTaskExecution(this.taskProperties.getExecutionid(), this.taskProperties.getExecutionid()));
this.taskExecution = this.taskRepository.startTaskExecution(
this.taskProperties.getExecutionid(),
this.taskNameResolver.getTaskName(), new Date(), args, this.taskNameResolver.getTaskName(), new Date(), args,
this.taskProperties.getExternalExecutionId(), this.taskProperties.getExternalExecutionId(),
this.taskProperties.getParentExecutionId()); this.taskProperties.getParentExecutionId());
@@ -268,15 +286,18 @@ public class TaskLifecycleListener implements ApplicationListener<ApplicationEve
taskExecution.setTaskName(this.taskNameResolver.getTaskName()); taskExecution.setTaskName(this.taskNameResolver.getTaskName());
taskExecution.setStartTime(new Date()); taskExecution.setStartTime(new Date());
taskExecution.setArguments(args); taskExecution.setArguments(args);
taskExecution.setExternalExecutionId(this.taskProperties.getExternalExecutionId()); taskExecution.setExternalExecutionId(
taskExecution.setParentExecutionId(this.taskProperties.getParentExecutionId()); this.taskProperties.getExternalExecutionId());
this.taskExecution = this.taskRepository.createTaskExecution( taskExecution.setParentExecutionId(
taskExecution); this.taskProperties.getParentExecutionId());
this.taskExecution = this.taskRepository
.createTaskExecution(taskExecution);
} }
} }
else { else {
logger.error("Multiple start events have been received. The first one was " + logger.error(
"recorded."); "Multiple start events have been received. The first one was "
+ "recorded.");
} }
setExitMessage(invokeOnTaskStartup(this.taskExecution)); setExitMessage(invokeOnTaskStartup(this.taskExecution));
@@ -289,9 +310,10 @@ public class TaskLifecycleListener implements ApplicationListener<ApplicationEve
} }
} }
private TaskExecution invokeOnTaskStartup(TaskExecution taskExecution){ private TaskExecution invokeOnTaskStartup(TaskExecution taskExecution) {
TaskExecution listenerTaskExecution = getTaskExecutionCopy(taskExecution); TaskExecution listenerTaskExecution = getTaskExecutionCopy(taskExecution);
List<TaskExecutionListener> startupListenerList = new ArrayList<>(this.taskExecutionListeners); List<TaskExecutionListener> startupListenerList = new ArrayList<>(
this.taskExecutionListeners);
if (!CollectionUtils.isEmpty(startupListenerList)) { if (!CollectionUtils.isEmpty(startupListenerList)) {
try { try {
Collections.reverse(startupListenerList); Collections.reverse(startupListenerList);
@@ -310,7 +332,7 @@ public class TaskLifecycleListener implements ApplicationListener<ApplicationEve
return listenerTaskExecution; return listenerTaskExecution;
} }
private TaskExecution invokeOnTaskEnd(TaskExecution taskExecution){ private TaskExecution invokeOnTaskEnd(TaskExecution taskExecution) {
TaskExecution listenerTaskExecution = getTaskExecutionCopy(taskExecution); TaskExecution listenerTaskExecution = getTaskExecutionCopy(taskExecution);
if (this.taskExecutionListeners != null) { if (this.taskExecutionListeners != null) {
try { try {
@@ -321,7 +343,8 @@ public class TaskLifecycleListener implements ApplicationListener<ApplicationEve
catch (Throwable listenerException) { catch (Throwable listenerException) {
String errorMessage = stackTraceToString(listenerException); String errorMessage = stackTraceToString(listenerException);
if (StringUtils.hasText(listenerTaskExecution.getErrorMessage())) { if (StringUtils.hasText(listenerTaskExecution.getErrorMessage())) {
errorMessage = String.format("%s :Task also threw this Exception: %s", errorMessage, listenerTaskExecution.getErrorMessage()); errorMessage = String.format("%s :Task also threw this Exception: %s",
errorMessage, listenerTaskExecution.getErrorMessage());
} }
logger.error(errorMessage); logger.error(errorMessage);
listenerTaskExecution.setErrorMessage(errorMessage); listenerTaskExecution.setErrorMessage(errorMessage);
@@ -331,7 +354,8 @@ public class TaskLifecycleListener implements ApplicationListener<ApplicationEve
return listenerTaskExecution; return listenerTaskExecution;
} }
private TaskExecution invokeOnTaskError(TaskExecution taskExecution, Throwable throwable){ private TaskExecution invokeOnTaskError(TaskExecution taskExecution,
Throwable throwable) {
TaskExecution listenerTaskExecution = getTaskExecutionCopy(taskExecution); TaskExecution listenerTaskExecution = getTaskExecutionCopy(taskExecution);
if (this.taskExecutionListeners != null) { if (this.taskExecutionListeners != null) {
try { try {
@@ -342,9 +366,9 @@ public class TaskLifecycleListener implements ApplicationListener<ApplicationEve
catch (Throwable listenerException) { catch (Throwable listenerException) {
this.listenerFailed = true; this.listenerFailed = true;
String errorMessage; String errorMessage;
if(StringUtils.hasText(listenerTaskExecution.getErrorMessage())) { if (StringUtils.hasText(listenerTaskExecution.getErrorMessage())) {
errorMessage = String.format("%s :While handling " + errorMessage = String.format("%s :While handling " + "this error: %s",
"this error: %s", listenerException.getMessage(), listenerException.getMessage(),
listenerTaskExecution.getErrorMessage()); listenerTaskExecution.getErrorMessage());
} }
else { else {
@@ -359,14 +383,14 @@ public class TaskLifecycleListener implements ApplicationListener<ApplicationEve
return listenerTaskExecution; return listenerTaskExecution;
} }
private TaskExecution getTaskExecutionCopy(TaskExecution taskExecution){ private TaskExecution getTaskExecutionCopy(TaskExecution taskExecution) {
Date startTime = new Date(taskExecution.getStartTime().getTime()); Date startTime = new Date(taskExecution.getStartTime().getTime());
Date endTime = (taskExecution.getEndTime() == null) ? Date endTime = (taskExecution.getEndTime() == null) ? null
null : new Date(taskExecution.getEndTime().getTime()); : new Date(taskExecution.getEndTime().getTime());
return new TaskExecution(taskExecution.getExecutionId(), return new TaskExecution(taskExecution.getExecutionId(),
taskExecution.getExitCode(), taskExecution.getTaskName(), startTime, taskExecution.getExitCode(), taskExecution.getTaskName(), startTime,
endTime,taskExecution.getExitMessage(), endTime, taskExecution.getExitMessage(),
Collections.unmodifiableList(taskExecution.getArguments()), Collections.unmodifiableList(taskExecution.getArguments()),
taskExecution.getErrorMessage(), taskExecution.getExternalExecutionId()); taskExecution.getErrorMessage(), taskExecution.getExternalExecutionId());
} }

View File

@@ -1,17 +1,17 @@
/* /*
* Copyright 2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.listener; package org.springframework.cloud.task.listener;
@@ -47,12 +47,13 @@ import org.springframework.core.annotation.AnnotationUtils;
* @author Glenn Renfro * @author Glenn Renfro
* @since 2.1.0 * @since 2.1.0
*/ */
public class TaskListenerExecutorObjectFactory implements ObjectFactory<TaskExecutionListener> { public class TaskListenerExecutorObjectFactory
implements ObjectFactory<TaskExecutionListener> {
private static final Log logger = LogFactory.getLog(TaskListenerExecutor.class); private static final Log logger = LogFactory.getLog(TaskListenerExecutor.class);
private final Set<Class<?>> nonAnnotatedClasses = private final Set<Class<?>> nonAnnotatedClasses = Collections
Collections.newSetFromMap(new ConcurrentHashMap<>()); .newSetFromMap(new ConcurrentHashMap<>());
private ConfigurableApplicationContext context; private ConfigurableApplicationContext context;
@@ -62,7 +63,7 @@ public class TaskListenerExecutorObjectFactory implements ObjectFactory<TaskExec
private Map<Method, Object> failedTaskInstances; private Map<Method, Object> failedTaskInstances;
public TaskListenerExecutorObjectFactory(ConfigurableApplicationContext context){ public TaskListenerExecutorObjectFactory(ConfigurableApplicationContext context) {
this.context = context; this.context = context;
} }
@@ -72,12 +73,13 @@ public class TaskListenerExecutorObjectFactory implements ObjectFactory<TaskExec
this.afterTaskInstances = new HashMap<>(); this.afterTaskInstances = new HashMap<>();
this.failedTaskInstances = new HashMap<>(); this.failedTaskInstances = new HashMap<>();
initializeExecutor(); initializeExecutor();
return new TaskListenerExecutor(beforeTaskInstances, afterTaskInstances, failedTaskInstances); return new TaskListenerExecutor(this.beforeTaskInstances, this.afterTaskInstances,
this.failedTaskInstances);
} }
private void initializeExecutor( ) { private void initializeExecutor() {
ConfigurableListableBeanFactory factory = context.getBeanFactory(); ConfigurableListableBeanFactory factory = this.context.getBeanFactory();
for( String beanName : context.getBeanDefinitionNames()) { for (String beanName : this.context.getBeanDefinitionNames()) {
if (!ScopedProxyUtils.isScopedTarget(beanName)) { if (!ScopedProxyUtils.isScopedTarget(beanName)) {
Class<?> type = null; Class<?> type = null;
@@ -85,9 +87,11 @@ public class TaskListenerExecutorObjectFactory implements ObjectFactory<TaskExec
type = AutoProxyUtils.determineTargetClass(factory, beanName); type = AutoProxyUtils.determineTargetClass(factory, beanName);
} }
catch (RuntimeException ex) { catch (RuntimeException ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it. // An unresolvable bean type, probably from a lazy bean - let's ignore
// it.
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex); logger.debug("Could not resolve target class for bean with name '"
+ beanName + "'", ex);
} }
} }
if (type != null) { if (type != null) {
@@ -99,7 +103,10 @@ public class TaskListenerExecutorObjectFactory implements ObjectFactory<TaskExec
catch (RuntimeException ex) { catch (RuntimeException ex) {
// An invalid scoped proxy arrangement - let's ignore it. // An invalid scoped proxy arrangement - let's ignore it.
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex); logger.debug(
"Could not resolve target bean for scoped proxy '"
+ beanName + "'",
ex);
} }
} }
} }
@@ -107,8 +114,11 @@ public class TaskListenerExecutorObjectFactory implements ObjectFactory<TaskExec
processBean(beanName, type); processBean(beanName, type);
} }
catch (RuntimeException ex) { catch (RuntimeException ex) {
throw new BeanInitializationException("Failed to process @BeforeTask " + throw new BeanInitializationException(
"annotation on bean with name '" + beanName + "'", ex); "Failed to process @BeforeTask "
+ "annotation on bean with name '" + beanName
+ "'",
ex);
} }
} }
} }
@@ -116,41 +126,49 @@ public class TaskListenerExecutorObjectFactory implements ObjectFactory<TaskExec
} }
private void processBean(String beanName, final Class<?> type){ private void processBean(String beanName, final Class<?> type) {
if (!this.nonAnnotatedClasses.contains(type)) { if (!this.nonAnnotatedClasses.contains(type)) {
Map<Method, BeforeTask> beforeTaskMethods = Map<Method, BeforeTask> beforeTaskMethods = (new MethodGetter<BeforeTask>())
(new MethodGetter<BeforeTask>()).getMethods(type, BeforeTask.class); .getMethods(type, BeforeTask.class);
Map<Method, AfterTask> afterTaskMethods = Map<Method, AfterTask> afterTaskMethods = (new MethodGetter<AfterTask>())
(new MethodGetter<AfterTask>()).getMethods(type, AfterTask.class); .getMethods(type, AfterTask.class);
Map<Method, FailedTask> failedTaskMethods = Map<Method, FailedTask> failedTaskMethods = (new MethodGetter<FailedTask>())
(new MethodGetter<FailedTask>()).getMethods(type, FailedTask.class); .getMethods(type, FailedTask.class);
if (beforeTaskMethods.isEmpty() && afterTaskMethods.isEmpty()) { if (beforeTaskMethods.isEmpty() && afterTaskMethods.isEmpty()) {
this.nonAnnotatedClasses.add(type); this.nonAnnotatedClasses.add(type);
return; return;
} }
if(!beforeTaskMethods.isEmpty()) { if (!beforeTaskMethods.isEmpty()) {
for(Method beforeTaskMethod : beforeTaskMethods.keySet()) { for (Method beforeTaskMethod : beforeTaskMethods.keySet()) {
this.beforeTaskInstances.put(beforeTaskMethod, context.getBean(beanName)); this.beforeTaskInstances.put(beforeTaskMethod,
this.context.getBean(beanName));
} }
} }
if(!afterTaskMethods.isEmpty()){ if (!afterTaskMethods.isEmpty()) {
for(Method afterTaskMethod : afterTaskMethods.keySet()) { for (Method afterTaskMethod : afterTaskMethods.keySet()) {
this.afterTaskInstances.put(afterTaskMethod, context.getBean(beanName)); this.afterTaskInstances.put(afterTaskMethod,
this.context.getBean(beanName));
} }
} }
if(!failedTaskMethods.isEmpty()){ if (!failedTaskMethods.isEmpty()) {
for(Method failedTaskMethod : failedTaskMethods.keySet()) { for (Method failedTaskMethod : failedTaskMethods.keySet()) {
this.failedTaskInstances.put(failedTaskMethod, context.getBean(beanName)); this.failedTaskInstances.put(failedTaskMethod,
this.context.getBean(beanName));
} }
} }
} }
} }
private static class MethodGetter<T extends Annotation> { private static class MethodGetter<T extends Annotation> {
public Map<Method, T> getMethods(final Class<?> type, final Class<T> annotationClass){
public Map<Method, T> getMethods(final Class<?> type,
final Class<T> annotationClass) {
return MethodIntrospector.selectMethods(type, return MethodIntrospector.selectMethods(type,
(MethodIntrospector.MetadataLookup<T>) method -> AnnotationUtils.findAnnotation(method, annotationClass)); (MethodIntrospector.MetadataLookup<T>) method -> AnnotationUtils
.findAnnotation(method, annotationClass));
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -27,22 +27,22 @@ import org.springframework.cloud.task.repository.TaskExecution;
/** /**
* <p> * <p>
* {@link TaskExecutionListener#onTaskEnd(TaskExecution)} * {@link TaskExecutionListener#onTaskEnd(TaskExecution)}.
* </p> * </p>
* *
* <pre class="code"> * <pre class="code">
* public class MyListener { * public class MyListener {
* &#064;AfterTask * &#064;AfterTask
* public void doSomething(TaskExecution taskExecution) { * public void doSomething(TaskExecution taskExecution) {
* } * }
* } * }
* </pre> * </pre>
* *
* @author Glenn Renfro * @author Glenn Renfro
*/ */
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Documented @Documented
public @interface AfterTask { public @interface AfterTask {
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -27,22 +27,22 @@ import org.springframework.cloud.task.repository.TaskExecution;
/** /**
* <p> * <p>
* {@link TaskExecutionListener#onTaskStartup(TaskExecution)} * {@link TaskExecutionListener#onTaskStartup(TaskExecution)}.
* </p> * </p>
* *
* <pre class="code"> * <pre class="code">
* public class MyListener { * public class MyListener {
* &#064;BeforeTask * &#064;BeforeTask
* public void doSomething(TaskExecution taskExecution) { * public void doSomething(TaskExecution taskExecution) {
* } * }
* } * }
* </pre> * </pre>
* *
* @author Glenn Renfro * @author Glenn Renfro
*/ */
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Documented @Documented
public @interface BeforeTask { public @interface BeforeTask {
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -27,22 +27,22 @@ import org.springframework.cloud.task.repository.TaskExecution;
/** /**
* <p> * <p>
* {@link TaskExecutionListener#onTaskFailed(TaskExecution, Throwable)} * {@link TaskExecutionListener#onTaskFailed(TaskExecution, Throwable)}.
* </p> * </p>
* *
* <pre class="code"> * <pre class="code">
* public class MyListener { * public class MyListener {
* &#064;FailedTask * &#064;FailedTask
* public void doSomething(TaskExecution taskExecution, Throwable throwable) { * public void doSomething(TaskExecution taskExecution, Throwable throwable) {
* } * }
* } * }
* </pre> * </pre>
* *
* @author Glenn Renfro * @author Glenn Renfro
*/ */
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Documented @Documented
public @interface FailedTask { public @interface FailedTask {
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -32,7 +32,7 @@ import org.springframework.cloud.task.repository.TaskExecution;
* *
* @author Glenn Renfro * @author Glenn Renfro
*/ */
public class TaskListenerExecutor implements TaskExecutionListener{ public class TaskListenerExecutor implements TaskExecutionListener {
private Map<Method, Object> beforeTaskInstances; private Map<Method, Object> beforeTaskInstances;
@@ -42,7 +42,7 @@ public class TaskListenerExecutor implements TaskExecutionListener{
public TaskListenerExecutor(Map<Method, Object> beforeTaskInstances, public TaskListenerExecutor(Map<Method, Object> beforeTaskInstances,
Map<Method, Object> afterTaskInstances, Map<Method, Object> afterTaskInstances,
Map<Method, Object> failedTaskInstances){ Map<Method, Object> failedTaskInstances) {
this.beforeTaskInstances = beforeTaskInstances; this.beforeTaskInstances = beforeTaskInstances;
this.afterTaskInstances = afterTaskInstances; this.afterTaskInstances = afterTaskInstances;
@@ -50,66 +50,77 @@ public class TaskListenerExecutor implements TaskExecutionListener{
} }
/** /**
* Executes all the methods that have been annotated with &#064;BeforeTask. * Executes all the methods that have been annotated with &#064;BeforeTask.
* @param taskExecution associated with the event. * @param taskExecution associated with the event.
*/ */
@Override @Override
public void onTaskStartup(TaskExecution taskExecution) { public void onTaskStartup(TaskExecution taskExecution) {
executeTaskListener(taskExecution, beforeTaskInstances.keySet(), beforeTaskInstances); executeTaskListener(taskExecution, this.beforeTaskInstances.keySet(),
this.beforeTaskInstances);
} }
/** /**
* Executes all the methods that have been annotated with &#064;AfterTask. * Executes all the methods that have been annotated with &#064;AfterTask.
* @param taskExecution associated with the event. * @param taskExecution associated with the event.
*/ */
@Override @Override
public void onTaskEnd(TaskExecution taskExecution) { public void onTaskEnd(TaskExecution taskExecution) {
executeTaskListener(taskExecution, afterTaskInstances.keySet(), afterTaskInstances); executeTaskListener(taskExecution, this.afterTaskInstances.keySet(),
this.afterTaskInstances);
} }
/** /**
* Executes all the methods that have been annotated with &#064;FailedTask. * Executes all the methods that have been annotated with &#064;FailedTask.
* @param throwable that was not caught for the task execution. * @param throwable that was not caught for the task execution.
* @param taskExecution associated with the event. * @param taskExecution associated with the event.
*/ */
@Override @Override
public void onTaskFailed(TaskExecution taskExecution, Throwable throwable) { public void onTaskFailed(TaskExecution taskExecution, Throwable throwable) {
executeTaskListenerWithThrowable(taskExecution, throwable, executeTaskListenerWithThrowable(taskExecution, throwable,
failedTaskInstances.keySet(),failedTaskInstances); this.failedTaskInstances.keySet(), this.failedTaskInstances);
} }
private void executeTaskListener(TaskExecution taskExecution, Set<Method> methods, Map<Method, Object> instances){ private void executeTaskListener(TaskExecution taskExecution, Set<Method> methods,
Map<Method, Object> instances) {
for (Method method : methods) { for (Method method : methods) {
try { try {
method.invoke(instances.get(method),taskExecution); method.invoke(instances.get(method), taskExecution);
} }
catch (IllegalAccessException e) { catch (IllegalAccessException e) {
throw new TaskExecutionException("@BeforeTask and @AfterTask annotated methods must be public.", e); throw new TaskExecutionException(
"@BeforeTask and @AfterTask annotated methods must be public.",
e);
} }
catch (InvocationTargetException e) { catch (InvocationTargetException e) {
throw new TaskExecutionException(String.format("Failed to process @BeforeTask or @AfterTask" + throw new TaskExecutionException(String.format(
" annotation because: %s", e.getTargetException().getMessage()), e); "Failed to process @BeforeTask or @AfterTask"
+ " annotation because: %s",
e.getTargetException().getMessage()), e);
} }
catch (IllegalArgumentException e){ catch (IllegalArgumentException e) {
throw new TaskExecutionException("taskExecution parameter is required for @BeforeTask and @AfterTask annotated methods", e); throw new TaskExecutionException("taskExecution parameter "
+ "is required for @BeforeTask and @AfterTask annotated methods",
e);
} }
} }
} }
private void executeTaskListenerWithThrowable(TaskExecution taskExecution, private void executeTaskListenerWithThrowable(TaskExecution taskExecution,
Throwable throwable, Set<Method> methods, Map<Method, Object> instances){ Throwable throwable, Set<Method> methods, Map<Method, Object> instances) {
for (Method method : methods) { for (Method method : methods) {
try { try {
method.invoke(instances.get(method),taskExecution, throwable); method.invoke(instances.get(method), taskExecution, throwable);
} }
catch (IllegalAccessException e) { catch (IllegalAccessException e) {
throw new TaskExecutionException("@FailedTask annotated methods must be public.", e); throw new TaskExecutionException(
"@FailedTask annotated methods must be public.", e);
} }
catch (InvocationTargetException e) { catch (InvocationTargetException e) {
throw new TaskExecutionException(String.format("Failed to process @FailedTask " + throw new TaskExecutionException(String.format(
"annotation because: %s", e.getTargetException().getMessage()), e); "Failed to process @FailedTask " + "annotation because: %s",
e.getTargetException().getMessage()), e);
} }
catch (IllegalArgumentException e){ catch (IllegalArgumentException e) {
throw new TaskExecutionException("taskExecution and throwable parameters " throw new TaskExecutionException("taskExecution and throwable parameters "
+ "are required for @FailedTask annotated methods", e); + "are required for @FailedTask annotated methods", e);
} }

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2015-2019 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.
*/
/** /**
* Base package for spring cloud task. * Base package for spring cloud task.
*/ */

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015-2017 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -33,7 +33,7 @@ import org.springframework.util.Assert;
public class TaskExecution { public class TaskExecution {
/** /**
* The unique id associated with the task execution. * The unique id associated with the task execution.
*/ */
private long executionId; private long executionId;
@@ -75,7 +75,7 @@ public class TaskExecution {
private String externalExecutionId; private String externalExecutionId;
/** /**
* Error information available upon the failure of a task * Error information available upon the failure of a task.
* *
* @since 1.1.0 * @since 1.1.0
*/ */
@@ -87,14 +87,12 @@ public class TaskExecution {
private List<String> arguments; private List<String> arguments;
public TaskExecution() { public TaskExecution() {
arguments = new ArrayList<>(); this.arguments = new ArrayList<>();
} }
public TaskExecution(long executionId, Integer exitCode, String taskName, public TaskExecution(long executionId, Integer exitCode, String taskName,
Date startTime, Date endTime, Date startTime, Date endTime, String exitMessage, List<String> arguments,
String exitMessage, List<String> arguments, String errorMessage, String externalExecutionId, Long parentExecutionId) {
String errorMessage, String externalExecutionId,
Long parentExecutionId) {
Assert.notNull(arguments, "arguments must not be null"); Assert.notNull(arguments, "arguments must not be null");
this.executionId = executionId; this.executionId = executionId;
@@ -102,24 +100,23 @@ public class TaskExecution {
this.taskName = taskName; this.taskName = taskName;
this.exitMessage = exitMessage; this.exitMessage = exitMessage;
this.arguments = new ArrayList<>(arguments); this.arguments = new ArrayList<>(arguments);
this.startTime = (startTime != null) ? (Date)startTime.clone() : null; this.startTime = (startTime != null) ? (Date) startTime.clone() : null;
this.endTime = (endTime != null) ? (Date)endTime.clone() : null; this.endTime = (endTime != null) ? (Date) endTime.clone() : null;
this.errorMessage = errorMessage; this.errorMessage = errorMessage;
this.externalExecutionId = externalExecutionId; this.externalExecutionId = externalExecutionId;
this.parentExecutionId = parentExecutionId; this.parentExecutionId = parentExecutionId;
} }
public TaskExecution(long executionId, Integer exitCode, String taskName, public TaskExecution(long executionId, Integer exitCode, String taskName,
Date startTime, Date endTime, Date startTime, Date endTime, String exitMessage, List<String> arguments,
String exitMessage, List<String> arguments,
String errorMessage, String externalExecutionId) { String errorMessage, String externalExecutionId) {
this(executionId, exitCode, taskName, startTime, endTime, exitMessage, this(executionId, exitCode, taskName, startTime, endTime, exitMessage, arguments,
arguments, errorMessage,externalExecutionId, null); errorMessage, externalExecutionId, null);
} }
public long getExecutionId() { public long getExecutionId() {
return executionId; return this.executionId;
} }
public Integer getExitCode() { public Integer getExitCode() {
@@ -131,7 +128,7 @@ public class TaskExecution {
} }
public String getTaskName() { public String getTaskName() {
return taskName; return this.taskName;
} }
public void setTaskName(String taskName) { public void setTaskName(String taskName) {
@@ -139,23 +136,23 @@ public class TaskExecution {
} }
public Date getStartTime() { public Date getStartTime() {
return (startTime != null) ? (Date)startTime.clone() : null; return (this.startTime != null) ? (Date) this.startTime.clone() : null;
} }
public void setStartTime(Date startTime) { public void setStartTime(Date startTime) {
this.startTime = (startTime != null) ? (Date)startTime.clone() : null; this.startTime = (startTime != null) ? (Date) startTime.clone() : null;
} }
public Date getEndTime() { public Date getEndTime() {
return (endTime != null) ? (Date)endTime.clone() : null; return (this.endTime != null) ? (Date) this.endTime.clone() : null;
} }
public void setEndTime(Date endTime) { public void setEndTime(Date endTime) {
this.endTime = (endTime != null) ? (Date)endTime.clone() : null; this.endTime = (endTime != null) ? (Date) endTime.clone() : null;
} }
public String getExitMessage() { public String getExitMessage() {
return exitMessage; return this.exitMessage;
} }
public void setExitMessage(String exitMessage) { public void setExitMessage(String exitMessage) {
@@ -163,15 +160,15 @@ public class TaskExecution {
} }
public List<String> getArguments() { public List<String> getArguments() {
return arguments; return this.arguments;
} }
public void setArguments(List<String> arguments) { public void setArguments(List<String> arguments) {
this.arguments = new ArrayList<> (arguments); this.arguments = new ArrayList<>(arguments);
} }
public String getErrorMessage() { public String getErrorMessage() {
return errorMessage; return this.errorMessage;
} }
public void setErrorMessage(String errorMessage) { public void setErrorMessage(String errorMessage) {
@@ -179,7 +176,7 @@ public class TaskExecution {
} }
public String getExternalExecutionId() { public String getExternalExecutionId() {
return externalExecutionId; return this.externalExecutionId;
} }
public void setExternalExecutionId(String externalExecutionId) { public void setExternalExecutionId(String externalExecutionId) {
@@ -187,7 +184,7 @@ public class TaskExecution {
} }
public Long getParentExecutionId() { public Long getParentExecutionId() {
return parentExecutionId; return this.parentExecutionId;
} }
public void setParentExecutionId(Long parentExecutionId) { public void setParentExecutionId(Long parentExecutionId) {
@@ -196,17 +193,13 @@ public class TaskExecution {
@Override @Override
public String toString() { public String toString() {
return "TaskExecution{" + return "TaskExecution{" + "executionId=" + this.executionId
"executionId=" + executionId + + ", parentExecutionId=" + this.parentExecutionId + ", exitCode="
", parentExecutionId=" + parentExecutionId + + this.exitCode + ", taskName='" + this.taskName + '\'' + ", startTime="
", exitCode=" + exitCode + + this.startTime + ", endTime=" + this.endTime + ", exitMessage='"
", taskName='" + taskName + '\'' + + this.exitMessage + '\'' + ", externalExecutionId='"
", startTime=" + startTime + + this.externalExecutionId + '\'' + ", errorMessage='" + this.errorMessage
", endTime=" + endTime + + '\'' + ", arguments=" + this.arguments + '}';
", exitMessage='" + exitMessage + '\'' +
", externalExecutionId='" + externalExecutionId + '\'' +
", errorMessage='" + errorMessage + '\'' +
", arguments=" + arguments +
'}';
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -33,16 +33,13 @@ public interface TaskExplorer {
/** /**
* Retrieve a {@link TaskExecution} by its id. * Retrieve a {@link TaskExecution} by its id.
*
* @param executionId the task execution id * @param executionId the task execution id
* @return the {@link TaskExecution} with this id, or null if not found * @return the {@link TaskExecution} with this id, or null if not found
*/ */
TaskExecution getTaskExecution(long executionId); TaskExecution getTaskExecution(long executionId);
/** /**
* Retrieve a collection of taskExecutions that have the task name provided. * Retrieve a collection of taskExecutions that have the task name provided.
*
* @param taskName the name of the task * @param taskName the name of the task
* @param pageable the constraints for the search * @param pageable the constraints for the search
* @return the set of running executions for tasks with the specified name * @return the set of running executions for tasks with the specified name
@@ -51,14 +48,12 @@ public interface TaskExplorer {
/** /**
* Retrieve a list of available task names. * Retrieve a list of available task names.
*
* @return the set of task names that have been executed * @return the set of task names that have been executed
*/ */
List<String> getTaskNames(); List<String> getTaskNames();
/** /**
* Get number of executions for a taskName. * Get number of executions for a taskName.
*
* @param taskName the name of the task to be searched * @param taskName the name of the task to be searched
* @return the number of running tasks that have the taskname specified * @return the number of running tasks that have the taskname specified
*/ */
@@ -66,21 +61,18 @@ public interface TaskExplorer {
/** /**
* Retrieves current number of task executions. * Retrieves current number of task executions.
*
* @return current number of task executions. * @return current number of task executions.
*/ */
long getTaskExecutionCount(); long getTaskExecutionCount();
/** /**
* Retrieves current number of running task executions. * Retrieves current number of running task executions.
*
* @return current number of running task executions. * @return current number of running task executions.
*/ */
long getRunningTaskExecutionCount(); long getRunningTaskExecutionCount();
/** /**
* Get a collection/page of executions * Get a collection/page of executions.
*
* @param taskName the name of the task to be searched * @param taskName the name of the task to be searched
* @param pageable the constraints for the search * @param pageable the constraints for the search
* @return list of task executions * @return list of task executions
@@ -88,9 +80,8 @@ public interface TaskExplorer {
Page<TaskExecution> findTaskExecutionsByName(String taskName, Pageable pageable); Page<TaskExecution> findTaskExecutionsByName(String taskName, Pageable pageable);
/** /**
* Retrieves all the task executions within the pageable constraints sorted by * Retrieves all the task executions within the pageable constraints sorted by start
* start date descending, taskExecution id descending. * date descending, taskExecution id descending.
*
* @param pageable the constraints for the search * @param pageable the constraints for the search
* @return page containing the results from the search * @return page containing the results from the search
*/ */
@@ -98,8 +89,7 @@ public interface TaskExplorer {
/** /**
* Returns the id of the TaskExecution that the requested Spring Batch job execution * Returns the id of the TaskExecution that the requested Spring Batch job execution
* was executed within the context of. Returns null if none were found. * was executed within the context of. Returns null if none were found.
*
* @param jobExecutionId the id of the JobExecution * @param jobExecutionId the id of the JobExecution
* @return the id of the {@link TaskExecution} * @return the id of the {@link TaskExecution}
*/ */
@@ -108,39 +98,39 @@ public interface TaskExplorer {
/** /**
* Returns a Set of JobExecution ids for the jobs that were executed within the scope * Returns a Set of JobExecution ids for the jobs that were executed within the scope
* of the requested task. * of the requested task.
*
* @param taskExecutionId id of the {@link TaskExecution} * @param taskExecutionId id of the {@link TaskExecution}
* @return a <code>Set</code> of the ids of the job executions executed within the task. * @return a <code>Set</code> of the ids of the job executions executed within the
* task.
*/ */
Set<Long> getJobExecutionIdsByTaskExecutionId(long taskExecutionId); Set<Long> getJobExecutionIdsByTaskExecutionId(long taskExecutionId);
/** /**
* Returns a {@link List} of the latest {@link TaskExecution} for 1 or more task names. * Returns a {@link List} of the latest {@link TaskExecution} for 1 or more task
* names.
* *
* Latest is defined by the most recent start time. A {@link TaskExecution} does not have to be finished * Latest is defined by the most recent start time. A {@link TaskExecution} does not
* (The results may including pending {@link TaskExecution}s). * have to be finished (The results may including pending {@link TaskExecution}s).
* *
* It is theoretically possible that a {@link TaskExecution} with the same name to have more than 1 * It is theoretically possible that a {@link TaskExecution} with the same name to
* {@link TaskExecution} for the exact same start time. In that case the {@link TaskExecution} with the * have more than 1 {@link TaskExecution} for the exact same start time. In that case
* highest Task Execution ID is returned. * the {@link TaskExecution} with the highest Task Execution ID is returned.
*
* This method will not consider end times in its calculations. Thus, when a task execution {@code A} starts
* after task execution {@code B} but finishes BEFORE task execution {@code A}, then task execution {@code B}
* is being returned.
* *
* This method will not consider end times in its calculations. Thus, when a task
* execution {@code A} starts after task execution {@code B} but finishes BEFORE task
* execution {@code A}, then task execution {@code B} is being returned.
* @param taskNames At least 1 task name must be provided * @param taskNames At least 1 task name must be provided
* @return List of TaskExecutions. May be empty but never null. * @return List of TaskExecutions. May be empty but never null.
*/ */
List<TaskExecution> getLatestTaskExecutionsByTaskNames(String... taskNames); List<TaskExecution> getLatestTaskExecutionsByTaskNames(String... taskNames);
/** /**
* Returns the latest task execution for a given task name. Will ultimately apply the same algorithm underneath * Returns the latest task execution for a given task name. Will ultimately apply the
* as {@link #getLatestTaskExecutionsByTaskNames(String...)} but will only return a single result. * same algorithm underneath as {@link #getLatestTaskExecutionsByTaskNames(String...)}
* * but will only return a single result.
* @param taskName Must not be null or empty * @param taskName Must not be null or empty
* @return The latest Task Execution or null * @return The latest Task Execution or null
* @see #getLatestTaskExecutionsByTaskNames(String...) * @see #getLatestTaskExecutionsByTaskNames(String...)
*/ */
TaskExecution getLatestTaskExecutionForTaskName(String taskName); TaskExecution getLatestTaskExecutionForTaskName(String taskName);
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.repository; package org.springframework.cloud.task.repository;
/** /**
@@ -26,4 +27,5 @@ public interface TaskNameResolver {
* @return the name of the task being executed within this context. * @return the name of the task being executed within this context.
*/ */
String getTaskName(); String getTaskName();
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -31,7 +31,6 @@ public interface TaskRepository {
/** /**
* Notifies the repository that a taskExecution has completed. * Notifies the repository that a taskExecution has completed.
*
* @param executionId to the task execution to be updated. * @param executionId to the task execution to be updated.
* @param exitCode to be stored for this task. * @param exitCode to be stored for this task.
* @param endTime designated when the task completed. * @param endTime designated when the task completed.
@@ -40,11 +39,10 @@ public interface TaskRepository {
*/ */
@Transactional @Transactional
TaskExecution completeTaskExecution(long executionId, Integer exitCode, Date endTime, TaskExecution completeTaskExecution(long executionId, Integer exitCode, Date endTime,
String exitMessage); String exitMessage);
/** /**
* Notifies the repository that a taskExecution has completed. * Notifies the repository that a taskExecution has completed.
*
* @param executionId to the task execution to be updated. * @param executionId to the task execution to be updated.
* @param exitCode to be stored for this task execution. * @param exitCode to be stored for this task execution.
* @param endTime designated when the task completed. * @param endTime designated when the task completed.
@@ -55,30 +53,26 @@ public interface TaskRepository {
*/ */
@Transactional @Transactional
TaskExecution completeTaskExecution(long executionId, Integer exitCode, Date endTime, TaskExecution completeTaskExecution(long executionId, Integer exitCode, Date endTime,
String exitMessage, String errorMessage); String exitMessage, String errorMessage);
/** /**
* Notifies the repository that a taskExecution needs to be created. * Notifies the repository that a taskExecution needs to be created.
* * @param taskExecution a TaskExecution instance containing the startTime, arguments
* @param taskExecution a TaskExecution instance containing the startTime, * and externalExecutionId that will be stored in the repository. Only the values
* arguments and externalExecutionId that will be stored in the repository. * enumerated above will be stored for this TaskExecution.
* Only the values enumerated above will be stored for this * @return the {@link TaskExecution} that was stored in the repository. The
* TaskExecution's taskExecutionId will also contain the id that was used to store the
* TaskExecution. * TaskExecution.
* @return the {@link TaskExecution} that was stored in the repository. The
* TaskExecution's taskExecutionId will also contain the id that was used
* to store the TaskExecution.
*/ */
@Transactional @Transactional
TaskExecution createTaskExecution(TaskExecution taskExecution); TaskExecution createTaskExecution(TaskExecution taskExecution);
/** /**
* Creates an empty TaskExecution with just an id and name provided. This is intended to be * Creates an empty TaskExecution with just an id and name provided. This is intended
* utilized in systems where the request of launching a task is separate from the * to be utilized in systems where the request of launching a task is separate from
* actual start of a task (the underlying system may need to deploy the task prior to * the actual start of a task (the underlying system may need to deploy the task prior
* launching, etc). * to launching, etc).
*
* @param name task name to be associated with the task execution. * @param name task name to be associated with the task execution.
*
* @return the initial {@link TaskExecution} * @return the initial {@link TaskExecution}
*/ */
@Transactional @Transactional
@@ -89,7 +83,6 @@ public interface TaskRepository {
* utilized in systems where the request of launching a task is separate from the * utilized in systems where the request of launching a task is separate from the
* actual start of a task (the underlying system may need to deploy the task prior to * actual start of a task (the underlying system may need to deploy the task prior to
* launching, etc). * launching, etc).
*
* @return the initial {@link TaskExecution} * @return the initial {@link TaskExecution}
*/ */
@Transactional @Transactional
@@ -97,43 +90,38 @@ public interface TaskRepository {
/** /**
* Notifies the repository that a taskExecution has has started. * Notifies the repository that a taskExecution has has started.
* * @param executionid to the task execution to be updated.
* @param executionid to the task execution to be updated. * @param taskName the name that associated with the task execution.
* @param taskName the name that associated with the task execution. * @param startTime the time task began.
* @param startTime the time task began. * @param arguments list of key/value pairs that configure the task.
* @param arguments list of key/value pairs that configure the task.
* @param externalExecutionId id assigned to the task by the platform. * @param externalExecutionId id assigned to the task by the platform.
* @return TaskExecution created based on the parameters. * @return TaskExecution created based on the parameters.
*/ */
@Transactional @Transactional
TaskExecution startTaskExecution(long executionid, String taskName, TaskExecution startTaskExecution(long executionid, String taskName, Date startTime,
Date startTime,List<String> arguments, String externalExecutionId); List<String> arguments, String externalExecutionId);
/** /**
* Notifies the repository to update the taskExecution's externalExecutionId. * Notifies the repository to update the taskExecution's externalExecutionId.
* * @param executionid to the task execution to be updated.
* @param executionid to the task execution to be updated.
* @param externalExecutionId id assigned to the task by the platform. * @param externalExecutionId id assigned to the task by the platform.
*/ */
@Transactional @Transactional
void updateExternalExecutionId(long executionid, void updateExternalExecutionId(long executionid, String externalExecutionId);
String externalExecutionId);
/** /**
* Notifies the repository that a taskExecution has has started. * Notifies the repository that a taskExecution has has started.
* @param executionid to the task execution to be updated. * @param executionid to the task execution to be updated.
* @param taskName the name that associated with the task execution. * @param taskName the name that associated with the task execution.
* @param startTime the time task began. * @param startTime the time task began.
* @param arguments list of key/value pairs that configure the task. * @param arguments list of key/value pairs that configure the task.
* @param externalExecutionId id assigned to the task by the platform. * @param externalExecutionId id assigned to the task by the platform.
* @param parentExecutionId the parent task execution id. * @param parentExecutionId the parent task execution id.
* @return A TaskExecution that contains the information available at the beginning of
* @return A TaskExecution that contains the information available at the * a TaskExecution.
* beginning of a TaskExecution.
*/ */
@Transactional @Transactional
TaskExecution startTaskExecution(long executionid, String taskName, TaskExecution startTaskExecution(long executionid, String taskName, Date startTime,
Date startTime,List<String> arguments, String externalExecutionId, List<String> arguments, String externalExecutionId, Long parentExecutionId);
Long parentExecutionId);
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -61,22 +61,33 @@ import org.springframework.util.StringUtils;
*/ */
public class JdbcTaskExecutionDao implements TaskExecutionDao { public class JdbcTaskExecutionDao implements TaskExecutionDao {
/**
* SELECT clause for task execution.
*/
public static final String SELECT_CLAUSE = "TASK_EXECUTION_ID, " public static final String SELECT_CLAUSE = "TASK_EXECUTION_ID, "
+ "START_TIME, END_TIME, TASK_NAME, EXIT_CODE, " + "START_TIME, END_TIME, TASK_NAME, EXIT_CODE, "
+ "EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, " + "EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, "
+ "EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID "; + "EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID ";
/**
* FROM clause for task execution.
*/
public static final String FROM_CLAUSE = "%PREFIX%EXECUTION"; public static final String FROM_CLAUSE = "%PREFIX%EXECUTION";
public static final String RUNNING_TASK_WHERE_CLAUSE = /**
"where TASK_NAME = :taskName AND END_TIME IS NULL "; * WHERE clause for running task.
*/
public static final String RUNNING_TASK_WHERE_CLAUSE = "where TASK_NAME = :taskName AND END_TIME IS NULL ";
/**
* WHERE clause for task name.
*/
public static final String TASK_NAME_WHERE_CLAUSE = "where TASK_NAME = :taskName "; public static final String TASK_NAME_WHERE_CLAUSE = "where TASK_NAME = :taskName ";
private static final String SAVE_TASK_EXECUTION = "INSERT into %PREFIX%EXECUTION" private static final String SAVE_TASK_EXECUTION = "INSERT into %PREFIX%EXECUTION"
+ "(TASK_EXECUTION_ID, EXIT_CODE, START_TIME, TASK_NAME, LAST_UPDATED, EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID)" + "(TASK_EXECUTION_ID, EXIT_CODE, START_TIME, TASK_NAME, LAST_UPDATED, EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID)"
+ "values (:taskExecutionId, :exitCode, :startTime, :taskName, :lastUpdated, :externalExecutionId, :parentExecutionId)"; + "values (:taskExecutionId, :exitCode, :startTime, "
+ ":taskName, :lastUpdated, :externalExecutionId, :parentExecutionId)";
private static final String CREATE_TASK_ARGUMENT = "INSERT into " private static final String CREATE_TASK_ARGUMENT = "INSERT into "
+ "%PREFIX%EXECUTION_PARAMS(TASK_EXECUTION_ID, TASK_PARAM ) values (:taskExecutionId, :taskParam)"; + "%PREFIX%EXECUTION_PARAMS(TASK_EXECUTION_ID, TASK_PARAM ) values (:taskExecutionId, :taskParam)";
@@ -85,9 +96,11 @@ public class JdbcTaskExecutionDao implements TaskExecutionDao {
+ "START_TIME = :startTime, TASK_NAME = :taskName, LAST_UPDATED = :lastUpdated"; + "START_TIME = :startTime, TASK_NAME = :taskName, LAST_UPDATED = :lastUpdated";
private static final String START_TASK_EXECUTION_EXTERNAL_ID_SUFFIX = ", " private static final String START_TASK_EXECUTION_EXTERNAL_ID_SUFFIX = ", "
+ "EXTERNAL_EXECUTION_ID = :externalExecutionId, PARENT_EXECUTION_ID = :parentExecutionId where TASK_EXECUTION_ID = :taskExecutionId"; + "EXTERNAL_EXECUTION_ID = :externalExecutionId, PARENT_EXECUTION_ID = :parentExecutionId "
+ "where TASK_EXECUTION_ID = :taskExecutionId";
private static final String START_TASK_EXECUTION_SUFFIX = ", PARENT_EXECUTION_ID = :parentExecutionId where TASK_EXECUTION_ID = :taskExecutionId"; private static final String START_TASK_EXECUTION_SUFFIX = ", PARENT_EXECUTION_ID = :parentExecutionId "
+ "where TASK_EXECUTION_ID = :taskExecutionId";
private static final String CHECK_TASK_EXECUTION_EXISTS = "SELECT COUNT(*) FROM " private static final String CHECK_TASK_EXECUTION_EXISTS = "SELECT COUNT(*) FROM "
+ "%PREFIX%EXECUTION WHERE TASK_EXECUTION_ID = :taskExecutionId"; + "%PREFIX%EXECUTION WHERE TASK_EXECUTION_ID = :taskExecutionId";
@@ -99,8 +112,8 @@ public class JdbcTaskExecutionDao implements TaskExecutionDao {
private static final String UPDATE_TASK_EXECUTION_EXTERNAL_EXECUTION_ID = "UPDATE %PREFIX%EXECUTION set " private static final String UPDATE_TASK_EXECUTION_EXTERNAL_EXECUTION_ID = "UPDATE %PREFIX%EXECUTION set "
+ "EXTERNAL_EXECUTION_ID = :externalExecutionId where TASK_EXECUTION_ID = :taskExecutionId"; + "EXTERNAL_EXECUTION_ID = :externalExecutionId where TASK_EXECUTION_ID = :taskExecutionId";
private static final String GET_EXECUTION_BY_ID = "SELECT TASK_EXECUTION_ID, " + private static final String GET_EXECUTION_BY_ID = "SELECT TASK_EXECUTION_ID, "
"START_TIME, END_TIME, TASK_NAME, EXIT_CODE, " + "START_TIME, END_TIME, TASK_NAME, EXIT_CODE, "
+ "EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, EXTERNAL_EXECUTION_ID, " + "EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, EXTERNAL_EXECUTION_ID, "
+ "PARENT_EXECUTION_ID " + "PARENT_EXECUTION_ID "
+ "from %PREFIX%EXECUTION where TASK_EXECUTION_ID = :taskExecutionId"; + "from %PREFIX%EXECUTION where TASK_EXECUTION_ID = :taskExecutionId";
@@ -108,41 +121,40 @@ public class JdbcTaskExecutionDao implements TaskExecutionDao {
private static final String FIND_ARGUMENT_FROM_ID = "SELECT TASK_EXECUTION_ID, " private static final String FIND_ARGUMENT_FROM_ID = "SELECT TASK_EXECUTION_ID, "
+ "TASK_PARAM from %PREFIX%EXECUTION_PARAMS where TASK_EXECUTION_ID = :taskExecutionId"; + "TASK_PARAM from %PREFIX%EXECUTION_PARAMS where TASK_EXECUTION_ID = :taskExecutionId";
private static final String TASK_EXECUTION_COUNT = "SELECT COUNT(*) FROM " + private static final String TASK_EXECUTION_COUNT = "SELECT COUNT(*) FROM "
"%PREFIX%EXECUTION "; + "%PREFIX%EXECUTION ";
private static final String TASK_EXECUTION_COUNT_BY_NAME = "SELECT COUNT(*) FROM " + private static final String TASK_EXECUTION_COUNT_BY_NAME = "SELECT COUNT(*) FROM "
"%PREFIX%EXECUTION where TASK_NAME = :taskName"; + "%PREFIX%EXECUTION where TASK_NAME = :taskName";
private static final String RUNNING_TASK_EXECUTION_COUNT_BY_NAME = "SELECT COUNT(*) FROM " + private static final String RUNNING_TASK_EXECUTION_COUNT_BY_NAME = "SELECT COUNT(*) FROM "
"%PREFIX%EXECUTION where TASK_NAME = :taskName AND END_TIME IS NULL "; + "%PREFIX%EXECUTION where TASK_NAME = :taskName AND END_TIME IS NULL ";
private static final String RUNNING_TASK_EXECUTION_COUNT = "SELECT COUNT(*) FROM " + private static final String RUNNING_TASK_EXECUTION_COUNT = "SELECT COUNT(*) FROM "
"%PREFIX%EXECUTION where END_TIME IS NULL "; + "%PREFIX%EXECUTION where END_TIME IS NULL ";
private static final String LAST_TASK_EXECUTIONS_BY_TASK_NAMES = private static final String LAST_TASK_EXECUTIONS_BY_TASK_NAMES = "select TE2.* from ("
"select TE2.* from (" + + "select MAX(TE.TASK_EXECUTION_ID) as TASK_EXECUTION_ID, TE.TASK_NAME, TE.START_TIME from ("
"select MAX(TE.TASK_EXECUTION_ID) as TASK_EXECUTION_ID, TE.TASK_NAME, TE.START_TIME from (" + + "select TASK_NAME, MAX(START_TIME) as START_TIME"
"select TASK_NAME, MAX(START_TIME) as START_TIME" + + " FROM %PREFIX%EXECUTION where TASK_NAME in (:taskNames)"
" FROM %PREFIX%EXECUTION where TASK_NAME in (:taskNames)" + + " GROUP BY TASK_NAME" + ") TE_MAX "
" GROUP BY TASK_NAME" + + "inner join %PREFIX%EXECUTION TE ON TE.TASK_NAME = TE_MAX.TASK_NAME AND TE.START_TIME = TE_MAX.START_TIME "
") TE_MAX " + + "group by TE.TASK_NAME, TE.START_TIME" + ") TE1 "
"inner join %PREFIX%EXECUTION TE ON TE.TASK_NAME = TE_MAX.TASK_NAME AND TE.START_TIME = TE_MAX.START_TIME " + + "inner join %PREFIX%EXECUTION TE2 ON TE1.TASK_EXECUTION_ID = TE2.TASK_EXECUTION_ID "
"group by TE.TASK_NAME, TE.START_TIME" + + "order by TE2.START_TIME DESC, TE2.TASK_EXECUTION_ID DESC";
") TE1 " +
"inner join %PREFIX%EXECUTION TE2 ON TE1.TASK_EXECUTION_ID = TE2.TASK_EXECUTION_ID " +
"order by TE2.START_TIME DESC, TE2.TASK_EXECUTION_ID DESC";
private static final String FIND_TASK_NAMES = "SELECT distinct TASK_NAME from %PREFIX%EXECUTION order by TASK_NAME"; private static final String FIND_TASK_NAMES = "SELECT distinct TASK_NAME from %PREFIX%EXECUTION order by TASK_NAME";
private static final String FIND_TASK_EXECUTION_BY_JOB_EXECUTION_ID = "SELECT TASK_EXECUTION_ID FROM %PREFIX%TASK_BATCH WHERE JOB_EXECUTION_ID = :jobExecutionId"; private static final String FIND_TASK_EXECUTION_BY_JOB_EXECUTION_ID = "SELECT TASK_EXECUTION_ID FROM "
+ "%PREFIX%TASK_BATCH WHERE JOB_EXECUTION_ID = :jobExecutionId";
private static final String FIND_JOB_EXECUTION_BY_TASK_EXECUTION_ID = "SELECT JOB_EXECUTION_ID FROM %PREFIX%TASK_BATCH WHERE TASK_EXECUTION_ID = :taskExecutionId"; private static final String FIND_JOB_EXECUTION_BY_TASK_EXECUTION_ID = "SELECT JOB_EXECUTION_ID "
+ "FROM %PREFIX%TASK_BATCH WHERE TASK_EXECUTION_ID = :taskExecutionId";
private String tablePrefix = TaskProperties.DEFAULT_TABLE_PREFIX;
private final NamedParameterJdbcTemplate jdbcTemplate; private final NamedParameterJdbcTemplate jdbcTemplate;
private String tablePrefix = TaskProperties.DEFAULT_TABLE_PREFIX;
private DataSource dataSource; private DataSource dataSource;
private LinkedHashMap<String, Order> orderMap; private LinkedHashMap<String, Order> orderMap;
@@ -169,120 +181,119 @@ public class JdbcTaskExecutionDao implements TaskExecutionDao {
Assert.notNull(dataSource, "The dataSource must not be null."); Assert.notNull(dataSource, "The dataSource must not be null.");
this.jdbcTemplate = new NamedParameterJdbcTemplate(dataSource); this.jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
this.dataSource = dataSource; this.dataSource = dataSource;
orderMap = new LinkedHashMap<>(); this.orderMap = new LinkedHashMap<>();
orderMap.put("START_TIME", Order.DESCENDING); this.orderMap.put("START_TIME", Order.DESCENDING);
orderMap.put("TASK_EXECUTION_ID", Order.DESCENDING); this.orderMap.put("TASK_EXECUTION_ID", Order.DESCENDING);
}
@Override
public TaskExecution createTaskExecution(String taskName,
Date startTime, List<String> arguments, String externalExecutionId) {
return createTaskExecution(taskName, startTime, arguments,
externalExecutionId, null);
} }
@Override @Override
public TaskExecution createTaskExecution(String taskName, Date startTime, public TaskExecution createTaskExecution(String taskName, Date startTime,
List<String> arguments, String externalExecutionId, List<String> arguments, String externalExecutionId) {
Long parentExecutionId) { return createTaskExecution(taskName, startTime, arguments, externalExecutionId,
null);
}
@Override
public TaskExecution createTaskExecution(String taskName, Date startTime,
List<String> arguments, String externalExecutionId, Long parentExecutionId) {
long nextExecutionId = getNextExecutionId(); long nextExecutionId = getNextExecutionId();
TaskExecution taskExecution = new TaskExecution(nextExecutionId, null, taskName, TaskExecution taskExecution = new TaskExecution(nextExecutionId, null, taskName,
startTime, null, null, arguments, null, externalExecutionId); startTime, null, null, arguments, null, externalExecutionId);
final MapSqlParameterSource queryParameters = new MapSqlParameterSource() final MapSqlParameterSource queryParameters = new MapSqlParameterSource()
.addValue("taskExecutionId", nextExecutionId, Types.BIGINT) .addValue("taskExecutionId", nextExecutionId, Types.BIGINT)
.addValue("exitCode", null, Types.INTEGER) .addValue("exitCode", null, Types.INTEGER)
.addValue("startTime", startTime, Types.TIMESTAMP) .addValue("startTime", startTime, Types.TIMESTAMP)
.addValue("taskName", taskName, Types.VARCHAR) .addValue("taskName", taskName, Types.VARCHAR)
.addValue("lastUpdated", new Date(), Types.TIMESTAMP) .addValue("lastUpdated", new Date(), Types.TIMESTAMP)
.addValue("externalExecutionId", externalExecutionId, Types.VARCHAR) .addValue("externalExecutionId", externalExecutionId, Types.VARCHAR)
.addValue("parentExecutionId", parentExecutionId, Types.BIGINT); .addValue("parentExecutionId", parentExecutionId, Types.BIGINT);
jdbcTemplate.update( this.jdbcTemplate.update(getQuery(SAVE_TASK_EXECUTION), queryParameters);
getQuery(SAVE_TASK_EXECUTION),
queryParameters);
insertTaskArguments(nextExecutionId, arguments); insertTaskArguments(nextExecutionId, arguments);
return taskExecution; return taskExecution;
} }
@Override @Override
public TaskExecution startTaskExecution(long executionId, String taskName, public TaskExecution startTaskExecution(long executionId, String taskName,
Date startTime, List<String> arguments, Date startTime, List<String> arguments, String externalExecutionId) {
String externalExecutionId) {
return startTaskExecution(executionId, taskName, startTime, arguments, return startTaskExecution(executionId, taskName, startTime, arguments,
externalExecutionId, null); externalExecutionId, null);
} }
@Override @Override
public TaskExecution startTaskExecution(long executionId, String taskName, public TaskExecution startTaskExecution(long executionId, String taskName,
Date startTime, List<String> arguments, Date startTime, List<String> arguments, String externalExecutionId,
String externalExecutionId, Long parentExecutionId) { Long parentExecutionId) {
TaskExecution taskExecution = new TaskExecution(executionId, null, taskName, TaskExecution taskExecution = new TaskExecution(executionId, null, taskName,
startTime, null, null, arguments,null, externalExecutionId, parentExecutionId); startTime, null, null, arguments, null, externalExecutionId,
parentExecutionId);
final MapSqlParameterSource queryParameters = new MapSqlParameterSource() final MapSqlParameterSource queryParameters = new MapSqlParameterSource()
.addValue("startTime", startTime, Types.TIMESTAMP) .addValue("startTime", startTime, Types.TIMESTAMP)
.addValue("exitCode", null, Types.INTEGER) .addValue("exitCode", null, Types.INTEGER)
.addValue("taskName", taskName, Types.VARCHAR) .addValue("taskName", taskName, Types.VARCHAR)
.addValue("lastUpdated", new Date(), Types.TIMESTAMP) .addValue("lastUpdated", new Date(), Types.TIMESTAMP)
.addValue("parentExecutionId", parentExecutionId, Types.BIGINT) .addValue("parentExecutionId", parentExecutionId, Types.BIGINT)
.addValue("taskExecutionId", executionId, Types.BIGINT); .addValue("taskExecutionId", executionId, Types.BIGINT);
String updateString = START_TASK_EXECUTION_PREFIX; String updateString = START_TASK_EXECUTION_PREFIX;
if(externalExecutionId == null) { if (externalExecutionId == null) {
updateString += START_TASK_EXECUTION_SUFFIX; updateString += START_TASK_EXECUTION_SUFFIX;
} }
else { else {
updateString += START_TASK_EXECUTION_EXTERNAL_ID_SUFFIX; updateString += START_TASK_EXECUTION_EXTERNAL_ID_SUFFIX;
queryParameters.addValue("externalExecutionId", externalExecutionId, Types.VARCHAR); queryParameters.addValue("externalExecutionId", externalExecutionId,
Types.VARCHAR);
} }
jdbcTemplate.update(getQuery(updateString), queryParameters); this.jdbcTemplate.update(getQuery(updateString), queryParameters);
insertTaskArguments(executionId, arguments); insertTaskArguments(executionId, arguments);
return taskExecution; return taskExecution;
} }
@Override @Override
public void completeTaskExecution(long taskExecutionId, Integer exitCode, Date endTime, public void completeTaskExecution(long taskExecutionId, Integer exitCode,
String exitMessage, String errorMessage) { Date endTime, String exitMessage, String errorMessage) {
final MapSqlParameterSource queryParameters = new MapSqlParameterSource() final MapSqlParameterSource queryParameters = new MapSqlParameterSource()
.addValue("taskExecutionId", taskExecutionId, Types.BIGINT); .addValue("taskExecutionId", taskExecutionId, Types.BIGINT);
// Check if given TaskExecution's Id already exists, if none is found // Check if given TaskExecution's Id already exists, if none is found
// it is invalid and an exception should be thrown. // it is invalid and an exception should be thrown.
if (jdbcTemplate.queryForObject(getQuery(CHECK_TASK_EXECUTION_EXISTS), queryParameters, Integer.class) != 1) { if (this.jdbcTemplate.queryForObject(getQuery(CHECK_TASK_EXECUTION_EXISTS),
throw new IllegalStateException("Invalid TaskExecution, ID " + taskExecutionId + " not found."); queryParameters, Integer.class) != 1) {
throw new IllegalStateException(
"Invalid TaskExecution, ID " + taskExecutionId + " not found.");
} }
final MapSqlParameterSource parameters = new MapSqlParameterSource() final MapSqlParameterSource parameters = new MapSqlParameterSource()
.addValue("endTime", endTime, Types.TIMESTAMP) .addValue("endTime", endTime, Types.TIMESTAMP)
.addValue("exitCode", exitCode, Types.INTEGER) .addValue("exitCode", exitCode, Types.INTEGER)
.addValue("exitMessage", exitMessage, Types.VARCHAR) .addValue("exitMessage", exitMessage, Types.VARCHAR)
.addValue("errorMessage", errorMessage, Types.VARCHAR) .addValue("errorMessage", errorMessage, Types.VARCHAR)
.addValue("lastUpdated", new Date(), Types.TIMESTAMP) .addValue("lastUpdated", new Date(), Types.TIMESTAMP)
.addValue("taskExecutionId", taskExecutionId, Types.BIGINT); .addValue("taskExecutionId", taskExecutionId, Types.BIGINT);
jdbcTemplate.update( this.jdbcTemplate.update(getQuery(UPDATE_TASK_EXECUTION), parameters);
getQuery(UPDATE_TASK_EXECUTION),
parameters);
} }
@Override @Override
public void completeTaskExecution(long taskExecutionId, Integer exitCode, Date endTime, public void completeTaskExecution(long taskExecutionId, Integer exitCode,
String exitMessage) { Date endTime, String exitMessage) {
completeTaskExecution(taskExecutionId, exitCode, endTime, exitMessage, null); completeTaskExecution(taskExecutionId, exitCode, endTime, exitMessage, null);
} }
@Override @Override
public TaskExecution getTaskExecution(long executionId) { public TaskExecution getTaskExecution(long executionId) {
final MapSqlParameterSource queryParameters = new MapSqlParameterSource() final MapSqlParameterSource queryParameters = new MapSqlParameterSource()
.addValue("taskExecutionId", executionId, Types.BIGINT); .addValue("taskExecutionId", executionId, Types.BIGINT);
try { try {
TaskExecution taskExecution = jdbcTemplate.queryForObject(getQuery(GET_EXECUTION_BY_ID), TaskExecution taskExecution = this.jdbcTemplate.queryForObject(
queryParameters, new TaskExecutionRowMapper()); getQuery(GET_EXECUTION_BY_ID), queryParameters,
new TaskExecutionRowMapper());
taskExecution.setArguments(getTaskArguments(executionId)); taskExecution.setArguments(getTaskArguments(executionId));
return taskExecution; return taskExecution;
} }
@@ -295,11 +306,11 @@ public class JdbcTaskExecutionDao implements TaskExecutionDao {
public long getTaskExecutionCountByTaskName(String taskName) { public long getTaskExecutionCountByTaskName(String taskName) {
final MapSqlParameterSource queryParameters = new MapSqlParameterSource() final MapSqlParameterSource queryParameters = new MapSqlParameterSource()
.addValue("taskName", taskName, Types.VARCHAR); .addValue("taskName", taskName, Types.VARCHAR);
try { try {
return jdbcTemplate.queryForObject( return this.jdbcTemplate.queryForObject(
getQuery(TASK_EXECUTION_COUNT_BY_NAME), queryParameters, Long.class); getQuery(TASK_EXECUTION_COUNT_BY_NAME), queryParameters, Long.class);
} }
catch (EmptyResultDataAccessException e) { catch (EmptyResultDataAccessException e) {
return 0; return 0;
@@ -309,11 +320,12 @@ public class JdbcTaskExecutionDao implements TaskExecutionDao {
@Override @Override
public long getRunningTaskExecutionCountByTaskName(String taskName) { public long getRunningTaskExecutionCountByTaskName(String taskName) {
final MapSqlParameterSource queryParameters = new MapSqlParameterSource() final MapSqlParameterSource queryParameters = new MapSqlParameterSource()
.addValue("taskName", taskName, Types.VARCHAR); .addValue("taskName", taskName, Types.VARCHAR);
try { try {
return jdbcTemplate.queryForObject( return this.jdbcTemplate.queryForObject(
getQuery(RUNNING_TASK_EXECUTION_COUNT_BY_NAME), queryParameters, Long.class); getQuery(RUNNING_TASK_EXECUTION_COUNT_BY_NAME), queryParameters,
Long.class);
} }
catch (EmptyResultDataAccessException e) { catch (EmptyResultDataAccessException e) {
return 0; return 0;
@@ -325,8 +337,8 @@ public class JdbcTaskExecutionDao implements TaskExecutionDao {
try { try {
final MapSqlParameterSource queryParameters = new MapSqlParameterSource(); final MapSqlParameterSource queryParameters = new MapSqlParameterSource();
return jdbcTemplate.queryForObject( return this.jdbcTemplate.queryForObject(
getQuery(RUNNING_TASK_EXECUTION_COUNT), queryParameters, Long.class); getQuery(RUNNING_TASK_EXECUTION_COUNT), queryParameters, Long.class);
} }
catch (EmptyResultDataAccessException e) { catch (EmptyResultDataAccessException e) {
return 0; return 0;
@@ -345,14 +357,15 @@ public class JdbcTaskExecutionDao implements TaskExecutionDao {
} }
} }
Assert.isTrue(taskNamesAsList.size() == taskNames.length, Assert.isTrue(taskNamesAsList.size() == taskNames.length, String.format(
String.format("Task names must not contain any empty elements but %s of %s were empty or null.", "Task names must not contain any empty elements but %s of %s were empty or null.",
taskNames.length - taskNamesAsList.size(), taskNames.length)); taskNames.length - taskNamesAsList.size(), taskNames.length));
try { try {
final Map<String, List<String>> paramMap = Collections.singletonMap("taskNames", taskNamesAsList); final Map<String, List<String>> paramMap = Collections
return this.jdbcTemplate.query( .singletonMap("taskNames", taskNamesAsList);
getQuery(LAST_TASK_EXECUTIONS_BY_TASK_NAMES), paramMap, new TaskExecutionRowMapper()); return this.jdbcTemplate.query(getQuery(LAST_TASK_EXECUTIONS_BY_TASK_NAMES),
paramMap, new TaskExecutionRowMapper());
} }
catch (EmptyResultDataAccessException e) { catch (EmptyResultDataAccessException e) {
return Collections.emptyList(); return Collections.emptyList();
@@ -362,7 +375,8 @@ public class JdbcTaskExecutionDao implements TaskExecutionDao {
@Override @Override
public TaskExecution getLatestTaskExecutionForTaskName(String taskName) { public TaskExecution getLatestTaskExecutionForTaskName(String taskName) {
Assert.hasText(taskName, "The task name must not be empty."); Assert.hasText(taskName, "The task name must not be empty.");
final List<TaskExecution> taskExecutions = this.getLatestTaskExecutionsByTaskNames(taskName); final List<TaskExecution> taskExecutions = this
.getLatestTaskExecutionsByTaskNames(taskName);
if (taskExecutions.isEmpty()) { if (taskExecutions.isEmpty()) {
return null; return null;
} }
@@ -370,7 +384,9 @@ public class JdbcTaskExecutionDao implements TaskExecutionDao {
return taskExecutions.get(0); return taskExecutions.get(0);
} }
else { else {
throw new IllegalStateException("Only expected a single TaskExecution but received " + taskExecutions.size()); throw new IllegalStateException(
"Only expected a single TaskExecution but received "
+ taskExecutions.size());
} }
} }
@@ -378,8 +394,8 @@ public class JdbcTaskExecutionDao implements TaskExecutionDao {
public long getTaskExecutionCount() { public long getTaskExecutionCount() {
try { try {
return jdbcTemplate.queryForObject( return this.jdbcTemplate.queryForObject(getQuery(TASK_EXECUTION_COUNT),
getQuery(TASK_EXECUTION_COUNT), new MapSqlParameterSource(), Long.class); new MapSqlParameterSource(), Long.class);
} }
catch (EmptyResultDataAccessException e) { catch (EmptyResultDataAccessException e) {
return 0; return 0;
@@ -387,14 +403,17 @@ public class JdbcTaskExecutionDao implements TaskExecutionDao {
} }
@Override @Override
public Page<TaskExecution> findRunningTaskExecutions(String taskName, Pageable pageable) { public Page<TaskExecution> findRunningTaskExecutions(String taskName,
Pageable pageable) {
return queryForPageableResults(pageable, SELECT_CLAUSE, FROM_CLAUSE, return queryForPageableResults(pageable, SELECT_CLAUSE, FROM_CLAUSE,
RUNNING_TASK_WHERE_CLAUSE, new MapSqlParameterSource("taskName", taskName), RUNNING_TASK_WHERE_CLAUSE,
new MapSqlParameterSource("taskName", taskName),
getRunningTaskExecutionCountByTaskName(taskName)); getRunningTaskExecutionCountByTaskName(taskName));
} }
@Override @Override
public Page<TaskExecution> findTaskExecutionsByName(String taskName, Pageable pageable) { public Page<TaskExecution> findTaskExecutionsByName(String taskName,
Pageable pageable) {
return queryForPageableResults(pageable, SELECT_CLAUSE, FROM_CLAUSE, return queryForPageableResults(pageable, SELECT_CLAUSE, FROM_CLAUSE,
TASK_NAME_WHERE_CLAUSE, new MapSqlParameterSource("taskName", taskName), TASK_NAME_WHERE_CLAUSE, new MapSqlParameterSource("taskName", taskName),
getTaskExecutionCountByTaskName(taskName)); getTaskExecutionCountByTaskName(taskName));
@@ -402,7 +421,8 @@ public class JdbcTaskExecutionDao implements TaskExecutionDao {
@Override @Override
public List<String> getTaskNames() { public List<String> getTaskNames() {
return jdbcTemplate.queryForList(getQuery(FIND_TASK_NAMES), new MapSqlParameterSource(), String.class); return this.jdbcTemplate.queryForList(getQuery(FIND_TASK_NAMES),
new MapSqlParameterSource(), String.class);
} }
@Override @Override
@@ -415,19 +435,18 @@ public class JdbcTaskExecutionDao implements TaskExecutionDao {
this.taskIncrementer = taskIncrementer; this.taskIncrementer = taskIncrementer;
} }
public long getNextExecutionId(){ public long getNextExecutionId() {
return taskIncrementer.nextLongValue(); return this.taskIncrementer.nextLongValue();
} }
@Override @Override
public Long getTaskExecutionIdByJobExecutionId(long jobExecutionId) { public Long getTaskExecutionIdByJobExecutionId(long jobExecutionId) {
final MapSqlParameterSource queryParameters = new MapSqlParameterSource() final MapSqlParameterSource queryParameters = new MapSqlParameterSource()
.addValue("jobExecutionId", jobExecutionId, Types.BIGINT); .addValue("jobExecutionId", jobExecutionId, Types.BIGINT);
try { try {
return jdbcTemplate.queryForObject( return this.jdbcTemplate.queryForObject(
getQuery(FIND_TASK_EXECUTION_BY_JOB_EXECUTION_ID), getQuery(FIND_TASK_EXECUTION_BY_JOB_EXECUTION_ID), queryParameters,
queryParameters,
Long.class); Long.class);
} }
catch (EmptyResultDataAccessException e) { catch (EmptyResultDataAccessException e) {
@@ -438,19 +457,20 @@ public class JdbcTaskExecutionDao implements TaskExecutionDao {
@Override @Override
public Set<Long> getJobExecutionIdsByTaskExecutionId(long taskExecutionId) { public Set<Long> getJobExecutionIdsByTaskExecutionId(long taskExecutionId) {
final MapSqlParameterSource queryParameters = new MapSqlParameterSource() final MapSqlParameterSource queryParameters = new MapSqlParameterSource()
.addValue("taskExecutionId", taskExecutionId, Types.BIGINT); .addValue("taskExecutionId", taskExecutionId, Types.BIGINT);
try { try {
return jdbcTemplate.query( return this.jdbcTemplate.query(
getQuery(FIND_JOB_EXECUTION_BY_TASK_EXECUTION_ID), getQuery(FIND_JOB_EXECUTION_BY_TASK_EXECUTION_ID), queryParameters,
queryParameters,
new ResultSetExtractor<Set<Long>>() { new ResultSetExtractor<Set<Long>>() {
@Override @Override
public Set<Long> extractData(ResultSet resultSet) throws SQLException, DataAccessException { public Set<Long> extractData(ResultSet resultSet)
throws SQLException, DataAccessException {
Set<Long> jobExecutionIds = new TreeSet<>(); Set<Long> jobExecutionIds = new TreeSet<>();
while(resultSet.next()) { while (resultSet.next()) {
jobExecutionIds.add(resultSet.getLong("JOB_EXECUTION_ID")); jobExecutionIds
.add(resultSet.getLong("JOB_EXECUTION_ID"));
} }
return jobExecutionIds; return jobExecutionIds;
@@ -463,29 +483,27 @@ public class JdbcTaskExecutionDao implements TaskExecutionDao {
} }
@Override @Override
public void updateExternalExecutionId(long taskExecutionId, String externalExecutionId) { public void updateExternalExecutionId(long taskExecutionId,
String externalExecutionId) {
final MapSqlParameterSource queryParameters = new MapSqlParameterSource() final MapSqlParameterSource queryParameters = new MapSqlParameterSource()
.addValue("externalExecutionId", externalExecutionId, Types.VARCHAR) .addValue("externalExecutionId", externalExecutionId, Types.VARCHAR)
.addValue("taskExecutionId", taskExecutionId, Types.BIGINT); .addValue("taskExecutionId", taskExecutionId, Types.BIGINT);
if (jdbcTemplate.update( if (this.jdbcTemplate.update(
getQuery(UPDATE_TASK_EXECUTION_EXTERNAL_EXECUTION_ID), getQuery(UPDATE_TASK_EXECUTION_EXTERNAL_EXECUTION_ID),
queryParameters) != 1) { queryParameters) != 1) {
throw new IllegalStateException("Invalid TaskExecution, ID " throw new IllegalStateException(
+ taskExecutionId + " not found."); "Invalid TaskExecution, ID " + taskExecutionId + " not found.");
} }
} }
private Page<TaskExecution> queryForPageableResults(Pageable pageable, private Page<TaskExecution> queryForPageableResults(Pageable pageable,
String selectClause, String selectClause, String fromClause, String whereClause,
String fromClause, MapSqlParameterSource queryParameters, long totalCount) {
String whereClause,
MapSqlParameterSource queryParameters,
long totalCount){
SqlPagingQueryProviderFactoryBean factoryBean = new SqlPagingQueryProviderFactoryBean(); SqlPagingQueryProviderFactoryBean factoryBean = new SqlPagingQueryProviderFactoryBean();
factoryBean.setSelectClause(selectClause); factoryBean.setSelectClause(selectClause);
factoryBean.setFromClause(fromClause); factoryBean.setFromClause(fromClause);
if(StringUtils.hasText(whereClause)){ if (StringUtils.hasText(whereClause)) {
factoryBean.setWhereClause(whereClause); factoryBean.setWhereClause(whereClause);
} }
final Sort sort = pageable.getSort(); final Sort sort = pageable.getSort();
@@ -493,7 +511,8 @@ public class JdbcTaskExecutionDao implements TaskExecutionDao {
if (sort != null) { if (sort != null) {
for (Sort.Order sortOrder : sort) { for (Sort.Order sortOrder : sort) {
sortOrderMap.put(sortOrder.getProperty(), sortOrder.isAscending() ? Order.ASCENDING : Order.DESCENDING); sortOrderMap.put(sortOrder.getProperty(),
sortOrder.isAscending() ? Order.ASCENDING : Order.DESCENDING);
} }
} }
@@ -508,29 +527,25 @@ public class JdbcTaskExecutionDao implements TaskExecutionDao {
PagingQueryProvider pagingQueryProvider; PagingQueryProvider pagingQueryProvider;
try { try {
pagingQueryProvider = factoryBean.getObject(); pagingQueryProvider = factoryBean.getObject();
pagingQueryProvider.init(dataSource); pagingQueryProvider.init(this.dataSource);
} }
catch (Exception e) { catch (Exception e) {
throw new IllegalStateException(e); throw new IllegalStateException(e);
} }
String query = pagingQueryProvider.getPageQuery(pageable); String query = pagingQueryProvider.getPageQuery(pageable);
List<TaskExecution> resultList = jdbcTemplate.query( List<TaskExecution> resultList = this.jdbcTemplate.query(getQuery(query),
getQuery(query), queryParameters, new TaskExecutionRowMapper());
queryParameters,
new TaskExecutionRowMapper());
return new PageImpl<>(resultList, pageable, totalCount); return new PageImpl<>(resultList, pageable, totalCount);
} }
private String getQuery(String base) { private String getQuery(String base) {
return StringUtils.replace(base, "%PREFIX%", tablePrefix); return StringUtils.replace(base, "%PREFIX%", this.tablePrefix);
} }
/** /**
* Convenience method that inserts all arguments from the provided * Convenience method that inserts all arguments from the provided task arguments.
* task arguments. * @param executionId The executionId to which the arguments are associated.
* * @param taskArguments The arguments to be stored.
* @param executionId The executionId to which the arguments are associated.
* @param taskArguments The arguments to be stored.
*/ */
private void insertTaskArguments(long executionId, List<String> taskArguments) { private void insertTaskArguments(long executionId, List<String> taskArguments) {
for (String args : taskArguments) { for (String args : taskArguments) {
@@ -541,26 +556,29 @@ public class JdbcTaskExecutionDao implements TaskExecutionDao {
/** /**
* Convenience method that inserts an individual records into the * Convenience method that inserts an individual records into the
* TASK_EXECUTION_PARAMS table. * TASK_EXECUTION_PARAMS table.
* @param taskExecutionId id of a task execution
* @param taskParam task parameters
*/ */
private void insertArgument(long taskExecutionId, String taskParam) { private void insertArgument(long taskExecutionId, String taskParam) {
final MapSqlParameterSource queryParameters = new MapSqlParameterSource() final MapSqlParameterSource queryParameters = new MapSqlParameterSource()
.addValue("taskExecutionId", taskExecutionId, Types.BIGINT) .addValue("taskExecutionId", taskExecutionId, Types.BIGINT)
.addValue("taskParam", taskParam, Types.VARCHAR); .addValue("taskParam", taskParam, Types.VARCHAR);
jdbcTemplate.update(getQuery(CREATE_TASK_ARGUMENT), queryParameters); this.jdbcTemplate.update(getQuery(CREATE_TASK_ARGUMENT), queryParameters);
} }
private List<String> getTaskArguments(long taskExecutionId){ private List<String> getTaskArguments(long taskExecutionId) {
final List<String> params= new ArrayList<>(); final List<String> params = new ArrayList<>();
RowCallbackHandler handler = new RowCallbackHandler() { RowCallbackHandler handler = new RowCallbackHandler() {
@Override @Override
public void processRow(ResultSet rs) throws SQLException { public void processRow(ResultSet rs) throws SQLException {
params.add(rs.getString(2)); params.add(rs.getString(2));
} }
}; };
jdbcTemplate.query(getQuery(FIND_ARGUMENT_FROM_ID), new MapSqlParameterSource("taskExecutionId", taskExecutionId), this.jdbcTemplate.query(getQuery(FIND_ARGUMENT_FROM_ID),
handler); new MapSqlParameterSource("taskExecutionId", taskExecutionId), handler);
return params; return params;
} }
/** /**
* Re-usable mapper for {@link TaskExecution} instances. * Re-usable mapper for {@link TaskExecution} instances.
* *
@@ -572,26 +590,23 @@ public class JdbcTaskExecutionDao implements TaskExecutionDao {
@Override @Override
public TaskExecution mapRow(ResultSet rs, int rowNum) throws SQLException { public TaskExecution mapRow(ResultSet rs, int rowNum) throws SQLException {
long id = rs.getLong("TASK_EXECUTION_ID"); long id = rs.getLong("TASK_EXECUTION_ID");
Long parentExecutionId = rs.getLong("PARENT_EXECUTION_ID"); Long parentExecutionId = rs.getLong("PARENT_EXECUTION_ID");
if(rs.wasNull()) { if (rs.wasNull()) {
parentExecutionId = null; parentExecutionId = null;
} }
return new TaskExecution(id, return new TaskExecution(id, getNullableExitCode(rs),
getNullableExitCode(rs), rs.getString("TASK_NAME"), rs.getTimestamp("START_TIME"),
rs.getString("TASK_NAME"), rs.getTimestamp("END_TIME"), rs.getString("EXIT_MESSAGE"),
rs.getTimestamp("START_TIME"), getTaskArguments(id), rs.getString("ERROR_MESSAGE"),
rs.getTimestamp("END_TIME"), rs.getString("EXTERNAL_EXECUTION_ID"), parentExecutionId);
rs.getString("EXIT_MESSAGE"),
getTaskArguments(id),
rs.getString("ERROR_MESSAGE"),
rs.getString("EXTERNAL_EXECUTION_ID"),
parentExecutionId);
} }
private Integer getNullableExitCode(ResultSet rs) throws SQLException { private Integer getNullableExitCode(ResultSet rs) throws SQLException {
int exitCode = rs.getInt("EXIT_CODE"); int exitCode = rs.getInt("EXIT_CODE");
return !rs.wasNull() ? exitCode : null; return !rs.wasNull() ? exitCode : null;
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -46,36 +46,38 @@ import org.springframework.util.StringUtils;
*/ */
public class MapTaskExecutionDao implements TaskExecutionDao { public class MapTaskExecutionDao implements TaskExecutionDao {
private final AtomicLong currentId = new AtomicLong(0L);
private ConcurrentMap<Long, TaskExecution> taskExecutions; private ConcurrentMap<Long, TaskExecution> taskExecutions;
private ConcurrentMap<Long, Set<Long>> batchJobAssociations; private ConcurrentMap<Long, Set<Long>> batchJobAssociations;
private final AtomicLong currentId = new AtomicLong(0L);
public MapTaskExecutionDao() { public MapTaskExecutionDao() {
taskExecutions = new ConcurrentHashMap<>(); this.taskExecutions = new ConcurrentHashMap<>();
batchJobAssociations = new ConcurrentHashMap<>(); this.batchJobAssociations = new ConcurrentHashMap<>();
} }
@Override @Override
public TaskExecution createTaskExecution(String taskName, public TaskExecution createTaskExecution(String taskName, Date startTime,
Date startTime, List<String> arguments, String externalExecutionId) { List<String> arguments, String externalExecutionId) {
return createTaskExecution(taskName, startTime, arguments, return createTaskExecution(taskName, startTime, arguments, externalExecutionId,
externalExecutionId, null); null);
} }
@Override @Override
public TaskExecution createTaskExecution(String taskName, Date startTime, List<String> arguments, String externalExecutionId, Long parentExecutionId) { public TaskExecution createTaskExecution(String taskName, Date startTime,
List<String> arguments, String externalExecutionId, Long parentExecutionId) {
long taskExecutionId = getNextExecutionId(); long taskExecutionId = getNextExecutionId();
TaskExecution taskExecution = new TaskExecution(taskExecutionId, null, taskName, TaskExecution taskExecution = new TaskExecution(taskExecutionId, null, taskName,
startTime, null, null, arguments, null, externalExecutionId, parentExecutionId); startTime, null, null, arguments, null, externalExecutionId,
taskExecutions.put(taskExecutionId, taskExecution); parentExecutionId);
this.taskExecutions.put(taskExecutionId, taskExecution);
return taskExecution; return taskExecution;
} }
@Override @Override
public TaskExecution startTaskExecution(long executionId, String taskName, Date startTime, List<String> arguments, public TaskExecution startTaskExecution(long executionId, String taskName,
String externalExecutionid) { Date startTime, List<String> arguments, String externalExecutionid) {
return startTaskExecution(executionId, taskName, startTime, arguments, return startTaskExecution(executionId, taskName, startTime, arguments,
externalExecutionid, null); externalExecutionid, null);
} }
@@ -84,24 +86,26 @@ public class MapTaskExecutionDao implements TaskExecutionDao {
public TaskExecution startTaskExecution(long executionId, String taskName, public TaskExecution startTaskExecution(long executionId, String taskName,
Date startTime, List<String> arguments, String externalExecutionid, Date startTime, List<String> arguments, String externalExecutionid,
Long parentExecutionId) { Long parentExecutionId) {
TaskExecution taskExecution= taskExecutions.get(executionId); TaskExecution taskExecution = this.taskExecutions.get(executionId);
taskExecution.setTaskName(taskName); taskExecution.setTaskName(taskName);
taskExecution.setStartTime(startTime); taskExecution.setStartTime(startTime);
taskExecution.setArguments(arguments); taskExecution.setArguments(arguments);
taskExecution.setParentExecutionId(parentExecutionId); taskExecution.setParentExecutionId(parentExecutionId);
if(externalExecutionid != null) { if (externalExecutionid != null) {
taskExecution.setExternalExecutionId(externalExecutionid); taskExecution.setExternalExecutionId(externalExecutionid);
} }
return taskExecution; return taskExecution;
} }
@Override @Override
public void completeTaskExecution(long executionId, Integer exitCode, Date endTime, String exitMessage, String errorMessage) { public void completeTaskExecution(long executionId, Integer exitCode, Date endTime,
if(!this.taskExecutions.containsKey(executionId)) { String exitMessage, String errorMessage) {
throw new IllegalStateException("Invalid TaskExecution, ID " + executionId + " not found."); if (!this.taskExecutions.containsKey(executionId)) {
throw new IllegalStateException(
"Invalid TaskExecution, ID " + executionId + " not found.");
} }
TaskExecution taskExecution= taskExecutions.get(executionId); TaskExecution taskExecution = this.taskExecutions.get(executionId);
taskExecution.setEndTime(endTime); taskExecution.setEndTime(endTime);
taskExecution.setExitCode(exitCode); taskExecution.setExitCode(exitCode);
taskExecution.setExitMessage(exitMessage); taskExecution.setExitMessage(exitMessage);
@@ -109,19 +113,20 @@ public class MapTaskExecutionDao implements TaskExecutionDao {
} }
@Override @Override
public void completeTaskExecution(long executionId, Integer exitCode, Date endTime, String exitMessage) { public void completeTaskExecution(long executionId, Integer exitCode, Date endTime,
String exitMessage) {
completeTaskExecution(executionId, exitCode, endTime, exitMessage, null); completeTaskExecution(executionId, exitCode, endTime, exitMessage, null);
} }
@Override @Override
public TaskExecution getTaskExecution(long executionId) { public TaskExecution getTaskExecution(long executionId) {
return taskExecutions.get(executionId); return this.taskExecutions.get(executionId);
} }
@Override @Override
public long getTaskExecutionCountByTaskName(String taskName) { public long getTaskExecutionCountByTaskName(String taskName) {
int count = 0; int count = 0;
for (Map.Entry<Long, TaskExecution> entry : taskExecutions.entrySet()) { for (Map.Entry<Long, TaskExecution> entry : this.taskExecutions.entrySet()) {
if (entry.getValue().getTaskName().equals(taskName)) { if (entry.getValue().getTaskName().equals(taskName)) {
count++; count++;
} }
@@ -132,9 +137,9 @@ public class MapTaskExecutionDao implements TaskExecutionDao {
@Override @Override
public long getRunningTaskExecutionCountByTaskName(String taskName) { public long getRunningTaskExecutionCountByTaskName(String taskName) {
int count = 0; int count = 0;
for (Map.Entry<Long, TaskExecution> entry : taskExecutions.entrySet()) { for (Map.Entry<Long, TaskExecution> entry : this.taskExecutions.entrySet()) {
if (entry.getValue().getTaskName().equals(taskName) && if (entry.getValue().getTaskName().equals(taskName)
entry.getValue().getEndTime() == null) { && entry.getValue().getEndTime() == null) {
count++; count++;
} }
} }
@@ -144,8 +149,8 @@ public class MapTaskExecutionDao implements TaskExecutionDao {
@Override @Override
public long getRunningTaskExecutionCount() { public long getRunningTaskExecutionCount() {
long count = 0; long count = 0;
for (Map.Entry<Long, TaskExecution> entry : taskExecutions.entrySet()) { for (Map.Entry<Long, TaskExecution> entry : this.taskExecutions.entrySet()) {
if ( entry.getValue().getEndTime() == null) { if (entry.getValue().getEndTime() == null) {
count++; count++;
} }
} }
@@ -154,15 +159,16 @@ public class MapTaskExecutionDao implements TaskExecutionDao {
@Override @Override
public long getTaskExecutionCount() { public long getTaskExecutionCount() {
return taskExecutions.size(); return this.taskExecutions.size();
} }
@Override @Override
public Page<TaskExecution> findRunningTaskExecutions(String taskName, Pageable pageable) { public Page<TaskExecution> findRunningTaskExecutions(String taskName,
Pageable pageable) {
Set<TaskExecution> result = getTaskExecutionTreeSet(); Set<TaskExecution> result = getTaskExecutionTreeSet();
for (Map.Entry<Long, TaskExecution> entry : taskExecutions.entrySet()) { for (Map.Entry<Long, TaskExecution> entry : this.taskExecutions.entrySet()) {
if (entry.getValue().getTaskName().equals(taskName) && if (entry.getValue().getTaskName().equals(taskName)
entry.getValue().getEndTime() == null) { && entry.getValue().getEndTime() == null) {
result.add(entry.getValue()); result.add(entry.getValue());
} }
} }
@@ -171,9 +177,10 @@ public class MapTaskExecutionDao implements TaskExecutionDao {
} }
@Override @Override
public Page<TaskExecution> findTaskExecutionsByName(String taskName, Pageable pageable) { public Page<TaskExecution> findTaskExecutionsByName(String taskName,
Pageable pageable) {
Set<TaskExecution> filteredSet = getTaskExecutionTreeSet(); Set<TaskExecution> filteredSet = getTaskExecutionTreeSet();
for (Map.Entry<Long, TaskExecution> entry : taskExecutions.entrySet()) { for (Map.Entry<Long, TaskExecution> entry : this.taskExecutions.entrySet()) {
if (entry.getValue().getTaskName().equals(taskName)) { if (entry.getValue().getTaskName().equals(taskName)) {
filteredSet.add(entry.getValue()); filteredSet.add(entry.getValue());
} }
@@ -185,7 +192,7 @@ public class MapTaskExecutionDao implements TaskExecutionDao {
@Override @Override
public List<String> getTaskNames() { public List<String> getTaskNames() {
Set<String> result = new TreeSet<>(); Set<String> result = new TreeSet<>();
for (Map.Entry<Long, TaskExecution> entry : taskExecutions.entrySet()) { for (Map.Entry<Long, TaskExecution> entry : this.taskExecutions.entrySet()) {
result.add(entry.getValue().getTaskName()); result.add(entry.getValue().getTaskName());
} }
return new ArrayList<>(result); return new ArrayList<>(result);
@@ -194,17 +201,17 @@ public class MapTaskExecutionDao implements TaskExecutionDao {
@Override @Override
public Page<TaskExecution> findAll(Pageable pageable) { public Page<TaskExecution> findAll(Pageable pageable) {
TreeSet<TaskExecution> sortedSet = getTaskExecutionTreeSet(); TreeSet<TaskExecution> sortedSet = getTaskExecutionTreeSet();
sortedSet.addAll(taskExecutions.values()); sortedSet.addAll(this.taskExecutions.values());
List<TaskExecution> result = new ArrayList<>(sortedSet.descendingSet()); List<TaskExecution> result = new ArrayList<>(sortedSet.descendingSet());
return getPageFromList(result, pageable, getTaskExecutionCount()); return getPageFromList(result, pageable, getTaskExecutionCount());
} }
public Map<Long, TaskExecution> getTaskExecutions() { public Map<Long, TaskExecution> getTaskExecutions() {
return Collections.unmodifiableMap(taskExecutions); return Collections.unmodifiableMap(this.taskExecutions);
} }
public long getNextExecutionId(){ public long getNextExecutionId() {
return currentId.getAndIncrement(); return this.currentId.getAndIncrement();
} }
@Override @Override
@@ -213,9 +220,10 @@ public class MapTaskExecutionDao implements TaskExecutionDao {
found: found:
for (Map.Entry<Long, Set<Long>> association : batchJobAssociations.entrySet()) { for (Map.Entry<Long, Set<Long>> association : this.batchJobAssociations
.entrySet()) {
for (Long curJobExecutionId : association.getValue()) { for (Long curJobExecutionId : association.getValue()) {
if(curJobExecutionId.equals(jobExecutionId)) { if (curJobExecutionId.equals(jobExecutionId)) {
taskId = association.getKey(); taskId = association.getKey();
break found; break found;
} }
@@ -227,8 +235,9 @@ public class MapTaskExecutionDao implements TaskExecutionDao {
@Override @Override
public Set<Long> getJobExecutionIdsByTaskExecutionId(long taskExecutionId) { public Set<Long> getJobExecutionIdsByTaskExecutionId(long taskExecutionId) {
if(batchJobAssociations.containsKey(taskExecutionId)) { if (this.batchJobAssociations.containsKey(taskExecutionId)) {
return Collections.unmodifiableSet(batchJobAssociations.get(taskExecutionId)); return Collections
.unmodifiableSet(this.batchJobAssociations.get(taskExecutionId));
} }
else { else {
return new TreeSet<>(); return new TreeSet<>();
@@ -236,15 +245,16 @@ public class MapTaskExecutionDao implements TaskExecutionDao {
} }
@Override @Override
public void updateExternalExecutionId(long taskExecutionId, String externalExecutionId) { public void updateExternalExecutionId(long taskExecutionId,
TaskExecution taskExecution = taskExecutions.get(taskExecutionId); String externalExecutionId) {
Assert.notNull(taskExecution, "Invalid TaskExecution, ID " TaskExecution taskExecution = this.taskExecutions.get(taskExecutionId);
+ taskExecutionId + " not found."); Assert.notNull(taskExecution,
"Invalid TaskExecution, ID " + taskExecutionId + " not found.");
taskExecution.setExternalExecutionId(externalExecutionId); taskExecution.setExternalExecutionId(externalExecutionId);
} }
public ConcurrentMap<Long, Set<Long>> getBatchJobAssociations() { public ConcurrentMap<Long, Set<Long>> getBatchJobAssociations() {
return batchJobAssociations; return this.batchJobAssociations;
} }
private TreeSet<TaskExecution> getTaskExecutionTreeSet() { private TreeSet<TaskExecution> getTaskExecutionTreeSet() {
@@ -252,19 +262,22 @@ public class MapTaskExecutionDao implements TaskExecutionDao {
@Override @Override
public int compare(TaskExecution e1, TaskExecution e2) { public int compare(TaskExecution e1, TaskExecution e2) {
int result = e1.getStartTime().compareTo(e2.getStartTime()); int result = e1.getStartTime().compareTo(e2.getStartTime());
if (result == 0){ if (result == 0) {
result = Long.valueOf(e1.getExecutionId()).compareTo(e2.getExecutionId()); result = Long.valueOf(e1.getExecutionId())
.compareTo(e2.getExecutionId());
} }
return result; return result;
} }
}); });
} }
private Page getPageFromList(List<TaskExecution> executionList, Pageable pageable, long maxSize){ private Page getPageFromList(List<TaskExecution> executionList, Pageable pageable,
long toIndex = (pageable.getOffset() + pageable.getPageSize() > executionList.size()) ? long maxSize) {
executionList.size() : pageable.getOffset() + pageable.getPageSize(); long toIndex = (pageable.getOffset() + pageable.getPageSize() > executionList
.size()) ? executionList.size()
: pageable.getOffset() + pageable.getPageSize();
return new PageImpl<>( return new PageImpl<>(
executionList.subList((int)pageable.getOffset(), (int)toIndex), executionList.subList((int) pageable.getOffset(), (int) toIndex),
pageable, maxSize); pageable, maxSize);
} }
@@ -281,29 +294,34 @@ public class MapTaskExecutionDao implements TaskExecutionDao {
} }
} }
Assert.isTrue(taskNamesAsList.size() == taskNames.length, Assert.isTrue(taskNamesAsList.size() == taskNames.length, String.format(
String.format("Task names must not contain any empty elements but %s of %s were empty or null.", "Task names must not contain any empty elements but %s of %s were empty or null.",
taskNames.length - taskNamesAsList.size(), taskNames.length)); taskNames.length - taskNamesAsList.size(), taskNames.length));
final Map<String, TaskExecution> tempTaskExecutions = new HashMap<>(); final Map<String, TaskExecution> tempTaskExecutions = new HashMap<>();
for (Map.Entry<Long, TaskExecution> taskExecutionMapEntry : this.taskExecutions.entrySet()) { for (Map.Entry<Long, TaskExecution> taskExecutionMapEntry : this.taskExecutions
if (!taskNamesAsList.contains(taskExecutionMapEntry.getValue().getTaskName())) { .entrySet()) {
if (!taskNamesAsList
.contains(taskExecutionMapEntry.getValue().getTaskName())) {
continue; continue;
} }
final TaskExecution tempTaskExecution = tempTaskExecutions.get(taskExecutionMapEntry.getValue().getTaskName()); final TaskExecution tempTaskExecution = tempTaskExecutions
.get(taskExecutionMapEntry.getValue().getTaskName());
if (tempTaskExecution == null if (tempTaskExecution == null
|| tempTaskExecution.getStartTime().before(taskExecutionMapEntry.getValue().getStartTime()) || tempTaskExecution.getStartTime()
|| ( .before(taskExecutionMapEntry.getValue().getStartTime())
tempTaskExecution.getStartTime().equals(taskExecutionMapEntry.getValue().getStartTime()) || (tempTaskExecution.getStartTime()
&& tempTaskExecution.getExecutionId() < taskExecutionMapEntry.getValue().getExecutionId() .equals(taskExecutionMapEntry.getValue().getStartTime())
) && tempTaskExecution.getExecutionId() < taskExecutionMapEntry
) { .getValue().getExecutionId())) {
tempTaskExecutions.put(taskExecutionMapEntry.getValue().getTaskName(), taskExecutionMapEntry.getValue()); tempTaskExecutions.put(taskExecutionMapEntry.getValue().getTaskName(),
taskExecutionMapEntry.getValue());
} }
} }
final List<TaskExecution> latestTaskExecutions = new ArrayList<>(tempTaskExecutions.values()); final List<TaskExecution> latestTaskExecutions = new ArrayList<>(
tempTaskExecutions.values());
Collections.sort(latestTaskExecutions, new TaskExecutionComparator()); Collections.sort(latestTaskExecutions, new TaskExecutionComparator());
return latestTaskExecutions; return latestTaskExecutions;
} }
@@ -311,7 +329,8 @@ public class MapTaskExecutionDao implements TaskExecutionDao {
@Override @Override
public TaskExecution getLatestTaskExecutionForTaskName(String taskName) { public TaskExecution getLatestTaskExecutionForTaskName(String taskName) {
Assert.hasText(taskName, "The task name must not be empty."); Assert.hasText(taskName, "The task name must not be empty.");
final List<TaskExecution> taskExecutions = this.getLatestTaskExecutionsByTaskNames(taskName); final List<TaskExecution> taskExecutions = this
.getLatestTaskExecutionsByTaskNames(taskName);
if (taskExecutions.isEmpty()) { if (taskExecutions.isEmpty()) {
return null; return null;
} }
@@ -319,20 +338,29 @@ public class MapTaskExecutionDao implements TaskExecutionDao {
return taskExecutions.get(0); return taskExecutions.get(0);
} }
else { else {
throw new IllegalStateException("Only expected a single TaskExecution but received " + taskExecutions.size()); throw new IllegalStateException(
"Only expected a single TaskExecution but received "
+ taskExecutions.size());
} }
} }
private static class TaskExecutionComparator implements Comparator<TaskExecution>, Serializable { private static class TaskExecutionComparator
implements Comparator<TaskExecution>, Serializable {
@Override @Override
public int compare(TaskExecution firstTaskExecution, TaskExecution secondTaskExecution) { public int compare(TaskExecution firstTaskExecution,
if (firstTaskExecution.getStartTime().equals(secondTaskExecution.getStartTime())) { TaskExecution secondTaskExecution) {
return Long.compare(firstTaskExecution.getExecutionId(), secondTaskExecution.getExecutionId()); if (firstTaskExecution.getStartTime()
.equals(secondTaskExecution.getStartTime())) {
return Long.compare(firstTaskExecution.getExecutionId(),
secondTaskExecution.getExecutionId());
} }
else { else {
return secondTaskExecution.getStartTime().compareTo(firstTaskExecution.getStartTime()); return secondTaskExecution.getStartTime()
.compareTo(firstTaskExecution.getStartTime());
} }
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -36,19 +36,17 @@ public interface TaskExecutionDao {
/** /**
* Save a new {@link TaskExecution}. * Save a new {@link TaskExecution}.
*
* @param taskName the name that associated with the task execution. * @param taskName the name that associated with the task execution.
* @param startTime the time task began. * @param startTime the time task began.
* @param arguments list of key/value pairs that configure the task. * @param arguments list of key/value pairs that configure the task.
* @param externalExecutionId id assigned to the task by the platform * @param externalExecutionId id assigned to the task by the platform
* @return A fully qualified {@link TaskExecution} instance. * @return A fully qualified {@link TaskExecution} instance.
*/ */
TaskExecution createTaskExecution( String taskName, TaskExecution createTaskExecution(String taskName, Date startTime,
Date startTime, List<String> arguments, String externalExecutionId); List<String> arguments, String externalExecutionId);
/** /**
* Save a new {@link TaskExecution}. * Save a new {@link TaskExecution}.
*
* @param taskName the name that associated with the task execution. * @param taskName the name that associated with the task execution.
* @param startTime the time task began. * @param startTime the time task began.
* @param arguments list of key/value pairs that configure the task. * @param arguments list of key/value pairs that configure the task.
@@ -57,65 +55,62 @@ public interface TaskExecutionDao {
* @return A fully qualified {@link TaskExecution} instance. * @return A fully qualified {@link TaskExecution} instance.
* @since 1.2.0 * @since 1.2.0
*/ */
TaskExecution createTaskExecution( String taskName, TaskExecution createTaskExecution(String taskName, Date startTime,
Date startTime, List<String> arguments, String externalExecutionId, List<String> arguments, String externalExecutionId, Long parentExecutionId);
Long parentExecutionId);
/** /**
* Update and existing {@link TaskExecution} to mark it as started. * Update and existing {@link TaskExecution} to mark it as started.
* * @param executionId the id of the taskExecution to be updated.
* @param executionId the id of the taskExecution to be updated.
* @param taskName the name that associated with the task execution. * @param taskName the name that associated with the task execution.
* @param startTime the time task began. * @param startTime the time task began.
* @param arguments list of key/value pairs that configure the task. * @param arguments list of key/value pairs that configure the task.
* @param externalExecutionId id assigned to the task by the platform * @param externalExecutionId id assigned to the task by the platform
* @return A TaskExecution containing the information available at task execution start. * @return A TaskExecution containing the information available at task execution
* start.
* @since 1.1.0 * @since 1.1.0
*/ */
TaskExecution startTaskExecution(long executionId, String taskName, TaskExecution startTaskExecution(long executionId, String taskName, Date startTime,
Date startTime, List<String> arguments, String externalExecutionId); List<String> arguments, String externalExecutionId);
/** /**
* Update and existing {@link TaskExecution} to mark it as started. * Update and existing {@link TaskExecution} to mark it as started.
* * @param executionId the id of the taskExecution to be updated.
* @param executionId the id of the taskExecution to be updated.
* @param taskName the name that associated with the task execution. * @param taskName the name that associated with the task execution.
* @param startTime the time task began. * @param startTime the time task began.
* @param arguments list of key/value pairs that configure the task. * @param arguments list of key/value pairs that configure the task.
* @param externalExecutionId id assigned to the task by the platform * @param externalExecutionId id assigned to the task by the platform
* @param parentExecutionId the parent task execution id. * @param parentExecutionId the parent task execution id.
* @return A TaskExecution containing the information available at task execution start. * @return A TaskExecution containing the information available at task execution
* start.
* @since 1.2.0 * @since 1.2.0
*/ */
TaskExecution startTaskExecution(long executionId, String taskName, TaskExecution startTaskExecution(long executionId, String taskName, Date startTime,
Date startTime, List<String> arguments, String externalExecutionId, List<String> arguments, String externalExecutionId, Long parentExecutionId);
Long parentExecutionId);
/** /**
* Update and existing {@link TaskExecution} to mark it as completed. * Update and existing {@link TaskExecution} to mark it as completed.
* * @param executionId the id of the taskExecution to be updated.
* @param executionId the id of the taskExecution to be updated.
* @param exitCode the status of the task upon completion. * @param exitCode the status of the task upon completion.
* @param endTime the time the task completed. * @param endTime the time the task completed.
* @param exitMessage the message assigned to the task upon completion. * @param exitMessage the message assigned to the task upon completion.
* @param errorMessage error information available upon failure of a task. * @param errorMessage error information available upon failure of a task.
* @since 1.1.0 * @since 1.1.0
*/ */
void completeTaskExecution(long executionId, Integer exitCode, Date endTime, String exitMessage, String errorMessage); void completeTaskExecution(long executionId, Integer exitCode, Date endTime,
String exitMessage, String errorMessage);
/** /**
* Update and existing {@link TaskExecution}. * Update and existing {@link TaskExecution}.
* * @param executionId the id of the taskExecution to be updated.
* @param executionId the id of the taskExecution to be updated.
* @param exitCode the status of the task upon completion. * @param exitCode the status of the task upon completion.
* @param endTime the time the task completed. * @param endTime the time the task completed.
* @param exitMessage the message assigned to the task upon completion. * @param exitMessage the message assigned to the task upon completion.
*/ */
void completeTaskExecution(long executionId, Integer exitCode, Date endTime, String exitMessage); void completeTaskExecution(long executionId, Integer exitCode, Date endTime,
String exitMessage);
/** /**
* Retrieves a task execution from the task repository. * Retrieves a task execution from the task repository.
*
* @param executionId the id associated with the task execution. * @param executionId the id associated with the task execution.
* @return a fully qualified TaskExecution instance. * @return a fully qualified TaskExecution instance.
*/ */
@@ -123,16 +118,14 @@ public interface TaskExecutionDao {
/** /**
* Retrieves current number of task executions for a taskName. * Retrieves current number of task executions for a taskName.
*
* @param taskName the name of the task to search for in the repository. * @param taskName the name of the task to search for in the repository.
* @return current number of task executions for the taskName. * @return current number of task executions for the taskName.
*/ */
long getTaskExecutionCountByTaskName(String taskName); long getTaskExecutionCountByTaskName(String taskName);
/** /**
* Retrieves current number of task executions for a taskName and with an endTime of null. * Retrieves current number of task executions for a taskName and with an endTime of
* * null.
* @param taskName the name of the task to search for in the repository. * @param taskName the name of the task to search for in the repository.
* @return current number of task executions for the taskName. * @return current number of task executions for the taskName.
*/ */
@@ -140,15 +133,12 @@ public interface TaskExecutionDao {
/** /**
* Retrieves current number of task executions with an endTime of null. * Retrieves current number of task executions with an endTime of null.
*
* @return current number of task executions. * @return current number of task executions.
*/ */
long getRunningTaskExecutionCount(); long getRunningTaskExecutionCount();
/** /**
* Retrieves current number of task executions. * Retrieves current number of task executions.
*
* @return current number of task executions. * @return current number of task executions.
*/ */
long getTaskExecutionCount(); long getTaskExecutionCount();
@@ -159,7 +149,7 @@ public interface TaskExecutionDao {
* @param pageable the constraints for the search. * @param pageable the constraints for the search.
* @return set of running task executions. * @return set of running task executions.
*/ */
Page<TaskExecution> findRunningTaskExecutions(String taskName, Pageable pageable); Page<TaskExecution> findRunningTaskExecutions(String taskName, Pageable pageable);
/** /**
* Retrieves a subset of task executions by task name, start location and size. * Retrieves a subset of task executions by task name, start location and size.
@@ -172,7 +162,6 @@ public interface TaskExecutionDao {
/** /**
* Retrieves a sorted list of distinct task names for the task executions. * Retrieves a sorted list of distinct task names for the task executions.
*
* @return a list of distinct task names from the task repository.. * @return a list of distinct task names from the task repository..
*/ */
List<String> getTaskNames(); List<String> getTaskNames();
@@ -193,8 +182,7 @@ public interface TaskExecutionDao {
/** /**
* Returns the id of the TaskExecution that the requested Spring Batch job execution * Returns the id of the TaskExecution that the requested Spring Batch job execution
* was executed within the context of. Returns null if non were found. * was executed within the context of. Returns null if non were found.
*
* @param jobExecutionId the id of the JobExecution * @param jobExecutionId the id of the JobExecution
* @return the id of the {@link TaskExecution} * @return the id of the {@link TaskExecution}
*/ */
@@ -203,7 +191,8 @@ public interface TaskExecutionDao {
/** /**
* Returns the job execution ids associated with a task execution id. * Returns the job execution ids associated with a task execution id.
* @param taskExecutionId id of the {@link TaskExecution} * @param taskExecutionId id of the {@link TaskExecution}
* @return a <code>Set</code> of the ids of the job executions executed within the task. * @return a <code>Set</code> of the ids of the job executions executed within the
* task.
*/ */
Set<Long> getJobExecutionIdsByTaskExecutionId(long taskExecutionId); Set<Long> getJobExecutionIdsByTaskExecutionId(long taskExecutionId);
@@ -212,35 +201,35 @@ public interface TaskExecutionDao {
* @param taskExecutionId the execution id for the task to be updated. * @param taskExecutionId the execution id for the task to be updated.
* @param externalExecutionId the new externalExecutionId. * @param externalExecutionId the new externalExecutionId.
*/ */
void updateExternalExecutionId(long taskExecutionId, void updateExternalExecutionId(long taskExecutionId, String externalExecutionId);
String externalExecutionId);
/** /**
* Returns a {@link List} of the latest {@link TaskExecution} for 1 or more task names. * Returns a {@link List} of the latest {@link TaskExecution} for 1 or more task
* names.
* *
* Latest is defined by the most recent start time. A {@link TaskExecution} does not have to be finished * Latest is defined by the most recent start time. A {@link TaskExecution} does not
* (The results may including pending {@link TaskExecution}s). * have to be finished (The results may including pending {@link TaskExecution}s).
* *
* It is theoretically possible that a {@link TaskExecution} with the same name to have more than 1 * It is theoretically possible that a {@link TaskExecution} with the same name to
* {@link TaskExecution} for the exact same start time. In that case the {@link TaskExecution} with the * have more than 1 {@link TaskExecution} for the exact same start time. In that case
* highest Task Execution ID is returned. * the {@link TaskExecution} with the highest Task Execution ID is returned.
*
* This method will not consider end times in its calculations. Thus, when a task execution {@code A} starts
* after task execution {@code B} but finishes BEFORE task execution {@code A}, then task execution {@code B}
* is being returned.
* *
* This method will not consider end times in its calculations. Thus, when a task
* execution {@code A} starts after task execution {@code B} but finishes BEFORE task
* execution {@code A}, then task execution {@code B} is being returned.
* @param taskNames At least 1 task name must be provided * @param taskNames At least 1 task name must be provided
* @return List of TaskExecutions. May be empty but never null. * @return List of TaskExecutions. May be empty but never null.
*/ */
List<TaskExecution> getLatestTaskExecutionsByTaskNames(String... taskNames); List<TaskExecution> getLatestTaskExecutionsByTaskNames(String... taskNames);
/** /**
* Returns the latest task execution for a given task name. Will ultimately apply the same algorithm underneath * Returns the latest task execution for a given task name. Will ultimately apply the
* as {@link #getLatestTaskExecutionsByTaskNames(String...)} but will only return a single result. * same algorithm underneath as {@link #getLatestTaskExecutionsByTaskNames(String...)}
* * but will only return a single result.
* @param taskName Must not be null or empty * @param taskName Must not be null or empty
* @return The latest Task Execution or null * @return The latest Task Execution or null
* @see #getLatestTaskExecutionsByTaskNames(String...) * @see #getLatestTaskExecutionsByTaskNames(String...)
*/ */
TaskExecution getLatestTaskExecutionForTaskName(String taskName); TaskExecution getLatestTaskExecutionForTaskName(String taskName);
} }

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2015-2019 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.
*/
/** /**
* Interface DAO and default implementations for storing and retrieving data for tasks * Interface DAO and default implementations for storing and retrieving data for tasks
* from a repository. * from a repository.

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -25,35 +25,33 @@ import org.springframework.data.domain.Pageable;
/** /**
* Interface defining the functionality to be provided for generating paging queries. * Interface defining the functionality to be provided for generating paging queries.
*
* @author Glenn Renfro * @author Glenn Renfro
*/ */
public interface PagingQueryProvider { public interface PagingQueryProvider {
/** /**
* Initialize the query provider using the provided {@link DataSource} if necessary. * Initialize the query provider using the provided {@link DataSource} if necessary.
*
* @param dataSource DataSource to use for any initialization * @param dataSource DataSource to use for any initialization
* @throws Exception throws {@link Exception} if query provider initialize fails. * @throws Exception throws {@link Exception} if query provider initialize fails.
*/ */
void init(DataSource dataSource) throws Exception; void init(DataSource dataSource) throws Exception;
/** /**
* The number of parameters that are declared in the query * The number of parameters that are declared in the query.
* @return number of parameters * @return number of parameters
*/ */
int getParameterCount(); int getParameterCount();
/** /**
* Indicate whether the generated queries use named parameter syntax. * Indicate whether the generated queries use named parameter syntax.
*
* @return true if named parameter syntax is used * @return true if named parameter syntax is used
*/ */
boolean isUsingNamedParameters(); boolean isUsingNamedParameters();
/** /**
* The sort keys. A Map of the columns that make up the key and a Boolean indicating ascending or descending * The sort keys. A Map of the columns that make up the key and a Boolean indicating
* (ascending = true). * ascending or descending (ascending = true).
*
* @return the sort keys used to order the query * @return the sort keys used to order the query
*/ */
Map<String, Order> getSortKeys(); Map<String, Order> getSortKeys();
@@ -61,9 +59,9 @@ public interface PagingQueryProvider {
/** /**
* *
* Generate the query that will provide the jump to item query. * Generate the query that will provide the jump to item query.
*
* @param pageable the coordinates to pull the next page from the datasource * @param pageable the coordinates to pull the next page from the datasource
* @return the generated query * @return the generated query
*/ */
String getPageQuery(Pageable pageable); String getPageQuery(Pageable pageable);
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -31,15 +31,15 @@ import org.springframework.util.Assert;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
* Abstract SQL Paging Query Provider to serve as a base class for all provided * Abstract SQL Paging Query Provider to serve as a base class for all provided SQL paging
* SQL paging query providers. * query providers.
* *
* Any implementation must provide a way to specify the select clause, from * Any implementation must provide a way to specify the select clause, from clause and
* clause and optionally a where clause. It is recommended that there should be an index for * optionally a where clause. It is recommended that there should be an index for the sort
* the sort key to provide better performance. * key to provide better performance.
* *
* Provides properties and preparation for the mandatory "selectClause" and * Provides properties and preparation for the mandatory "selectClause" and "fromClause"
* "fromClause" as well as for the optional "whereClause". * as well as for the optional "whereClause".
* *
* @author Glenn Renfro * @author Glenn Renfro
*/ */
@@ -51,12 +51,19 @@ public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvi
private String whereClause; private String whereClause;
private Map<String, Order> sortKeys = new LinkedHashMap<String, Order>(); private Map<String, Order> sortKeys = new LinkedHashMap<>();
private int parameterCount; private int parameterCount;
private boolean usingNamedParameters; private boolean usingNamedParameters;
/**
* @return SQL SELECT clause part of SQL query string
*/
protected String getSelectClause() {
return this.selectClause;
}
/** /**
* @param selectClause SELECT clause part of SQL query string * @param selectClause SELECT clause part of SQL query string
*/ */
@@ -65,11 +72,10 @@ public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvi
} }
/** /**
* * @return SQL FROM clause part of SQL query string
* @return SQL SELECT clause part of SQL query string
*/ */
protected String getSelectClause() { protected String getFromClause() {
return selectClause; return this.fromClause;
} }
/** /**
@@ -80,11 +86,10 @@ public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvi
} }
/** /**
* * @return SQL WHERE clause part of SQL query string
* @return SQL FROM clause part of SQL query string
*/ */
protected String getFromClause() { protected String getWhereClause() {
return fromClause; return this.whereClause;
} }
/** /**
@@ -100,11 +105,13 @@ public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvi
} }
/** /**
* * A Map&lt;String, Order&gt; of sort columns as the key and {@link Order} for
* @return SQL WHERE clause part of SQL query string * ascending/descending.
* @return sortKey key to use to sort and limit page content
*/ */
protected String getWhereClause() { @Override
return whereClause; public Map<String, Order> getSortKeys() {
return this.sortKeys;
} }
/** /**
@@ -114,56 +121,51 @@ public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvi
this.sortKeys = sortKeys; this.sortKeys = sortKeys;
} }
/**
* A Map&lt;String, Order&gt; of sort columns as the key and {@link Order} for ascending/descending.
*
* @return sortKey key to use to sort and limit page content
*/
@Override
public Map<String, Order> getSortKeys() {
return sortKeys;
}
@Override @Override
public int getParameterCount() { public int getParameterCount() {
return parameterCount; return this.parameterCount;
} }
@Override @Override
public boolean isUsingNamedParameters() { public boolean isUsingNamedParameters() {
return usingNamedParameters; return this.usingNamedParameters;
} }
@Override @Override
public void init(DataSource dataSource) throws Exception { public void init(DataSource dataSource) throws Exception {
Assert.notNull(dataSource, "DataSource must not be null"); Assert.notNull(dataSource, "DataSource must not be null");
Assert.hasLength(selectClause, "selectClause must be specified"); Assert.hasLength(this.selectClause, "selectClause must be specified");
Assert.hasLength(fromClause, "fromClause must be specified"); Assert.hasLength(this.fromClause, "fromClause must be specified");
Assert.notEmpty(sortKeys, "sortKey must be specified"); Assert.notEmpty(this.sortKeys, "sortKey must be specified");
StringBuilder sql = new StringBuilder(); StringBuilder sql = new StringBuilder();
sql.append("SELECT ").append(selectClause); sql.append("SELECT ").append(this.selectClause);
sql.append(" FROM ").append(fromClause); sql.append(" FROM ").append(this.fromClause);
if (whereClause != null) { if (this.whereClause != null) {
sql.append(" WHERE ").append(whereClause); sql.append(" WHERE ").append(this.whereClause);
} }
List<String> namedParameters = new ArrayList<String>(); List<String> namedParameters = new ArrayList<>();
parameterCount = JdbcParameterUtils.countParameterPlaceholders(sql.toString(), namedParameters); this.parameterCount = JdbcParameterUtils
.countParameterPlaceholders(sql.toString(), namedParameters);
if (namedParameters.size() > 0) { if (namedParameters.size() > 0) {
if (parameterCount != namedParameters.size()) { if (this.parameterCount != namedParameters.size()) {
throw new InvalidDataAccessApiUsageException( throw new InvalidDataAccessApiUsageException(
"You can't use both named parameters and classic \"?\" placeholders: " + sql); "You can't use both named parameters and classic \"?\" placeholders: "
+ sql);
} }
usingNamedParameters = true; this.usingNamedParameters = true;
} }
} }
private String removeKeyWord(String keyWord, String clause) { private String removeKeyWord(String keyWord, String clause) {
String temp = clause.trim(); String temp = clause.trim();
String keyWordString = keyWord + " "; String keyWordString = keyWord + " ";
if (temp.toLowerCase().startsWith(keyWordString) && temp.length() > keyWordString.length()) { if (temp.toLowerCase().startsWith(keyWordString)
&& temp.length() > keyWordString.length()) {
return temp.substring(keyWordString.length()); return temp.substring(keyWordString.length());
} }
else { else {
return temp; return temp;
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -19,9 +19,10 @@ package org.springframework.cloud.task.repository.database.support;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
/** /**
* IBM DB2 implementation of a {@link org.springframework.cloud.task.repository.database.PagingQueryProvider} using database * IBM DB2 implementation of a
* specific features. * {@link org.springframework.cloud.task.repository.database.PagingQueryProvider} using
* * database specific features.
*
* @author Thomas Schuettel * @author Thomas Schuettel
*/ */
public class Db2PagingQueryProvider extends AbstractSqlPagingQueryProvider { public class Db2PagingQueryProvider extends AbstractSqlPagingQueryProvider {
@@ -30,15 +31,18 @@ public class Db2PagingQueryProvider extends AbstractSqlPagingQueryProvider {
public String getPageQuery(Pageable pageable) { public String getPageQuery(Pageable pageable) {
long offset = pageable.getOffset() + 1; long offset = pageable.getOffset() + 1;
return generateRowNumSqlQueryWithNesting(getSelectClause(), false, return generateRowNumSqlQueryWithNesting(getSelectClause(), false,
"TMP_ROW_NUM BETWEEN " + offset + " AND " + (offset + pageable.getPageSize())); "TMP_ROW_NUM BETWEEN " + offset + " AND "
+ (offset + pageable.getPageSize()));
} }
private String generateRowNumSqlQueryWithNesting(String selectClause, boolean remainingPageQuery, private String generateRowNumSqlQueryWithNesting(String selectClause,
String rowNumClause) { boolean remainingPageQuery, String rowNumClause) {
StringBuilder sql = new StringBuilder(); StringBuilder sql = new StringBuilder();
sql.append("SELECT ").append(selectClause).append(" FROM (SELECT ").append(selectClause).append(", ") sql.append("SELECT ").append(selectClause).append(" FROM (SELECT ")
.append(selectClause).append(", ")
.append("ROW_NUMBER() OVER() as TMP_ROW_NUM"); .append("ROW_NUMBER() OVER() as TMP_ROW_NUM");
sql.append(" FROM (SELECT ").append(selectClause).append(" FROM ").append(this.getFromClause()); sql.append(" FROM (SELECT ").append(selectClause).append(" FROM ")
.append(this.getFromClause());
SqlPagingQueryUtils.buildWhereClause(this, remainingPageQuery, sql); SqlPagingQueryUtils.buildWhereClause(this, remainingPageQuery, sql);
sql.append(" ORDER BY ").append(SqlPagingQueryUtils.buildSortClause(this)); sql.append(" ORDER BY ").append(SqlPagingQueryUtils.buildSortClause(this));
sql.append(")) WHERE ").append(rowNumClause); sql.append(")) WHERE ").append(rowNumClause);

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -29,8 +29,8 @@ public class H2PagingQueryProvider extends AbstractSqlPagingQueryProvider {
@Override @Override
public String getPageQuery(Pageable pageable) { public String getPageQuery(Pageable pageable) {
String topClause = new StringBuilder().append("LIMIT ") String topClause = new StringBuilder().append("LIMIT ")
.append(pageable.getOffset()).append(" ") .append(pageable.getOffset()).append(" ").append(pageable.getPageSize())
.append(pageable.getPageSize()).toString(); .toString();
return SqlPagingQueryUtils.generateTopJumpToQuery(this, topClause); return SqlPagingQueryUtils.generateTopJumpToQuery(this, topClause);
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -20,7 +20,8 @@ import org.springframework.cloud.task.repository.database.PagingQueryProvider;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
/** /**
* HSQLDB implementation of a {@link PagingQueryProvider} using database specific features. * HSQLDB implementation of a {@link PagingQueryProvider} using database specific
* features.
* *
* @author Glenn Renfro * @author Glenn Renfro
*/ */
@@ -29,8 +30,8 @@ public class HsqlPagingQueryProvider extends AbstractSqlPagingQueryProvider {
@Override @Override
public String getPageQuery(Pageable pageable) { public String getPageQuery(Pageable pageable) {
String topClause = new StringBuilder().append("LIMIT ") String topClause = new StringBuilder().append("LIMIT ")
.append(pageable.getOffset()).append(" ") .append(pageable.getOffset()).append(" ").append(pageable.getPageSize())
.append(pageable.getPageSize()).toString(); .toString();
return SqlPagingQueryUtils.generateTopJumpToQuery(this, topClause); return SqlPagingQueryUtils.generateTopJumpToQuery(this, topClause);
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -25,11 +25,12 @@ import org.springframework.data.domain.Pageable;
* @author Glenn Renfro * @author Glenn Renfro
*/ */
public class MySqlPagingQueryProvider extends AbstractSqlPagingQueryProvider { public class MySqlPagingQueryProvider extends AbstractSqlPagingQueryProvider {
@Override @Override
public String getPageQuery(Pageable pageable) { public String getPageQuery(Pageable pageable) {
String topClause = new StringBuilder().append("LIMIT ") String topClause = new StringBuilder().append("LIMIT ")
.append(pageable.getOffset()).append(", ") .append(pageable.getOffset()).append(", ").append(pageable.getPageSize())
.append(pageable.getPageSize()).toString(); .toString();
return SqlPagingQueryUtils.generateLimitJumpToQuery(this, topClause); return SqlPagingQueryUtils.generateLimitJumpToQuery(this, topClause);
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -20,7 +20,8 @@ import org.springframework.cloud.task.repository.database.PagingQueryProvider;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
/** /**
* Oracle implementation of a {@link PagingQueryProvider} using database specific features. * Oracle implementation of a {@link PagingQueryProvider} using database specific
* features.
* *
* @author Glenn Renfro * @author Glenn Renfro
*/ */
@@ -28,22 +29,24 @@ public class OraclePagingQueryProvider extends AbstractSqlPagingQueryProvider {
@Override @Override
public String getPageQuery(Pageable pageable) { public String getPageQuery(Pageable pageable) {
long offset = pageable.getOffset()+1; long offset = pageable.getOffset() + 1;
return generateRowNumSqlQueryWithNesting(getSelectClause(), false, "TMP_ROW_NUM >= " return generateRowNumSqlQueryWithNesting(getSelectClause(), false,
+ offset + " AND TMP_ROW_NUM < " + (offset+pageable.getPageSize())); "TMP_ROW_NUM >= " + offset + " AND TMP_ROW_NUM < "
+ (offset + pageable.getPageSize()));
} }
private String generateRowNumSqlQueryWithNesting(String selectClause, private String generateRowNumSqlQueryWithNesting(String selectClause,
boolean remainingPageQuery, boolean remainingPageQuery, String rowNumClause) {
String rowNumClause) {
StringBuilder sql = new StringBuilder(); StringBuilder sql = new StringBuilder();
sql.append("SELECT ").append(selectClause).append(" FROM (SELECT ").append(selectClause) sql.append("SELECT ").append(selectClause).append(" FROM (SELECT ")
.append(", ").append("ROWNUM as TMP_ROW_NUM"); .append(selectClause).append(", ").append("ROWNUM as TMP_ROW_NUM");
sql.append(" FROM (SELECT ").append(selectClause).append(" FROM ").append(this.getFromClause()); sql.append(" FROM (SELECT ").append(selectClause).append(" FROM ")
.append(this.getFromClause());
SqlPagingQueryUtils.buildWhereClause(this, remainingPageQuery, sql); SqlPagingQueryUtils.buildWhereClause(this, remainingPageQuery, sql);
sql.append(" ORDER BY ").append(SqlPagingQueryUtils.buildSortClause(this)); sql.append(" ORDER BY ").append(SqlPagingQueryUtils.buildSortClause(this));
sql.append(")) WHERE ").append(rowNumClause); sql.append(")) WHERE ").append(rowNumClause);
return sql.toString(); return sql.toString();
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -20,7 +20,8 @@ import org.springframework.cloud.task.repository.database.PagingQueryProvider;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
/** /**
* Postgres implementation of a {@link PagingQueryProvider} using database specific features. * Postgres implementation of a {@link PagingQueryProvider} using database specific
* features.
* *
* @author Glenn Renfro * @author Glenn Renfro
*/ */
@@ -28,9 +29,10 @@ public class PostgresPagingQueryProvider extends AbstractSqlPagingQueryProvider
@Override @Override
public String getPageQuery(Pageable pageable) { public String getPageQuery(Pageable pageable) {
String limitClause = new StringBuilder().append("LIMIT "). String limitClause = new StringBuilder().append("LIMIT ")
append(pageable.getPageSize()).append(" OFFSET "). .append(pageable.getPageSize()).append(" OFFSET ")
append(pageable.getOffset()).toString(); .append(pageable.getOffset()).toString();
return SqlPagingQueryUtils.generateLimitJumpToQuery(this, limitClause); return SqlPagingQueryUtils.generateLimitJumpToQuery(this, limitClause);
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -16,17 +16,6 @@
package org.springframework.cloud.task.repository.database.support; package org.springframework.cloud.task.repository.database.support;
import static org.springframework.cloud.task.repository.support.DatabaseType.DB2;
import static org.springframework.cloud.task.repository.support.DatabaseType.DB2AS400;
import static org.springframework.cloud.task.repository.support.DatabaseType.DB2VSE;
import static org.springframework.cloud.task.repository.support.DatabaseType.DB2ZOS;
import static org.springframework.cloud.task.repository.support.DatabaseType.HSQL;
import static org.springframework.cloud.task.repository.support.DatabaseType.H2;
import static org.springframework.cloud.task.repository.support.DatabaseType.MYSQL;
import static org.springframework.cloud.task.repository.support.DatabaseType.ORACLE;
import static org.springframework.cloud.task.repository.support.DatabaseType.POSTGRES;
import static org.springframework.cloud.task.repository.support.DatabaseType.SQLSERVER;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@@ -40,14 +29,26 @@ import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import static org.springframework.cloud.task.repository.support.DatabaseType.DB2;
import static org.springframework.cloud.task.repository.support.DatabaseType.DB2AS400;
import static org.springframework.cloud.task.repository.support.DatabaseType.DB2VSE;
import static org.springframework.cloud.task.repository.support.DatabaseType.DB2ZOS;
import static org.springframework.cloud.task.repository.support.DatabaseType.H2;
import static org.springframework.cloud.task.repository.support.DatabaseType.HSQL;
import static org.springframework.cloud.task.repository.support.DatabaseType.MYSQL;
import static org.springframework.cloud.task.repository.support.DatabaseType.ORACLE;
import static org.springframework.cloud.task.repository.support.DatabaseType.POSTGRES;
import static org.springframework.cloud.task.repository.support.DatabaseType.SQLSERVER;
/** /**
* Factory bean for {@link PagingQueryProvider} interface. The database type * Factory bean for {@link PagingQueryProvider} interface. The database type will be
* will be determined from the data source if not provided explicitly. Valid * determined from the data source if not provided explicitly. Valid types are given by
* types are given by the {@link DatabaseType} enum. * the {@link DatabaseType} enum.
* *
* @author Glenn Renfro * @author Glenn Renfro
*/ */
public class SqlPagingQueryProviderFactoryBean implements FactoryBean<PagingQueryProvider> { public class SqlPagingQueryProviderFactoryBean
implements FactoryBean<PagingQueryProvider> {
private DataSource dataSource; private DataSource dataSource;
@@ -61,20 +62,19 @@ public class SqlPagingQueryProviderFactoryBean implements FactoryBean<PagingQuer
private Map<String, Order> sortKeys; private Map<String, Order> sortKeys;
private Map<DatabaseType, AbstractSqlPagingQueryProvider> providers = new HashMap<DatabaseType, AbstractSqlPagingQueryProvider>(); private Map<DatabaseType, AbstractSqlPagingQueryProvider> providers = new HashMap<>();
{ {
providers.put(HSQL, new HsqlPagingQueryProvider()); this.providers.put(HSQL, new HsqlPagingQueryProvider());
providers.put(H2, new H2PagingQueryProvider()); this.providers.put(H2, new H2PagingQueryProvider());
providers.put(MYSQL, new MySqlPagingQueryProvider()); this.providers.put(MYSQL, new MySqlPagingQueryProvider());
providers.put(POSTGRES, new PostgresPagingQueryProvider()); this.providers.put(POSTGRES, new PostgresPagingQueryProvider());
providers.put(ORACLE, new OraclePagingQueryProvider()); this.providers.put(ORACLE, new OraclePagingQueryProvider());
providers.put(SQLSERVER, new SqlServerPagingQueryProvider()); this.providers.put(SQLSERVER, new SqlServerPagingQueryProvider());
providers.put(DB2, new Db2PagingQueryProvider()); this.providers.put(DB2, new Db2PagingQueryProvider());
providers.put(DB2VSE, new Db2PagingQueryProvider()); this.providers.put(DB2VSE, new Db2PagingQueryProvider());
providers.put(DB2ZOS, new Db2PagingQueryProvider()); this.providers.put(DB2ZOS, new Db2PagingQueryProvider());
providers.put(DB2AS400, new Db2PagingQueryProvider()); this.providers.put(DB2AS400, new Db2PagingQueryProvider());
} }
/** /**
@@ -124,8 +124,8 @@ public class SqlPagingQueryProviderFactoryBean implements FactoryBean<PagingQuer
} }
/** /**
* Get a {@link PagingQueryProvider} instance using the provided properties * Get a {@link PagingQueryProvider} instance using the provided properties and
* and appropriate for the given database type. * appropriate for the given database type.
* *
* @see FactoryBean#getObject() * @see FactoryBean#getObject()
*/ */
@@ -134,24 +134,28 @@ public class SqlPagingQueryProviderFactoryBean implements FactoryBean<PagingQuer
DatabaseType type; DatabaseType type;
try { try {
type = databaseType != null ? DatabaseType.valueOf(databaseType.toUpperCase()) : DatabaseType type = this.databaseType != null
.fromMetaData(dataSource); ? DatabaseType.valueOf(this.databaseType.toUpperCase())
: DatabaseType.fromMetaData(this.dataSource);
} }
catch (MetaDataAccessException e) { catch (MetaDataAccessException e) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Could not inspect meta data for database type. You have to supply it explicitly.", e); "Could not inspect meta data for database type. You have to supply it explicitly.",
e);
} }
AbstractSqlPagingQueryProvider provider = providers.get(type); AbstractSqlPagingQueryProvider provider = this.providers.get(type);
Assert.state(provider != null, "Should not happen: missing PagingQueryProvider for DatabaseType=" + type); Assert.state(provider != null,
"Should not happen: missing PagingQueryProvider for DatabaseType="
+ type);
provider.setFromClause(fromClause); provider.setFromClause(this.fromClause);
provider.setWhereClause(whereClause); provider.setWhereClause(this.whereClause);
provider.setSortKeys(sortKeys); provider.setSortKeys(this.sortKeys);
if (StringUtils.hasText(selectClause)) { if (StringUtils.hasText(this.selectClause)) {
provider.setSelectClause(selectClause); provider.setSelectClause(this.selectClause);
} }
provider.init(dataSource); provider.init(this.dataSource);
return provider; return provider;
@@ -176,4 +180,5 @@ public class SqlPagingQueryProviderFactoryBean implements FactoryBean<PagingQuer
public boolean isSingleton() { public boolean isSingleton() {
return true; return true;
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -21,28 +21,29 @@ import java.util.Map;
import org.springframework.batch.item.database.Order; import org.springframework.batch.item.database.Order;
/** /**
* Utility class that generates the actual SQL statements used by query * Utility class that generates the actual SQL statements used by query providers.
* providers.
* *
* @author Glenn Renfro * @author Glenn Renfro
*/ */
public class SqlPagingQueryUtils { public final class SqlPagingQueryUtils {
private SqlPagingQueryUtils(){} private SqlPagingQueryUtils() {
}
/** /**
* Generate SQL query string using a LIMIT clause * Generate SQL query string using a LIMIT clause.
* * @param provider {@link AbstractSqlPagingQueryProvider} providing the implementation
* @param provider {@link AbstractSqlPagingQueryProvider} providing the * specifics
* implementation specifics
* @param limitClause the implementation specific top clause to be used * @param limitClause the implementation specific top clause to be used
* @return the generated query * @return the generated query
*/ */
public static String generateLimitJumpToQuery(AbstractSqlPagingQueryProvider provider, String limitClause) { public static String generateLimitJumpToQuery(AbstractSqlPagingQueryProvider provider,
String limitClause) {
StringBuilder sql = new StringBuilder(); StringBuilder sql = new StringBuilder();
sql.append("SELECT ").append(provider.getSelectClause()); sql.append("SELECT ").append(provider.getSelectClause());
sql.append(" FROM ").append(provider.getFromClause()); sql.append(" FROM ").append(provider.getFromClause());
sql.append(provider.getWhereClause() == null ? "" : " WHERE " + provider.getWhereClause()); sql.append(provider.getWhereClause() == null ? ""
: " WHERE " + provider.getWhereClause());
sql.append(" ORDER BY ").append(buildSortClause(provider)); sql.append(" ORDER BY ").append(buildSortClause(provider));
sql.append(" ").append(limitClause); sql.append(" ").append(limitClause);
@@ -50,18 +51,20 @@ public class SqlPagingQueryUtils {
} }
/** /**
* Generate SQL query string using a TOP clause * Generate SQL query string using a TOP clause.
* * @param provider {@link AbstractSqlPagingQueryProvider} providing the implementation
* @param provider {@link AbstractSqlPagingQueryProvider} providing the * specifics
* implementation specifics
* @param topClause the implementation specific top clause to be used * @param topClause the implementation specific top clause to be used
* @return the generated query * @return the generated query
*/ */
public static String generateTopJumpToQuery(AbstractSqlPagingQueryProvider provider, String topClause) { public static String generateTopJumpToQuery(AbstractSqlPagingQueryProvider provider,
String topClause) {
StringBuilder sql = new StringBuilder(); StringBuilder sql = new StringBuilder();
sql.append("SELECT ").append(topClause).append(" ").append(provider.getSelectClause()); sql.append("SELECT ").append(topClause).append(" ")
.append(provider.getSelectClause());
sql.append(" FROM ").append(provider.getFromClause()); sql.append(" FROM ").append(provider.getFromClause());
sql.append(provider.getWhereClause() == null ? "" : " WHERE " + provider.getWhereClause()); sql.append(provider.getWhereClause() == null ? ""
: " WHERE " + provider.getWhereClause());
sql.append(" ORDER BY ").append(buildSortClause(provider)); sql.append(" ORDER BY ").append(buildSortClause(provider));
return sql.toString(); return sql.toString();
@@ -69,13 +72,12 @@ public class SqlPagingQueryUtils {
/** /**
* Generates WHERE clause for queries that require sub selects. * Generates WHERE clause for queries that require sub selects.
*
* @param provider the paging query provider that will provide the base where clause * @param provider the paging query provider that will provide the base where clause
* @param remainingPageQuery if true assumes more will be appended to where clause * @param remainingPageQuery if true assumes more will be appended to where clause
* @param sql the sql statement to be appended. * @param sql the sql statement to be appended.
*/ */
public static void buildWhereClause( AbstractSqlPagingQueryProvider provider, public static void buildWhereClause(AbstractSqlPagingQueryProvider provider,
boolean remainingPageQuery, StringBuilder sql) { boolean remainingPageQuery, StringBuilder sql) {
if (remainingPageQuery) { if (remainingPageQuery) {
sql.append(" WHERE "); sql.append(" WHERE ");
if (provider.getWhereClause() != null) { if (provider.getWhereClause() != null) {
@@ -85,15 +87,15 @@ public class SqlPagingQueryUtils {
} }
} }
else { else {
sql.append(provider.getWhereClause() == null ? "" : " WHERE " + provider.getWhereClause()); sql.append(provider.getWhereClause() == null ? ""
: " WHERE " + provider.getWhereClause());
} }
} }
/** /**
* Generates ORDER BY attributes based on the sort keys. * Generates ORDER BY attributes based on the sort keys.
* * @param provider {@link AbstractSqlPagingQueryProvider} providing the implementation
* @param provider {@link AbstractSqlPagingQueryProvider} providing the * specifics
* implementation specifics
* @return a String that can be appended to an ORDER BY clause. * @return a String that can be appended to an ORDER BY clause.
*/ */
public static String buildSortClause(AbstractSqlPagingQueryProvider provider) { public static String buildSortClause(AbstractSqlPagingQueryProvider provider) {
@@ -102,7 +104,6 @@ public class SqlPagingQueryUtils {
/** /**
* Generates ORDER BY attributes based on the sort keys. * Generates ORDER BY attributes based on the sort keys.
*
* @param sortKeys generates order by clause from map * @param sortKeys generates order by clause from map
* @return a String that can be appended to an ORDER BY clause. * @return a String that can be appended to an ORDER BY clause.
*/ */
@@ -117,7 +118,7 @@ public class SqlPagingQueryUtils {
builder.append(sortKey.getKey()); builder.append(sortKey.getKey());
if(sortKey.getValue() != null && sortKey.getValue() == Order.DESCENDING) { if (sortKey.getValue() != null && sortKey.getValue() == Order.DESCENDING) {
builder.append(" DESC"); builder.append(" DESC");
} }
else { else {
@@ -127,4 +128,5 @@ public class SqlPagingQueryUtils {
return builder.toString(); return builder.toString();
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -20,31 +20,33 @@ import org.springframework.cloud.task.repository.database.PagingQueryProvider;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
/** /**
* Sql Server implementation of a {@link PagingQueryProvider} using database specific features. * Sql Server implementation of a {@link PagingQueryProvider} using database specific
* features.
*
* @author Glenn Renfro * @author Glenn Renfro
*/ */
public class SqlServerPagingQueryProvider extends AbstractSqlPagingQueryProvider{ public class SqlServerPagingQueryProvider extends AbstractSqlPagingQueryProvider {
@Override @Override
public String getPageQuery(Pageable pageable) { public String getPageQuery(Pageable pageable) {
long offset = pageable.getOffset()+1; long offset = pageable.getOffset() + 1;
return generateRowNumSqlQueryWithNesting(getSelectClause(), false, "TMP_ROW_NUM >= " return generateRowNumSqlQueryWithNesting(getSelectClause(), false,
+ offset + " AND TMP_ROW_NUM < " + (offset+pageable.getPageSize())); "TMP_ROW_NUM >= " + offset + " AND TMP_ROW_NUM < "
+ (offset + pageable.getPageSize()));
} }
private String generateRowNumSqlQueryWithNesting(String selectClause, private String generateRowNumSqlQueryWithNesting(String selectClause,
boolean remainingPageQuery, boolean remainingPageQuery, String rowNumClause) {
String rowNumClause) {
StringBuilder sql = new StringBuilder(); StringBuilder sql = new StringBuilder();
sql.append("SELECT ").append(selectClause).append(" FROM (SELECT ").append(selectClause) sql.append("SELECT ").append(selectClause).append(" FROM (SELECT ")
.append(", ").append("ROW_NUMBER() OVER (ORDER BY ") .append(selectClause).append(", ").append("ROW_NUMBER() OVER (ORDER BY ")
.append(SqlPagingQueryUtils.buildSortClause(this)) .append(SqlPagingQueryUtils.buildSortClause(this))
.append(") AS TMP_ROW_NUM ") .append(") AS TMP_ROW_NUM ").append(" FROM ").append(getFromClause());
.append(" FROM ").append(getFromClause());
SqlPagingQueryUtils.buildWhereClause(this, remainingPageQuery, sql); SqlPagingQueryUtils.buildWhereClause(this, remainingPageQuery, sql);
sql.append(") TASK_EXECUTION_PAGE "); sql.append(") TASK_EXECUTION_PAGE ");
sql.append(" WHERE ").append(rowNumClause); sql.append(" WHERE ").append(rowNumClause);
sql.append(" ORDER BY ").append(SqlPagingQueryUtils.buildSortClause(this)); sql.append(" ORDER BY ").append(SqlPagingQueryUtils.buildSortClause(this));
return sql.toString(); return sql.toString();
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -25,63 +25,107 @@ import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.jdbc.support.MetaDataAccessException; import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
* Enum representing a database type, such as DB2 or oracle. The type also * Enum representing a database type, such as DB2 or oracle. The type also contains a
* contains a product name, which is expected to be the same as the product name * product name, which is expected to be the same as the product name provided by the
* provided by the database driver's metadata. * database driver's metadata.
* *
* @author Glenn Renfro * @author Glenn Renfro
*/ */
public enum DatabaseType { public enum DatabaseType {
/**
* HSQL DB.
*/
HSQL("HSQL Database Engine"), HSQL("HSQL Database Engine"),
/**
* H2 DB.
*/
H2("H2"), H2("H2"),
/**
* Oracle DB.
*/
ORACLE("Oracle"), ORACLE("Oracle"),
/**
* MySQL DB.
*/
MYSQL("MySQL"), MYSQL("MySQL"),
/**
* PostgreSQL DB.
*/
POSTGRES("PostgreSQL"), POSTGRES("PostgreSQL"),
/**
* Microsoft SQL Server DB.
*/
SQLSERVER("Microsoft SQL Server"), SQLSERVER("Microsoft SQL Server"),
/**
* DB2 DB.
*/
DB2("DB2"), DB2("DB2"),
/**
* DB2VSE DB.
*/
DB2VSE("DB2VSE"), DB2VSE("DB2VSE"),
/**
* DB2ZOS DB.
*/
DB2ZOS("DB2ZOS"), DB2ZOS("DB2ZOS"),
/**
* DB2AS400 DB.
*/
DB2AS400("DB2AS400"); DB2AS400("DB2AS400");
private static final Map<String, DatabaseType> dbNameMap; private static final Map<String, DatabaseType> dbNameMap;
static {
dbNameMap = new HashMap<>();
for (DatabaseType type : values()) {
dbNameMap.put(type.getProductName(), type);
}
}
private final String productName; private final String productName;
DatabaseType(String productName) { DatabaseType(String productName) {
this.productName = productName; this.productName = productName;
} }
static{
dbNameMap = new HashMap<String, DatabaseType>();
for(DatabaseType type: values()){
dbNameMap.put(type.getProductName(), type);
}
}
/** /**
* Convenience method that pulls a database product name from the DataSource's metadata. * Convenience method that pulls a database product name from the DataSource's
* * metadata.
* @param dataSource the datasource used to extact metadata. * @param dataSource the datasource used to extact metadata.
* @return DatabaseType The database type associated with the datasource. * @return DatabaseType The database type associated with the datasource.
* @throws MetaDataAccessException thrown if failure occurs on metadata lookup. * @throws MetaDataAccessException thrown if failure occurs on metadata lookup.
*/ */
public static DatabaseType fromMetaData(DataSource dataSource) throws MetaDataAccessException { public static DatabaseType fromMetaData(DataSource dataSource)
String databaseProductName = throws MetaDataAccessException {
JdbcUtils.extractDatabaseMetaData(dataSource, "getDatabaseProductName").toString(); String databaseProductName = JdbcUtils
if (StringUtils.hasText(databaseProductName) && !databaseProductName.equals("DB2/Linux") && databaseProductName.startsWith("DB2")) { .extractDatabaseMetaData(dataSource, "getDatabaseProductName").toString();
String databaseProductVersion = if (StringUtils.hasText(databaseProductName)
JdbcUtils.extractDatabaseMetaData(dataSource, "getDatabaseProductVersion").toString(); && !databaseProductName.equals("DB2/Linux")
&& databaseProductName.startsWith("DB2")) {
String databaseProductVersion = JdbcUtils
.extractDatabaseMetaData(dataSource, "getDatabaseProductVersion")
.toString();
if (databaseProductVersion.startsWith("ARI")) { if (databaseProductVersion.startsWith("ARI")) {
databaseProductName = "DB2VSE"; databaseProductName = "DB2VSE";
} }
else if (databaseProductVersion.startsWith("DSN")) { else if (databaseProductVersion.startsWith("DSN")) {
databaseProductName = "DB2ZOS"; databaseProductName = "DB2ZOS";
} }
else if (databaseProductName.indexOf("AS") != -1 && (databaseProductVersion.startsWith("QSQ") || else if (databaseProductName.indexOf("AS") != -1
databaseProductVersion.substring(databaseProductVersion.indexOf('V')).matches("V\\dR\\d[mM]\\d"))) { && (databaseProductVersion.startsWith("QSQ") || databaseProductVersion
.substring(databaseProductVersion.indexOf('V'))
.matches("V\\dR\\d[mM]\\d"))) {
databaseProductName = "DB2AS400"; databaseProductName = "DB2AS400";
} }
else { else {
@@ -96,23 +140,22 @@ public enum DatabaseType {
/** /**
* Static method to obtain a DatabaseType from the provided product name. * Static method to obtain a DatabaseType from the provided product name.
*
* @param productName the name of the database. * @param productName the name of the database.
* @return DatabaseType for given product name. * @return DatabaseType for given product name.
* @throws IllegalArgumentException if none is found. * @throws IllegalArgumentException if none is found.
*/ */
public static DatabaseType fromProductName(String productName){ public static DatabaseType fromProductName(String productName) {
if(!dbNameMap.containsKey(productName)){ if (!dbNameMap.containsKey(productName)) {
throw new IllegalArgumentException("DatabaseType not found for product name: [" + throw new IllegalArgumentException(
productName + "]"); "DatabaseType not found for product name: [" + productName + "]");
} }
else{ else {
return dbNameMap.get(productName); return dbNameMap.get(productName);
} }
} }
private String getProductName() { private String getProductName() {
return productName; return this.productName;
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -39,7 +39,8 @@ public class SimpleTaskExplorer implements TaskExplorer {
private TaskExecutionDao taskExecutionDao; private TaskExecutionDao taskExecutionDao;
public SimpleTaskExplorer(TaskExecutionDaoFactoryBean taskExecutionDaoFactoryBean) { public SimpleTaskExplorer(TaskExecutionDaoFactoryBean taskExecutionDaoFactoryBean) {
Assert.notNull(taskExecutionDaoFactoryBean, "taskExecutionDaoFactoryBean must not be null"); Assert.notNull(taskExecutionDaoFactoryBean,
"taskExecutionDaoFactoryBean must not be null");
try { try {
this.taskExecutionDao = taskExecutionDaoFactoryBean.getObject(); this.taskExecutionDao = taskExecutionDaoFactoryBean.getObject();
@@ -51,62 +52,64 @@ public class SimpleTaskExplorer implements TaskExplorer {
@Override @Override
public TaskExecution getTaskExecution(long executionId) { public TaskExecution getTaskExecution(long executionId) {
return taskExecutionDao.getTaskExecution(executionId); return this.taskExecutionDao.getTaskExecution(executionId);
} }
@Override @Override
public Page<TaskExecution> findRunningTaskExecutions(String taskName, Pageable pageable) { public Page<TaskExecution> findRunningTaskExecutions(String taskName,
return taskExecutionDao.findRunningTaskExecutions(taskName, pageable); Pageable pageable) {
return this.taskExecutionDao.findRunningTaskExecutions(taskName, pageable);
} }
@Override @Override
public List<String> getTaskNames() { public List<String> getTaskNames() {
return taskExecutionDao.getTaskNames(); return this.taskExecutionDao.getTaskNames();
} }
@Override @Override
public long getTaskExecutionCountByTaskName(String taskName) { public long getTaskExecutionCountByTaskName(String taskName) {
return taskExecutionDao.getTaskExecutionCountByTaskName(taskName); return this.taskExecutionDao.getTaskExecutionCountByTaskName(taskName);
} }
@Override @Override
public long getTaskExecutionCount() { public long getTaskExecutionCount() {
return taskExecutionDao.getTaskExecutionCount(); return this.taskExecutionDao.getTaskExecutionCount();
} }
@Override @Override
public long getRunningTaskExecutionCount() { public long getRunningTaskExecutionCount() {
return taskExecutionDao.getRunningTaskExecutionCount(); return this.taskExecutionDao.getRunningTaskExecutionCount();
} }
@Override @Override
public Page<TaskExecution> findTaskExecutionsByName(String taskName, Pageable pageable) { public Page<TaskExecution> findTaskExecutionsByName(String taskName,
return taskExecutionDao.findTaskExecutionsByName(taskName, pageable); Pageable pageable) {
return this.taskExecutionDao.findTaskExecutionsByName(taskName, pageable);
} }
@Override @Override
public Page<TaskExecution> findAll(Pageable pageable) { public Page<TaskExecution> findAll(Pageable pageable) {
return taskExecutionDao.findAll(pageable); return this.taskExecutionDao.findAll(pageable);
} }
@Override @Override
public Long getTaskExecutionIdByJobExecutionId(long jobExecutionId) { public Long getTaskExecutionIdByJobExecutionId(long jobExecutionId) {
return taskExecutionDao.getTaskExecutionIdByJobExecutionId(jobExecutionId); return this.taskExecutionDao.getTaskExecutionIdByJobExecutionId(jobExecutionId);
} }
@Override @Override
public Set<Long> getJobExecutionIdsByTaskExecutionId(long taskExecutionId) { public Set<Long> getJobExecutionIdsByTaskExecutionId(long taskExecutionId) {
return taskExecutionDao.getJobExecutionIdsByTaskExecutionId(taskExecutionId); return this.taskExecutionDao.getJobExecutionIdsByTaskExecutionId(taskExecutionId);
} }
@Override @Override
public List<TaskExecution> getLatestTaskExecutionsByTaskNames(String... taskNames) { public List<TaskExecution> getLatestTaskExecutionsByTaskNames(String... taskNames) {
return taskExecutionDao.getLatestTaskExecutionsByTaskNames(taskNames); return this.taskExecutionDao.getLatestTaskExecutionsByTaskNames(taskNames);
} }
@Override @Override
public TaskExecution getLatestTaskExecutionForTaskName(String taskName) { public TaskExecution getLatestTaskExecutionForTaskName(String taskName) {
return taskExecutionDao.getLatestTaskExecutionForTaskName(taskName); return this.taskExecutionDao.getLatestTaskExecutionForTaskName(taskName);
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.repository.support; package org.springframework.cloud.task.repository.support;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
@@ -23,11 +24,11 @@ import org.springframework.context.ApplicationContextAware;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
* Simple implementation of the {@link TaskNameResolver} interface. Names the task based * Simple implementation of the {@link TaskNameResolver} interface. Names the task based
* on the following order of precidence: * on the following order of precidence:
* <ol> * <ol>
* <li>A configured property <code>spring.cloud.task.name</code></li> * <li>A configured property <code>spring.cloud.task.name</code></li>
* <li>The {@link ApplicationContext}'s id.</li> * <li>The {@link ApplicationContext}'s id.</li>
* </ol> * </ol>
* *
* @author Michael Minella * @author Michael Minella
@@ -45,17 +46,19 @@ public class SimpleTaskNameResolver implements TaskNameResolver, ApplicationCont
} }
@Override @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.context = applicationContext; this.context = applicationContext;
} }
@Override @Override
public String getTaskName() { public String getTaskName() {
if(StringUtils.hasText(configuredName)) { if (StringUtils.hasText(this.configuredName)) {
return configuredName; return this.configuredName;
} }
else { else {
return context.getId().replace(":", "_"); return this.context.getId().replace(":", "_");
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015-2017 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -31,15 +31,27 @@ import org.springframework.util.Assert;
/** /**
* Records the task execution information to the log and to TaskExecutionDao provided. * Records the task execution information to the log and to TaskExecutionDao provided.
*
* @author Glenn Renfro * @author Glenn Renfro
*/ */
public class SimpleTaskRepository implements TaskRepository { public class SimpleTaskRepository implements TaskRepository {
/**
* Max exit message size.
*/
public static final int MAX_EXIT_MESSAGE_SIZE = 2500; public static final int MAX_EXIT_MESSAGE_SIZE = 2500;
/**
* Max task name size.
*/
public static final int MAX_TASK_NAME_SIZE = 100; public static final int MAX_TASK_NAME_SIZE = 100;
/**
* Max error message size.
*/
public static final int MAX_ERROR_MESSAGE_SIZE = 2500; public static final int MAX_ERROR_MESSAGE_SIZE = 2500;
private static final Log logger = LogFactory.getLog(SimpleTaskRepository.class); private static final Log logger = LogFactory.getLog(SimpleTaskRepository.class);
private TaskExecutionDao taskExecutionDao; private TaskExecutionDao taskExecutionDao;
@@ -53,63 +65,63 @@ public class SimpleTaskRepository implements TaskRepository {
private int maxErrorMessageSize = MAX_ERROR_MESSAGE_SIZE; private int maxErrorMessageSize = MAX_ERROR_MESSAGE_SIZE;
public SimpleTaskRepository(FactoryBean<TaskExecutionDao> taskExecutionDaoFactoryBean){ public SimpleTaskRepository(
Assert.notNull(taskExecutionDaoFactoryBean, "A FactoryBean that provides a TaskExecutionDao is required"); FactoryBean<TaskExecutionDao> taskExecutionDaoFactoryBean) {
Assert.notNull(taskExecutionDaoFactoryBean,
"A FactoryBean that provides a TaskExecutionDao is required");
this.taskExecutionDaoFactoryBean = taskExecutionDaoFactoryBean; this.taskExecutionDaoFactoryBean = taskExecutionDaoFactoryBean;
} }
public SimpleTaskRepository(FactoryBean<TaskExecutionDao> taskExecutionDaoFactoryBean, Integer maxExitMessageSize, public SimpleTaskRepository(FactoryBean<TaskExecutionDao> taskExecutionDaoFactoryBean,
Integer maxTaskNameSize, Integer maxErrorMessageSize){ Integer maxExitMessageSize, Integer maxTaskNameSize,
Assert.notNull(taskExecutionDaoFactoryBean, "A FactoryBean that provides a TaskExecutionDao is required"); Integer maxErrorMessageSize) {
if(maxTaskNameSize != null) { Assert.notNull(taskExecutionDaoFactoryBean,
"A FactoryBean that provides a TaskExecutionDao is required");
if (maxTaskNameSize != null) {
this.maxTaskNameSize = maxTaskNameSize; this.maxTaskNameSize = maxTaskNameSize;
} }
if(maxExitMessageSize != null) { if (maxExitMessageSize != null) {
this.maxExitMessageSize = maxExitMessageSize; this.maxExitMessageSize = maxExitMessageSize;
} }
if(maxErrorMessageSize != null) { if (maxErrorMessageSize != null) {
this.maxErrorMessageSize = maxErrorMessageSize; this.maxErrorMessageSize = maxErrorMessageSize;
} }
this.taskExecutionDaoFactoryBean = taskExecutionDaoFactoryBean; this.taskExecutionDaoFactoryBean = taskExecutionDaoFactoryBean;
} }
@Override @Override
public TaskExecution completeTaskExecution(long executionId, Integer exitCode, Date endTime, String exitMessage) { public TaskExecution completeTaskExecution(long executionId, Integer exitCode,
Date endTime, String exitMessage) {
return completeTaskExecution(executionId, exitCode, endTime, exitMessage, null); return completeTaskExecution(executionId, exitCode, endTime, exitMessage, null);
} }
@Override @Override
public TaskExecution completeTaskExecution(long executionId, Integer exitCode, Date endTime, public TaskExecution completeTaskExecution(long executionId, Integer exitCode,
String exitMessage, String errorMessage) { Date endTime, String exitMessage, String errorMessage) {
initialize(); initialize();
validateCompletedTaskExitInformation(executionId, exitCode, endTime); validateCompletedTaskExitInformation(executionId, exitCode, endTime);
exitMessage = trimMessage(exitMessage, this.maxExitMessageSize); exitMessage = trimMessage(exitMessage, this.maxExitMessageSize);
errorMessage = trimMessage(errorMessage, this.maxErrorMessageSize); errorMessage = trimMessage(errorMessage, this.maxErrorMessageSize);
taskExecutionDao.completeTaskExecution(executionId, exitCode, endTime, exitMessage, errorMessage); this.taskExecutionDao.completeTaskExecution(executionId, exitCode, endTime,
logger.debug("Updating: TaskExecution with executionId="+executionId exitMessage, errorMessage);
+ " with the following {" logger.debug("Updating: TaskExecution with executionId=" + executionId
+ "exitCode=" + exitCode + " with the following {" + "exitCode=" + exitCode + ", endTime="
+ ", endTime=" + endTime + endTime + ", exitMessage='" + exitMessage + '\'' + ", errorMessage='"
+ ", exitMessage='" + exitMessage + '\'' + errorMessage + '\'' + '}');
+ ", errorMessage='" + errorMessage + '\''
+ '}');
return taskExecutionDao.getTaskExecution(executionId); return this.taskExecutionDao.getTaskExecution(executionId);
} }
@Override @Override
public TaskExecution createTaskExecution(TaskExecution taskExecution) { public TaskExecution createTaskExecution(TaskExecution taskExecution) {
initialize(); initialize();
validateCreateInformation(taskExecution); validateCreateInformation(taskExecution);
TaskExecution daoTaskExecution = TaskExecution daoTaskExecution = this.taskExecutionDao.createTaskExecution(
taskExecutionDao.createTaskExecution( taskExecution.getTaskName(), taskExecution.getStartTime(),
taskExecution.getTaskName(), taskExecution.getArguments(), taskExecution.getExternalExecutionId(),
taskExecution.getStartTime(), taskExecution.getParentExecutionId());
taskExecution.getArguments(),
taskExecution.getExternalExecutionId(),
taskExecution.getParentExecutionId());
logger.debug("Creating: " + taskExecution.toString()); logger.debug("Creating: " + taskExecution.toString());
return daoTaskExecution; return daoTaskExecution;
} }
@@ -117,21 +129,20 @@ public class SimpleTaskRepository implements TaskRepository {
@Override @Override
public TaskExecution createTaskExecution(String name) { public TaskExecution createTaskExecution(String name) {
initialize(); initialize();
TaskExecution taskExecution = TaskExecution taskExecution = this.taskExecutionDao.createTaskExecution(name,
taskExecutionDao.createTaskExecution(name, null, null, Collections.<String>emptyList(), null);
Collections.<String>emptyList(), null);
logger.debug("Creating: " + taskExecution.toString()); logger.debug("Creating: " + taskExecution.toString());
return taskExecution; return taskExecution;
} }
@Override @Override
public TaskExecution createTaskExecution() { public TaskExecution createTaskExecution() {
return createTaskExecution((String)null); return createTaskExecution((String) null);
} }
@Override @Override
public TaskExecution startTaskExecution(long executionid, String taskName, Date startTime, List<String> arguments, public TaskExecution startTaskExecution(long executionid, String taskName,
String externalExecutionId) { Date startTime, List<String> arguments, String externalExecutionId) {
return startTaskExecution(executionid, taskName, startTime, arguments, return startTaskExecution(executionid, taskName, startTime, arguments,
externalExecutionId, null); externalExecutionId, null);
} }
@@ -139,7 +150,7 @@ public class SimpleTaskRepository implements TaskRepository {
@Override @Override
public void updateExternalExecutionId(long executionid, String externalExecutionId) { public void updateExternalExecutionId(long executionid, String externalExecutionId) {
initialize(); initialize();
taskExecutionDao.updateExternalExecutionId(executionid, externalExecutionId); this.taskExecutionDao.updateExternalExecutionId(executionid, externalExecutionId);
} }
@Override @Override
@@ -147,10 +158,9 @@ public class SimpleTaskRepository implements TaskRepository {
Date startTime, List<String> arguments, String externalExecutionId, Date startTime, List<String> arguments, String externalExecutionId,
Long parentExecutionId) { Long parentExecutionId) {
initialize(); initialize();
TaskExecution taskExecution = TaskExecution taskExecution = this.taskExecutionDao.startTaskExecution(
taskExecutionDao.startTaskExecution(executionid, taskName, executionid, taskName, startTime, arguments, externalExecutionId,
startTime, arguments, externalExecutionId, parentExecutionId);
parentExecutionId);
logger.debug("Starting: " + taskExecution.toString()); logger.debug("Starting: " + taskExecution.toString());
return taskExecution; return taskExecution;
} }
@@ -161,44 +171,47 @@ public class SimpleTaskRepository implements TaskRepository {
*/ */
public TaskExecutionDao getTaskExecutionDao() { public TaskExecutionDao getTaskExecutionDao() {
initialize(); initialize();
return taskExecutionDao; return this.taskExecutionDao;
} }
private void initialize() { private void initialize() {
if(!initialized) { if (!this.initialized) {
try { try {
this.taskExecutionDao = this.taskExecutionDaoFactoryBean.getObject(); this.taskExecutionDao = this.taskExecutionDaoFactoryBean.getObject();
this.initialized = true; this.initialized = true;
} }
catch (Exception e) { catch (Exception e) {
throw new IllegalStateException("Unable to create the TaskExecutionDao", e); throw new IllegalStateException("Unable to create the TaskExecutionDao",
e);
} }
} }
} }
/** /**
* Validate startTime and taskName are valid. * Validate startTime and taskName are valid.
* @param taskExecution task execution to validate
*/ */
private void validateCreateInformation(TaskExecution taskExecution) { private void validateCreateInformation(TaskExecution taskExecution) {
Assert.notNull(taskExecution.getStartTime(), "TaskExecution start time cannot be null."); Assert.notNull(taskExecution.getStartTime(),
"TaskExecution start time cannot be null.");
if (taskExecution.getTaskName() != null && if (taskExecution.getTaskName() != null
taskExecution.getTaskName().length() > this.maxTaskNameSize) { && taskExecution.getTaskName().length() > this.maxTaskNameSize) {
throw new IllegalArgumentException("TaskName length exceeds " throw new IllegalArgumentException(
+ this.maxTaskNameSize + " characters"); "TaskName length exceeds " + this.maxTaskNameSize + " characters");
} }
} }
private void validateCompletedTaskExitInformation(long executionId, Integer exitCode, Date endTime){ private void validateCompletedTaskExitInformation(long executionId, Integer exitCode,
Date endTime) {
Assert.notNull(exitCode, "exitCode should not be null"); Assert.notNull(exitCode, "exitCode should not be null");
Assert.isTrue(exitCode >= 0, "exit code must be greater than or equal to zero"); Assert.isTrue(exitCode >= 0, "exit code must be greater than or equal to zero");
Assert.notNull(endTime, "TaskExecution endTime cannot be null."); Assert.notNull(endTime, "TaskExecution endTime cannot be null.");
} }
private String trimMessage(String exitMessage, int maxSize){ private String trimMessage(String exitMessage, int maxSize) {
String result = exitMessage; String result = exitMessage;
if(exitMessage != null && if (exitMessage != null && exitMessage.length() > maxSize) {
exitMessage.length() > maxSize) {
result = exitMessage.substring(0, maxSize); result = exitMessage.substring(0, maxSize);
} }
return result; return result;
@@ -215,4 +228,5 @@ public class SimpleTaskRepository implements TaskRepository {
public void setMaxErrorMessageSize(int maxErrorMessageSize) { public void setMaxErrorMessageSize(int maxErrorMessageSize) {
this.maxErrorMessageSize = maxErrorMessageSize; this.maxErrorMessageSize = maxErrorMessageSize;
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.repository.support; package org.springframework.cloud.task.repository.support;
import javax.sql.DataSource; import javax.sql.DataSource;
@@ -43,7 +44,7 @@ public class TaskExecutionDaoFactoryBean implements FactoryBean<TaskExecutionDao
private String tablePrefix = TaskProperties.DEFAULT_TABLE_PREFIX; private String tablePrefix = TaskProperties.DEFAULT_TABLE_PREFIX;
/** /**
* Default constructor will result in a Map based TaskExecutionDao. <b>This is only * Default constructor will result in a Map based TaskExecutionDao. <b>This is only
* intended for testing purposes.</b> * intended for testing purposes.</b>
*/ */
public TaskExecutionDaoFactoryBean() { public TaskExecutionDaoFactoryBean() {
@@ -51,7 +52,6 @@ public class TaskExecutionDaoFactoryBean implements FactoryBean<TaskExecutionDao
/** /**
* {@link DataSource} to be used. * {@link DataSource} to be used.
*
* @param dataSource {@link DataSource} to be used. * @param dataSource {@link DataSource} to be used.
* @param tablePrefix the table prefix to use for this dao. * @param tablePrefix the table prefix to use for this dao.
*/ */
@@ -63,7 +63,6 @@ public class TaskExecutionDaoFactoryBean implements FactoryBean<TaskExecutionDao
/** /**
* {@link DataSource} to be used. * {@link DataSource} to be used.
*
* @param dataSource {@link DataSource} to be used. * @param dataSource {@link DataSource} to be used.
*/ */
public TaskExecutionDaoFactoryBean(DataSource dataSource) { public TaskExecutionDaoFactoryBean(DataSource dataSource) {
@@ -74,7 +73,7 @@ public class TaskExecutionDaoFactoryBean implements FactoryBean<TaskExecutionDao
@Override @Override
public TaskExecutionDao getObject() throws Exception { public TaskExecutionDao getObject() throws Exception {
if(this.dao == null) { if (this.dao == null) {
if (this.dataSource != null) { if (this.dataSource != null) {
buildTaskExecutionDao(this.dataSource); buildTaskExecutionDao(this.dataSource);
} }
@@ -97,15 +96,19 @@ public class TaskExecutionDaoFactoryBean implements FactoryBean<TaskExecutionDao
} }
private void buildTaskExecutionDao(DataSource dataSource) { private void buildTaskExecutionDao(DataSource dataSource) {
DataFieldMaxValueIncrementerFactory incrementerFactory = new DefaultDataFieldMaxValueIncrementerFactory(dataSource); DataFieldMaxValueIncrementerFactory incrementerFactory = new DefaultDataFieldMaxValueIncrementerFactory(
dataSource);
this.dao = new JdbcTaskExecutionDao(dataSource, this.tablePrefix); this.dao = new JdbcTaskExecutionDao(dataSource, this.tablePrefix);
String databaseType; String databaseType;
try { try {
databaseType = org.springframework.batch.support.DatabaseType.fromMetaData(dataSource).name(); databaseType = org.springframework.batch.support.DatabaseType
.fromMetaData(dataSource).name();
} }
catch (MetaDataAccessException e) { catch (MetaDataAccessException e) {
throw new IllegalStateException(e); throw new IllegalStateException(e);
} }
((JdbcTaskExecutionDao) this.dao).setTaskIncrementer(incrementerFactory.getIncrementer(databaseType, this.tablePrefix + "SEQ")); ((JdbcTaskExecutionDao) this.dao).setTaskIncrementer(incrementerFactory
.getIncrementer(databaseType, this.tablePrefix + "SEQ"));
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015-2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -32,11 +32,11 @@ import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
* Utility for initializing the Task Repository's datasource. If a single * Utility for initializing the Task Repository's datasource. If a single
* {@link DataSource} is available in the current context, and functionality is enabled * {@link DataSource} is available in the current context, and functionality is enabled
* (as it is by default), this will initialize the database. If more than one DataSource * (as it is by default), this will initialize the database. If more than one DataSource
* is available in the current context, custom configuration of this is required * is available in the current context, custom configuration of this is required (if
* (if desired). * desired).
* *
* By default, initialization of the database can be disabled by configuring the property * By default, initialization of the database can be disabled by configuring the property
* <code>spring.cloud.task.initialize.enable</code> to false. * <code>spring.cloud.task.initialize.enable</code> to false.
@@ -67,7 +67,7 @@ public final class TaskRepositoryInitializer implements InitializingBean {
@Value("${spring.cloud.task.tablePrefix:#{null}}") @Value("${spring.cloud.task.tablePrefix:#{null}}")
private String tablePrefix; private String tablePrefix;
public TaskRepositoryInitializer(){ public TaskRepositoryInitializer() {
} }
public void setDataSource(DataSource dataSource) { public void setDataSource(DataSource dataSource) {
@@ -81,7 +81,9 @@ public final class TaskRepositoryInitializer implements InitializingBean {
private String getDatabaseType(DataSource dataSource) { private String getDatabaseType(DataSource dataSource) {
try { try {
return JdbcUtils.commonDatabaseName(DatabaseType.fromMetaData(dataSource).toString()).toLowerCase(); return JdbcUtils
.commonDatabaseName(DatabaseType.fromMetaData(dataSource).toString())
.toLowerCase();
} }
catch (MetaDataAccessException ex) { catch (MetaDataAccessException ex) {
throw new IllegalStateException("Unable to detect database type", ex); throw new IllegalStateException("Unable to detect database type", ex);
@@ -90,10 +92,9 @@ public final class TaskRepositoryInitializer implements InitializingBean {
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
if (dataSource != null && if (this.dataSource != null && this.taskInitializationEnable
taskInitializationEnable && && !StringUtils.hasText(this.tablePrefix)) {
!StringUtils.hasText(this.tablePrefix)) { String platform = getDatabaseType(this.dataSource);
String platform = getDatabaseType(dataSource);
if ("hsql".equals(platform)) { if ("hsql".equals(platform)) {
platform = "hsqldb"; platform = "hsqldb";
} }
@@ -106,17 +107,18 @@ public final class TaskRepositoryInitializer implements InitializingBean {
if ("mysql".equals(platform)) { if ("mysql".equals(platform)) {
platform = "mysql"; platform = "mysql";
} }
if ("sqlserver".equals(platform)){ if ("sqlserver".equals(platform)) {
platform = "sqlserver"; platform = "sqlserver";
} }
ResourceDatabasePopulator populator = new ResourceDatabasePopulator(); ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
String schemaLocation = schema; String schemaLocation = schema;
schemaLocation = schemaLocation.replace("@@platform@@", platform); schemaLocation = schemaLocation.replace("@@platform@@", platform);
populator.addScript(resourceLoader.getResource(schemaLocation)); populator.addScript(this.resourceLoader.getResource(schemaLocation));
populator.setContinueOnError(true); populator.setContinueOnError(true);
logger.debug(String.format("Initializing task schema for %s database", logger.debug(
platform)); String.format("Initializing task schema for %s database", platform));
DatabasePopulatorUtils.execute(populator, dataSource); DatabasePopulatorUtils.execute(populator, this.dataSource);
} }
} }
} }

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2015-2019 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.
*/
/** /**
* Classes used for setting up and supporting a task repositories. * Classes used for setting up and supporting a task repositories.
*/ */

View File

@@ -1,10 +1,10 @@
{ {
"properties": [ "properties": [
{ {
"defaultValue": false, "defaultValue": false,
"name": "spring.cloud.task.single-instance-enabled", "name": "spring.cloud.task.single-instance-enabled",
"description": "This property is used to determine if a task will execute if another task with the same app name is running.", "description": "This property is used to determine if a task will execute if another task with the same app name is running.",
"type": "java.lang.Boolean" "type": "java.lang.Boolean"
} }
] ]
} }

View File

@@ -1,17 +1,17 @@
/* /*
* Copyright 2017-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task; package org.springframework.cloud.task;
@@ -25,8 +25,7 @@ import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration;
import org.springframework.cloud.task.configuration.SingleInstanceTaskListener; import org.springframework.cloud.task.configuration.SingleInstanceTaskListener;
import org.springframework.cloud.task.configuration.SingleTaskConfiguration; import org.springframework.cloud.task.configuration.SingleTaskConfiguration;
import static org.junit.Assert.assertEquals; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertNotNull;
/** /**
* Verifies that the beans created by the SimpleSingleTaskAutoConfigurationConfiguration * Verifies that the beans created by the SimpleSingleTaskAutoConfigurationConfiguration
@@ -43,15 +42,18 @@ public class SimpleSingleTaskAutoConfigurationTests {
ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of( .withConfiguration(AutoConfigurations.of(
PropertyPlaceholderAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,
SimpleTaskAutoConfiguration.class, SimpleTaskAutoConfiguration.class, SingleTaskConfiguration.class))
SingleTaskConfiguration.class))
.withPropertyValues("spring.cloud.task.singleInstanceEnabled=true"); .withPropertyValues("spring.cloud.task.singleInstanceEnabled=true");
applicationContextRunner.run((context) -> { applicationContextRunner.run((context) -> {
SingleInstanceTaskListener singleInstanceTaskListener = context.getBean(SingleInstanceTaskListener.class); SingleInstanceTaskListener singleInstanceTaskListener = context
.getBean(SingleInstanceTaskListener.class);
assertNotNull("singleInstanceTaskListener should not be null", singleInstanceTaskListener); assertThat(singleInstanceTaskListener)
.as("singleInstanceTaskListener should not be null").isNotNull();
assertEquals(singleInstanceTaskListener.getClass(), SingleInstanceTaskListener.class); }); assertThat(SingleInstanceTaskListener.class)
.isEqualTo(singleInstanceTaskListener.getClass());
});
} }
} }

View File

@@ -1,17 +1,17 @@
/* /*
* Copyright 2017-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task; package org.springframework.cloud.task;
@@ -26,8 +26,7 @@ import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration;
import org.springframework.cloud.task.configuration.SingleInstanceTaskListener; import org.springframework.cloud.task.configuration.SingleInstanceTaskListener;
import org.springframework.cloud.task.configuration.SingleTaskConfiguration; import org.springframework.cloud.task.configuration.SingleTaskConfiguration;
import static org.junit.Assert.assertEquals; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertNotNull;
/** /**
* Verifies that the beans created by the SimpleSingleTaskAutoConfigurationConfiguration * Verifies that the beans created by the SimpleSingleTaskAutoConfigurationConfiguration
@@ -44,16 +43,19 @@ public class SimpleSingleTaskAutoConfigurationWithDataSourceTests {
ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of( .withConfiguration(AutoConfigurations.of(
PropertyPlaceholderAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,
SimpleTaskAutoConfiguration.class, SimpleTaskAutoConfiguration.class, SingleTaskConfiguration.class,
SingleTaskConfiguration.class,
EmbeddedDataSourceConfiguration.class)) EmbeddedDataSourceConfiguration.class))
.withPropertyValues("spring.cloud.task.singleInstanceEnabled=true"); .withPropertyValues("spring.cloud.task.singleInstanceEnabled=true");
applicationContextRunner.run((context) -> { applicationContextRunner.run((context) -> {
SingleInstanceTaskListener singleInstanceTaskListener = context.getBean(SingleInstanceTaskListener.class); SingleInstanceTaskListener singleInstanceTaskListener = context
.getBean(SingleInstanceTaskListener.class);
assertNotNull("singleInstanceTaskListener should not be null", singleInstanceTaskListener); assertThat(singleInstanceTaskListener)
.as("singleInstanceTaskListener should not be null").isNotNull();
assertEquals(singleInstanceTaskListener.getClass(), SingleInstanceTaskListener.class); assertThat(SingleInstanceTaskListener.class)
.isEqualTo(singleInstanceTaskListener.getClass());
}); });
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -48,7 +48,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
/** /**
@@ -71,10 +71,10 @@ public class SimpleTaskAutoConfigurationTests {
@Test @Test
public void testRepository() { public void testRepository() {
ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of( .withConfiguration(
PropertyPlaceholderAutoConfiguration.class, AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class,
SimpleTaskAutoConfiguration.class, SimpleTaskAutoConfiguration.class,
SingleTaskConfiguration.class)); SingleTaskConfiguration.class));
applicationContextRunner.run((context) -> { applicationContextRunner.run((context) -> {
TaskRepository taskRepository = context.getBean(TaskRepository.class); TaskRepository taskRepository = context.getBean(TaskRepository.class);
@@ -89,50 +89,50 @@ public class SimpleTaskAutoConfigurationTests {
ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of( .withConfiguration(AutoConfigurations.of(
PropertyPlaceholderAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,
SimpleTaskAutoConfiguration.class, SimpleTaskAutoConfiguration.class, SingleTaskConfiguration.class))
SingleTaskConfiguration.class))
.withPropertyValues("spring.cloud.task.autoconfiguration.enabled=false"); .withPropertyValues("spring.cloud.task.autoconfiguration.enabled=false");
Executable executable = () -> { Executable executable = () -> {
applicationContextRunner.run((context) -> { applicationContextRunner.run((context) -> {
context.getBean(TaskRepository.class); context.getBean(TaskRepository.class);
}); });
}; };
verifyExceptionThrown(NoSuchBeanDefinitionException.class, "No qualifying " + verifyExceptionThrown(NoSuchBeanDefinitionException.class, "No qualifying "
"bean of type 'org.springframework.cloud.task.repository.TaskRepository' " + + "bean of type 'org.springframework.cloud.task.repository.TaskRepository' "
"available", executable); + "available", executable);
} }
@Test @Test
public void testRepositoryInitialized() { public void testRepositoryInitialized() {
ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(EmbeddedDataSourceConfiguration.class, .withConfiguration(AutoConfigurations.of(
EmbeddedDataSourceConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,
SimpleTaskAutoConfiguration.class, SimpleTaskAutoConfiguration.class, SingleTaskConfiguration.class))
SingleTaskConfiguration.class))
.withUserConfiguration(TaskLifecycleListenerConfiguration.class); .withUserConfiguration(TaskLifecycleListenerConfiguration.class);
applicationContextRunner.run((context) -> { applicationContextRunner.run((context) -> {
TaskExplorer taskExplorer = context.getBean(TaskExplorer.class); TaskExplorer taskExplorer = context.getBean(TaskExplorer.class);
assertThat(taskExplorer.getTaskExecutionCount()).isEqualTo(1l); assertThat(taskExplorer.getTaskExecutionCount()).isEqualTo(1L);
}); });
} }
@Test @Test
public void testRepositoryNotInitialized() { public void testRepositoryNotInitialized() {
ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(EmbeddedDataSourceConfiguration.class, .withConfiguration(AutoConfigurations.of(
EmbeddedDataSourceConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,
SimpleTaskAutoConfiguration.class, SimpleTaskAutoConfiguration.class, SingleTaskConfiguration.class))
SingleTaskConfiguration.class))
.withUserConfiguration(TaskLifecycleListenerConfiguration.class) .withUserConfiguration(TaskLifecycleListenerConfiguration.class)
.withPropertyValues("spring.cloud.task.tablePrefix=foobarless"); .withPropertyValues("spring.cloud.task.tablePrefix=foobarless");
verifyExceptionThrownDefaultExecutable(ApplicationContextException.class, "Failed to start " + verifyExceptionThrownDefaultExecutable(ApplicationContextException.class,
"bean 'taskLifecycleListener'; nested exception is " + "Failed to start " + "bean 'taskLifecycleListener'; nested exception is "
"org.springframework.dao.DataAccessResourceFailureException: " + + "org.springframework.dao.DataAccessResourceFailureException: "
"Could not obtain sequence value; nested exception is org.h2.jdbc.JdbcSQLException: " + + "Could not obtain sequence value; nested exception is org.h2.jdbc.JdbcSQLException: "
"Syntax error in SQL statement \"SELECT FOOBARLESSSEQ.NEXTVAL FROM[*] DUAL \"; " + + "Syntax error in SQL statement \"SELECT FOOBARLESSSEQ.NEXTVAL FROM[*] DUAL \"; "
"expected \"identifier\"; SQL statement:\n" + + "expected \"identifier\"; SQL statement:\n"
"select foobarlessSEQ.nextval from dual [42001-197]", applicationContextRunner); + "select foobarlessSEQ.nextval from dual [42001-197]",
applicationContextRunner);
} }
@Test @Test
@@ -140,29 +140,32 @@ public class SimpleTaskAutoConfigurationTests {
ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of( .withConfiguration(AutoConfigurations.of(
PropertyPlaceholderAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,
SimpleTaskAutoConfiguration.class, SimpleTaskAutoConfiguration.class, SingleTaskConfiguration.class))
SingleTaskConfiguration.class))
.withUserConfiguration(MultipleConfigurers.class); .withUserConfiguration(MultipleConfigurers.class);
verifyExceptionThrownDefaultExecutable(BeanCreationException.class, "Error creating bean " + verifyExceptionThrownDefaultExecutable(BeanCreationException.class,
"with name 'simpleTaskAutoConfiguration': Invocation of init " + "Error creating bean "
"method failed; nested exception is java.lang.IllegalStateException:" + + "with name 'simpleTaskAutoConfiguration': Invocation of init "
" Expected one TaskConfigurer but found 2", applicationContextRunner); + "method failed; nested exception is java.lang.IllegalStateException:"
+ " Expected one TaskConfigurer but found 2",
applicationContextRunner);
} }
@Test @Test
public void testMultipleDataSources() { public void testMultipleDataSources() {
ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class, .withConfiguration(AutoConfigurations.of(
SimpleTaskAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,
SingleTaskConfiguration.class)) SimpleTaskAutoConfiguration.class, SingleTaskConfiguration.class))
.withUserConfiguration(MultipleDataSources.class); .withUserConfiguration(MultipleDataSources.class);
verifyExceptionThrownDefaultExecutable(BeanCreationException.class, "Error creating bean " + verifyExceptionThrownDefaultExecutable(BeanCreationException.class,
"with name 'simpleTaskAutoConfiguration': Invocation of init method " + "Error creating bean "
"failed; nested exception is java.lang.IllegalStateException: To use " + + "with name 'simpleTaskAutoConfiguration': Invocation of init method "
"the default TaskConfigurer the context must contain no more than " + + "failed; nested exception is java.lang.IllegalStateException: To use "
"one DataSource, found 2", applicationContextRunner); + "the default TaskConfigurer the context must contain no more than "
+ "one DataSource, found 2",
applicationContextRunner);
} }
@@ -178,14 +181,15 @@ public class SimpleTaskAutoConfigurationTests {
verifyExceptionThrown(classToCheck, message, executable); verifyExceptionThrown(classToCheck, message, executable);
} }
public void verifyExceptionThrown(Class classToCheck, String message, Executable executable) { public void verifyExceptionThrown(Class classToCheck, String message,
Throwable exception = assertThrows(classToCheck, executable); Executable executable) {
assertThat(exception.getMessage()).isEqualTo(message); assertThatExceptionOfType(classToCheck).isThrownBy(executable::execute)
.withMessage(message);
} }
/** /**
* Verify that the verifyEnvironment method skips DataSource Proxy Beans when determining * Verify that the verifyEnvironment method skips DataSource Proxy Beans when
* the number of available dataSources. * determining the number of available dataSources.
*/ */
@Test @Test
public void testWithDataSourceProxy() { public void testWithDataSourceProxy() {
@@ -193,12 +197,12 @@ public class SimpleTaskAutoConfigurationTests {
.withConfiguration(AutoConfigurations.of( .withConfiguration(AutoConfigurations.of(
EmbeddedDataSourceConfiguration.class, EmbeddedDataSourceConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,
SimpleTaskAutoConfiguration.class, SimpleTaskAutoConfiguration.class, SingleTaskConfiguration.class))
SingleTaskConfiguration.class))
.withUserConfiguration(DataSourceProxyConfiguration.class); .withUserConfiguration(DataSourceProxyConfiguration.class);
applicationContextRunner.run((context) -> { applicationContextRunner.run((context) -> {
assertThat(context.getBeanNamesForType(DataSource.class).length).isEqualTo(2); assertThat(context.getBeanNamesForType(DataSource.class).length).isEqualTo(2);
SimpleTaskAutoConfiguration taskConfiguration = context.getBean(SimpleTaskAutoConfiguration.class); SimpleTaskAutoConfiguration taskConfiguration = context
.getBean(SimpleTaskAutoConfiguration.class);
assertThat(taskConfiguration).isNotNull(); assertThat(taskConfiguration).isNotNull();
assertThat(taskConfiguration.taskExplorer()).isNotNull(); assertThat(taskConfiguration.taskExplorer()).isNotNull();
}); });
@@ -216,6 +220,7 @@ public class SimpleTaskAutoConfigurationTests {
public TaskConfigurer taskConfigurer2() { public TaskConfigurer taskConfigurer2() {
return new DefaultTaskConfigurer((DataSource) null); return new DefaultTaskConfigurer((DataSource) null);
} }
} }
@Configuration @Configuration
@@ -243,9 +248,10 @@ public class SimpleTaskAutoConfigurationTests {
public BeanDefinitionHolder proxyDataSource() { public BeanDefinitionHolder proxyDataSource() {
GenericBeanDefinition proxyBeanDefinition = new GenericBeanDefinition(); GenericBeanDefinition proxyBeanDefinition = new GenericBeanDefinition();
proxyBeanDefinition.setBeanClassName("javax.sql.DataSource"); proxyBeanDefinition.setBeanClassName("javax.sql.DataSource");
BeanDefinitionHolder myDataSource = new BeanDefinitionHolder(proxyBeanDefinition, "dataSource2"); BeanDefinitionHolder myDataSource = new BeanDefinitionHolder(
ScopedProxyUtils.createScopedProxy(myDataSource, (BeanDefinitionRegistry) this.context.getBeanFactory(), proxyBeanDefinition, "dataSource2");
true); ScopedProxyUtils.createScopedProxy(myDataSource,
(BeanDefinitionRegistry) this.context.getBeanFactory(), true);
return myDataSource; return myDataSource;
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -31,7 +31,7 @@ import org.springframework.context.ApplicationContextException;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import static org.junit.Assert.assertTrue; import static org.assertj.core.api.Assertions.assertThat;
/** /**
* Verifies core behavior for Tasks. * Verifies core behavior for Tasks.
@@ -41,42 +41,49 @@ import static org.junit.Assert.assertTrue;
public class TaskCoreTests { public class TaskCoreTests {
private static final String TASK_NAME = "taskEventTest"; private static final String TASK_NAME = "taskEventTest";
private static final String EXCEPTION_MESSAGE = "FOO EXCEPTION";
private static final String CREATE_TASK_MESSAGE = "Creating: TaskExecution{executionId=";
private static final String UPDATE_TASK_MESSAGE = "Updating: TaskExecution with executionId=";
private static final String SUCCESS_EXIT_CODE_MESSAGE = "with the following {exitCode=0";
private static final String EXCEPTION_EXIT_CODE_MESSAGE = "with the following {exitCode=1";
private static final String EXCEPTION_INVALID_TASK_EXECUTION_ID =
"java.lang.IllegalArgumentException: Invalid TaskExecution, ID 55 not found";
private static final String ERROR_MESSAGE =
"errorMessage='java.lang.IllegalStateException: Failed to execute CommandLineRunner";
private ConfigurableApplicationContext applicationContext; private static final String EXCEPTION_MESSAGE = "FOO EXCEPTION";
private static final String CREATE_TASK_MESSAGE = "Creating: TaskExecution{executionId=";
private static final String UPDATE_TASK_MESSAGE = "Updating: TaskExecution with executionId=";
private static final String SUCCESS_EXIT_CODE_MESSAGE = "with the following {exitCode=0";
private static final String EXCEPTION_EXIT_CODE_MESSAGE = "with the following {exitCode=1";
private static final String EXCEPTION_INVALID_TASK_EXECUTION_ID = "java.lang.IllegalArgumentException: "
+ "Invalid TaskExecution, ID 55 not found";
private static final String ERROR_MESSAGE = "errorMessage='java.lang.IllegalStateException: "
+ "Failed to execute CommandLineRunner";
@Rule @Rule
public OutputCapture outputCapture = new OutputCapture(); public OutputCapture outputCapture = new OutputCapture();
private ConfigurableApplicationContext applicationContext;
@After @After
public void teardown() { public void teardown() {
if (applicationContext != null && applicationContext.isActive()) { if (this.applicationContext != null && this.applicationContext.isActive()) {
applicationContext.close(); this.applicationContext.close();
} }
} }
@Test @Test
public void successfulTaskTest() { public void successfulTaskTest() {
this.applicationContext = SpringApplication.run( TaskConfiguration.class, this.applicationContext = SpringApplication.run(TaskConfiguration.class,
"--spring.cloud.task.closecontext.enable=false", "--spring.cloud.task.closecontext.enable=false",
"--spring.cloud.task.name=" + TASK_NAME, "--spring.cloud.task.name=" + TASK_NAME,
"--spring.main.web-environment=false"); "--spring.main.web-environment=false");
String output = this.outputCapture.toString(); String output = this.outputCapture.toString();
assertTrue("Test results do not show create task message: " + output, assertThat(output.contains(CREATE_TASK_MESSAGE))
output.contains(CREATE_TASK_MESSAGE)); .as("Test results do not show create task message: " + output).isTrue();
assertTrue("Test results do not show success message: " + output, assertThat(output.contains(UPDATE_TASK_MESSAGE))
output.contains(UPDATE_TASK_MESSAGE)); .as("Test results do not show success message: " + output).isTrue();
assertTrue("Test results have incorrect exit code: " + output, assertThat(output.contains(SUCCESS_EXIT_CODE_MESSAGE))
output.contains(SUCCESS_EXIT_CODE_MESSAGE)); .as("Test results have incorrect exit code: " + output).isTrue();
} }
/** /**
@@ -84,25 +91,27 @@ public class TaskCoreTests {
*/ */
@Test @Test
public void successfulTaskTestWithAnnotation() { public void successfulTaskTestWithAnnotation() {
this.applicationContext = SpringApplication.run( TaskConfigurationWithAnotation.class, this.applicationContext = SpringApplication.run(
TaskConfigurationWithAnotation.class,
"--spring.cloud.task.closecontext.enable=false", "--spring.cloud.task.closecontext.enable=false",
"--spring.cloud.task.name=" + TASK_NAME, "--spring.cloud.task.name=" + TASK_NAME,
"--spring.main.web-environment=false"); "--spring.main.web-environment=false");
String output = this.outputCapture.toString(); String output = this.outputCapture.toString();
assertTrue("Test results do not show create task message: " + output, assertThat(output.contains(CREATE_TASK_MESSAGE))
output.contains(CREATE_TASK_MESSAGE)); .as("Test results do not show create task message: " + output).isTrue();
assertTrue("Test results do not show success message: " + output, assertThat(output.contains(UPDATE_TASK_MESSAGE))
output.contains(UPDATE_TASK_MESSAGE)); .as("Test results do not show success message: " + output).isTrue();
assertTrue("Test results have incorrect exit code: " + output, assertThat(output.contains(SUCCESS_EXIT_CODE_MESSAGE))
output.contains(SUCCESS_EXIT_CODE_MESSAGE)); .as("Test results have incorrect exit code: " + output).isTrue();
} }
@Test @Test
public void exceptionTaskTest() { public void exceptionTaskTest() {
boolean exceptionFired = false; boolean exceptionFired = false;
try { try {
this.applicationContext = SpringApplication.run( TaskExceptionConfiguration.class, this.applicationContext = SpringApplication.run(
TaskExceptionConfiguration.class,
"--spring.cloud.task.closecontext.enable=false", "--spring.cloud.task.closecontext.enable=false",
"--spring.cloud.task.name=" + TASK_NAME, "--spring.cloud.task.name=" + TASK_NAME,
"--spring.main.web-environment=false"); "--spring.main.web-environment=false");
@@ -110,19 +119,20 @@ public class TaskCoreTests {
catch (IllegalStateException exception) { catch (IllegalStateException exception) {
exceptionFired = true; exceptionFired = true;
} }
assertTrue("An IllegalStateException should have been thrown", exceptionFired); assertThat(exceptionFired).as("An IllegalStateException should have been thrown")
.isTrue();
String output = this.outputCapture.toString(); String output = this.outputCapture.toString();
assertTrue("Test results do not show create task message: " + output, assertThat(output.contains(CREATE_TASK_MESSAGE))
output.contains(CREATE_TASK_MESSAGE)); .as("Test results do not show create task message: " + output).isTrue();
assertTrue("Test results do not show success message: " + output, assertThat(output.contains(UPDATE_TASK_MESSAGE))
output.contains(UPDATE_TASK_MESSAGE)); .as("Test results do not show success message: " + output).isTrue();
assertTrue("Test results have incorrect exit code: " + output, assertThat(output.contains(EXCEPTION_EXIT_CODE_MESSAGE))
output.contains(EXCEPTION_EXIT_CODE_MESSAGE)); .as("Test results have incorrect exit code: " + output).isTrue();
assertTrue("Test results have incorrect exit message: " + output, assertThat(output.contains(ERROR_MESSAGE))
output.contains(ERROR_MESSAGE)); .as("Test results have incorrect exit message: " + output).isTrue();
assertTrue("Test results have exception message: " + output, assertThat(output.contains(EXCEPTION_MESSAGE))
output.contains(EXCEPTION_MESSAGE)); .as("Test results have exception message: " + output).isTrue();
} }
@Test @Test
@@ -130,7 +140,8 @@ public class TaskCoreTests {
boolean exceptionFired = false; boolean exceptionFired = false;
try { try {
this.applicationContext = SpringApplication.run( this.applicationContext = SpringApplication.run(
TaskExceptionConfiguration.class, "--spring.cloud.task.closecontext.enable=false", TaskExceptionConfiguration.class,
"--spring.cloud.task.closecontext.enable=false",
"--spring.cloud.task.name=" + TASK_NAME, "--spring.cloud.task.name=" + TASK_NAME,
"--spring.main.web-environment=false", "--spring.main.web-environment=false",
"--spring.cloud.task.executionid=55"); "--spring.cloud.task.executionid=55");
@@ -138,15 +149,18 @@ public class TaskCoreTests {
catch (ApplicationContextException exception) { catch (ApplicationContextException exception) {
exceptionFired = true; exceptionFired = true;
} }
assertTrue("An ApplicationContextException should have been thrown", exceptionFired); assertThat(exceptionFired)
.as("An ApplicationContextException should have been thrown").isTrue();
String output = this.outputCapture.toString(); String output = this.outputCapture.toString();
assertTrue("Test results do not show the correct exception message: " + output, assertThat(output.contains(EXCEPTION_INVALID_TASK_EXECUTION_ID))
output.contains(EXCEPTION_INVALID_TASK_EXECUTION_ID)); .as("Test results do not show the correct exception message: " + output)
.isTrue();
} }
@EnableTask @EnableTask
@ImportAutoConfiguration({SimpleTaskAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class}) @ImportAutoConfiguration({ SimpleTaskAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
public static class TaskConfiguration { public static class TaskConfiguration {
@Bean @Bean
@@ -157,10 +171,12 @@ public class TaskCoreTests {
} }
}; };
} }
} }
@EnableTask @EnableTask
@ImportAutoConfiguration({SimpleTaskAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class}) @ImportAutoConfiguration({ SimpleTaskAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
public static class TaskConfigurationWithAnotation { public static class TaskConfigurationWithAnotation {
@Bean @Bean
@@ -171,10 +187,12 @@ public class TaskCoreTests {
} }
}; };
} }
} }
@EnableTask @EnableTask
@ImportAutoConfiguration({SimpleTaskAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class}) @ImportAutoConfiguration({ SimpleTaskAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
public static class TaskExceptionConfiguration { public static class TaskExceptionConfiguration {
@Bean @Bean
@@ -186,5 +204,7 @@ public class TaskCoreTests {
} }
}; };
} }
} }
} }

View File

@@ -1,17 +1,17 @@
/* /*
* Copyright 2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task; package org.springframework.cloud.task;
@@ -36,15 +36,15 @@ import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
/** /**
* Verifies that TaskRepositoryInitializer creates tables if a {@link TaskConfigurer} * Verifies that TaskRepositoryInitializer creates tables if a {@link TaskConfigurer} has
* has a {@link DataSource}. * a {@link DataSource}.
* *
* @author Glenn Renfro * @author Glenn Renfro
* @since 2.0.0 * @since 2.0.0
*/ */
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@ContextConfiguration(classes = {SimpleTaskAutoConfiguration.class, @ContextConfiguration(classes = { SimpleTaskAutoConfiguration.class,
EmbeddedDataSourceConfiguration.class}) EmbeddedDataSourceConfiguration.class })
@DirtiesContext @DirtiesContext
public class TaskRepositoryInitializerDefaultTaskConfigurerTests { public class TaskRepositoryInitializerDefaultTaskConfigurerTests {
@@ -53,8 +53,9 @@ public class TaskRepositoryInitializerDefaultTaskConfigurerTests {
@Test @Test
public void testTablesCreated() { public void testTablesCreated() {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); JdbcTemplate jdbcTemplate = new JdbcTemplate(this.dataSource);
List<Map<String, Object>> rows= jdbcTemplate.queryForList("SHOW TABLES"); List<Map<String, Object>> rows = jdbcTemplate.queryForList("SHOW TABLES");
assertThat(rows.size()).isEqualTo(4); assertThat(rows.size()).isEqualTo(4);
} }
} }

View File

@@ -1,17 +1,17 @@
/* /*
* Copyright 2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task; package org.springframework.cloud.task;
@@ -37,16 +37,16 @@ import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
/** /**
* Verifies that TaskRepositoryInitializer does not create tables if a {@link TaskConfigurer} * Verifies that TaskRepositoryInitializer does not create tables if a
* has no {@link DataSource}. * {@link TaskConfigurer} has no {@link DataSource}.
* *
* @author Glenn Renfro * @author Glenn Renfro
* @since 2.0.0 * @since 2.0.0
*/ */
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@ContextConfiguration(classes = {SimpleTaskAutoConfiguration.class, SingleTaskConfiguration.class, @ContextConfiguration(classes = { SimpleTaskAutoConfiguration.class,
EmbeddedDataSourceConfiguration.class, SingleTaskConfiguration.class, EmbeddedDataSourceConfiguration.class,
DefaultTaskConfigurer.class}) DefaultTaskConfigurer.class })
public class TaskRepositoryInitializerNoDataSourceTaskConfigurerTests { public class TaskRepositoryInitializerNoDataSourceTaskConfigurerTests {
@Autowired @Autowired
@@ -54,8 +54,9 @@ public class TaskRepositoryInitializerNoDataSourceTaskConfigurerTests {
@Test @Test
public void testNoTablesCreated() { public void testNoTablesCreated() {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); JdbcTemplate jdbcTemplate = new JdbcTemplate(this.dataSource);
List<Map<String, Object>> rows= jdbcTemplate.queryForList("SHOW TABLES"); List<Map<String, Object>> rows = jdbcTemplate.queryForList("SHOW TABLES");
assertThat(rows.size()).isEqualTo(0); assertThat(rows.size()).isEqualTo(0);
} }
} }

View File

@@ -1,17 +1,17 @@
/* /*
* Copyright 2017 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.configuration; package org.springframework.cloud.task.configuration;
@@ -31,11 +31,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import static org.hamcrest.CoreMatchers.equalTo; import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
/** /**
@@ -54,64 +50,80 @@ public class DefaultTaskConfigurerTests {
@Test @Test
public void resourcelessTransactionManagerTest() { public void resourcelessTransactionManagerTest() {
DefaultTaskConfigurer defaultTaskConfigurer = new DefaultTaskConfigurer(); DefaultTaskConfigurer defaultTaskConfigurer = new DefaultTaskConfigurer();
assertThat(defaultTaskConfigurer.getTransactionManager().getClass().getName(), assertThat(defaultTaskConfigurer.getTransactionManager().getClass().getName())
is("org.springframework.batch.support.transaction.ResourcelessTransactionManager")); .isEqualTo(
"org.springframework.batch.support.transaction.ResourcelessTransactionManager");
defaultTaskConfigurer = new DefaultTaskConfigurer("foo"); defaultTaskConfigurer = new DefaultTaskConfigurer("foo");
assertThat(defaultTaskConfigurer.getTransactionManager().getClass().getName(), assertThat(defaultTaskConfigurer.getTransactionManager().getClass().getName())
is("org.springframework.batch.support.transaction.ResourcelessTransactionManager")); .isEqualTo(
"org.springframework.batch.support.transaction.ResourcelessTransactionManager");
} }
@Test @Test
public void testDefaultContext() throws Exception { public void testDefaultContext() throws Exception {
AnnotationConfigApplicationContext localContext = new AnnotationConfigApplicationContext(); AnnotationConfigApplicationContext localContext = new AnnotationConfigApplicationContext();
localContext.register(EmbeddedDataSourceConfiguration.class,EntityManagerConfiguration.class); localContext.register(EmbeddedDataSourceConfiguration.class,
EntityManagerConfiguration.class);
localContext.refresh(); localContext.refresh();
DefaultTaskConfigurer defaultTaskConfigurer = new DefaultTaskConfigurer(dataSource, TaskProperties.DEFAULT_TABLE_PREFIX, localContext); DefaultTaskConfigurer defaultTaskConfigurer = new DefaultTaskConfigurer(
assertThat(defaultTaskConfigurer.getTransactionManager().getClass().getName(), is(equalTo("org.springframework.orm.jpa.JpaTransactionManager"))); this.dataSource, TaskProperties.DEFAULT_TABLE_PREFIX, localContext);
assertThat(defaultTaskConfigurer.getTransactionManager().getClass().getName())
.isEqualTo("org.springframework.orm.jpa.JpaTransactionManager");
} }
@Test @Test
public void dataSourceTransactionManagerTest() { public void dataSourceTransactionManagerTest() {
DefaultTaskConfigurer defaultTaskConfigurer = new DefaultTaskConfigurer(dataSource); DefaultTaskConfigurer defaultTaskConfigurer = new DefaultTaskConfigurer(
assertThat(defaultTaskConfigurer.getTransactionManager().getClass().getName(), this.dataSource);
is("org.springframework.jdbc.datasource.DataSourceTransactionManager")); assertThat(defaultTaskConfigurer.getTransactionManager().getClass().getName())
defaultTaskConfigurer = new DefaultTaskConfigurer(dataSource, "FOO", null); .isEqualTo(
assertThat(defaultTaskConfigurer.getTransactionManager().getClass().getName(), "org.springframework.jdbc.datasource.DataSourceTransactionManager");
is("org.springframework.jdbc.datasource.DataSourceTransactionManager")); defaultTaskConfigurer = new DefaultTaskConfigurer(this.dataSource, "FOO", null);
defaultTaskConfigurer = new DefaultTaskConfigurer(dataSource, "FOO", context); assertThat(defaultTaskConfigurer.getTransactionManager().getClass().getName())
assertThat(defaultTaskConfigurer.getTransactionManager().getClass().getName(), .isEqualTo(
is("org.springframework.jdbc.datasource.DataSourceTransactionManager")); "org.springframework.jdbc.datasource.DataSourceTransactionManager");
defaultTaskConfigurer = new DefaultTaskConfigurer(this.dataSource, "FOO",
this.context);
assertThat(defaultTaskConfigurer.getTransactionManager().getClass().getName())
.isEqualTo(
"org.springframework.jdbc.datasource.DataSourceTransactionManager");
} }
@Test @Test
public void taskExplorerTest() { public void taskExplorerTest() {
DefaultTaskConfigurer defaultTaskConfigurer = new DefaultTaskConfigurer(dataSource); DefaultTaskConfigurer defaultTaskConfigurer = new DefaultTaskConfigurer(
assertThat(defaultTaskConfigurer.getTaskExplorer(), is(notNullValue())); this.dataSource);
assertThat(defaultTaskConfigurer.getTaskExplorer()).isNotNull();
defaultTaskConfigurer = new DefaultTaskConfigurer(); defaultTaskConfigurer = new DefaultTaskConfigurer();
assertThat(defaultTaskConfigurer.getTaskExplorer(), is(notNullValue())); assertThat(defaultTaskConfigurer.getTaskExplorer()).isNotNull();
} }
@Test @Test
public void taskRepositoryTest() { public void taskRepositoryTest() {
DefaultTaskConfigurer defaultTaskConfigurer = new DefaultTaskConfigurer(dataSource); DefaultTaskConfigurer defaultTaskConfigurer = new DefaultTaskConfigurer(
assertThat(defaultTaskConfigurer.getTaskRepository(), is(notNullValue())); this.dataSource);
assertThat(defaultTaskConfigurer.getTaskRepository()).isNotNull();
defaultTaskConfigurer = new DefaultTaskConfigurer(); defaultTaskConfigurer = new DefaultTaskConfigurer();
assertThat(defaultTaskConfigurer.getTaskRepository(), is(notNullValue())); assertThat(defaultTaskConfigurer.getTaskRepository()).isNotNull();
} }
@Test @Test
public void taskDataSource() { public void taskDataSource() {
DefaultTaskConfigurer defaultTaskConfigurer = new DefaultTaskConfigurer(dataSource); DefaultTaskConfigurer defaultTaskConfigurer = new DefaultTaskConfigurer(
assertThat(defaultTaskConfigurer.getTaskDataSource(), is(notNullValue())); this.dataSource);
assertThat(defaultTaskConfigurer.getTaskDataSource()).isNotNull();
defaultTaskConfigurer = new DefaultTaskConfigurer(); defaultTaskConfigurer = new DefaultTaskConfigurer();
assertThat(defaultTaskConfigurer.getTaskDataSource(), is(nullValue())); assertThat(defaultTaskConfigurer.getTaskDataSource()).isNull();
} }
@Configuration @Configuration
public static class EntityManagerConfiguration { public static class EntityManagerConfiguration {
@Bean @Bean
public EntityManager entityManager() { public EntityManager entityManager() {
return mock(EntityManager.class); return mock(EntityManager.class);
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2017-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -27,36 +27,37 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import static org.hamcrest.core.Is.is; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertThat;
@RunWith(Suite.class) @RunWith(Suite.class)
@SuiteClasses({ @SuiteClasses({ TaskPropertiesTests.CloseContextEnabledTest.class
TaskPropertiesTests.CloseContextEnabledTest.class
}) })
@DirtiesContext @DirtiesContext
public class TaskPropertiesTests { public class TaskPropertiesTests {
@Autowired @Autowired
TaskProperties taskProperties; TaskProperties taskProperties;
@Test @Test
public void test() { public void test() {
assertThat(taskProperties.getClosecontextEnabled(), is(false)); assertThat(this.taskProperties.getClosecontextEnabled()).isFalse();
} }
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@SpringBootTest(classes={TaskPropertiesTests.Config.class, @SpringBootTest(classes = { TaskPropertiesTests.Config.class,
SimpleTaskAutoConfiguration.class, SingleTaskConfiguration.class}, SimpleTaskAutoConfiguration.class,
properties = { "spring.cloud.task.closecontextEnabled=false" }) SingleTaskConfiguration.class }, properties = {
"spring.cloud.task.closecontextEnabled=false" })
@DirtiesContext @DirtiesContext
public static class CloseContextEnabledTest extends TaskPropertiesTests {} public static class CloseContextEnabledTest extends TaskPropertiesTests {
}
@Configuration @Configuration
public static class Config { public static class Config {
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015-2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.configuration; package org.springframework.cloud.task.configuration;
import javax.sql.DataSource; import javax.sql.DataSource;
@@ -63,27 +64,29 @@ public class TestConfiguration implements InitializingBean {
} }
@Bean @Bean
public TaskRepository taskRepository(){ public TaskRepository taskRepository() {
return new SimpleTaskRepository(this.taskExecutionDaoFactoryBean); return new SimpleTaskRepository(this.taskExecutionDaoFactoryBean);
} }
@Bean @Bean
public PlatformTransactionManager transactionManager() { public PlatformTransactionManager transactionManager() {
if(dataSource == null) { if (this.dataSource == null) {
return new ResourcelessTransactionManager(); return new ResourcelessTransactionManager();
} }
else { else {
return new DataSourceTransactionManager(dataSource); return new DataSourceTransactionManager(this.dataSource);
} }
} }
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
if(this.dataSource != null) { if (this.dataSource != null) {
this.taskExecutionDaoFactoryBean = new TaskExecutionDaoFactoryBean(this.dataSource); this.taskExecutionDaoFactoryBean = new TaskExecutionDaoFactoryBean(
this.dataSource);
} }
else { else {
this.taskExecutionDaoFactoryBean = new TaskExecutionDaoFactoryBean(); this.taskExecutionDaoFactoryBean = new TaskExecutionDaoFactoryBean();
} }
} }
} }

View File

@@ -1,25 +1,24 @@
/* /*
* Copyright 2016 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.listener; package org.springframework.cloud.task.listener;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.assertEquals; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertNotNull;
/** /**
* @author Glenn Renfro * @author Glenn Renfro
@@ -31,24 +30,25 @@ public class TaskExceptionTests {
@Test @Test
public void testTaskException() { public void testTaskException() {
TaskException taskException = new TaskException(ERROR_MESSAGE); TaskException taskException = new TaskException(ERROR_MESSAGE);
assertEquals(ERROR_MESSAGE, taskException.getMessage()); assertThat(taskException.getMessage()).isEqualTo(ERROR_MESSAGE);
taskException = new TaskException(ERROR_MESSAGE, taskException = new TaskException(ERROR_MESSAGE,
new IllegalStateException(ERROR_MESSAGE)); new IllegalStateException(ERROR_MESSAGE));
assertEquals(ERROR_MESSAGE, taskException.getMessage()); assertThat(taskException.getMessage()).isEqualTo(ERROR_MESSAGE);
assertNotNull(taskException.getCause()); assertThat(taskException.getCause()).isNotNull();
assertEquals(ERROR_MESSAGE, taskException.getCause().getMessage()); assertThat(taskException.getCause().getMessage()).isEqualTo(ERROR_MESSAGE);
} }
@Test @Test
public void testTaskExecutionException() { public void testTaskExecutionException() {
TaskExecutionException taskException = new TaskExecutionException(ERROR_MESSAGE); TaskExecutionException taskException = new TaskExecutionException(ERROR_MESSAGE);
assertEquals(ERROR_MESSAGE, taskException.getMessage()); assertThat(taskException.getMessage()).isEqualTo(ERROR_MESSAGE);
taskException = new TaskExecutionException(ERROR_MESSAGE, taskException = new TaskExecutionException(ERROR_MESSAGE,
new IllegalStateException(ERROR_MESSAGE)); new IllegalStateException(ERROR_MESSAGE));
assertEquals(ERROR_MESSAGE, taskException.getMessage()); assertThat(taskException.getMessage()).isEqualTo(ERROR_MESSAGE);
assertNotNull(taskException.getCause()); assertThat(taskException.getCause()).isNotNull();
assertEquals(ERROR_MESSAGE, taskException.getCause().getMessage()); assertThat(taskException.getCause().getMessage()).isEqualTo(ERROR_MESSAGE);
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2016-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -37,10 +37,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import static org.junit.Assert.assertEquals; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
/** /**
* Verifies that the TaskExecutionListener invocations occur at the appropriate task * Verifies that the TaskExecutionListener invocations occur at the appropriate task
@@ -49,14 +46,17 @@ import static org.junit.Assert.assertTrue;
* @author Glenn Renfro * @author Glenn Renfro
*/ */
public class TaskExecutionListenerTests { public class TaskExecutionListenerTests {
private AnnotationConfigApplicationContext context;
private static final String EXCEPTION_MESSAGE = "This was expected"; private static final String EXCEPTION_MESSAGE = "This was expected";
private static boolean beforeTaskDidFireOnError = false; private static boolean beforeTaskDidFireOnError = false;
private static boolean endTaskDidFireOnError = false; private static boolean endTaskDidFireOnError = false;
private static boolean failedTaskDidFireOnError = false; private static boolean failedTaskDidFireOnError = false;
private AnnotationConfigApplicationContext context;
@BeforeTask @BeforeTask
public void setup() { public void setup() {
beforeTaskDidFireOnError = false; beforeTaskDidFireOnError = false;
@@ -66,27 +66,29 @@ public class TaskExecutionListenerTests {
@After @After
public void tearDown() { public void tearDown() {
if(context != null && context.isActive()) { if (this.context != null && this.context.isActive()) {
context.close(); this.context.close();
} }
} }
/** /**
* Verify that if a TaskExecutionListener Bean is present that the onTaskStartup method * Verify that if a TaskExecutionListener Bean is present that the onTaskStartup
* is called. * method is called.
*/ */
@Test @Test
public void testTaskCreate() { public void testTaskCreate() {
setupContextForTaskExecutionListener(); setupContextForTaskExecutionListener();
DefaultTaskListenerConfiguration.TestTaskExecutionListener taskExecutionListener = DefaultTaskListenerConfiguration.TestTaskExecutionListener taskExecutionListener = this.context
context.getBean(DefaultTaskListenerConfiguration.TestTaskExecutionListener.class); .getBean(
TaskExecution taskExecution = new TaskExecution(0, null, "wombat", DefaultTaskListenerConfiguration.TestTaskExecutionListener.class);
new Date(), new Date(), null, new ArrayList<>(), null, null); TaskExecution taskExecution = new TaskExecution(0, null, "wombat", new Date(),
verifyListenerResults(false, false, taskExecution,taskExecutionListener); new Date(), null, new ArrayList<>(), null, null);
verifyListenerResults(false, false, taskExecution, taskExecutionListener);
} }
/** /**
* Verify that if a LifecycleProcessor executes all TaskExecutionListeners if BeforeTask throws exception. * Verify that if a LifecycleProcessor executes all TaskExecutionListeners if
* BeforeTask throws exception.
*/ */
@Test @Test
public void testBeforeTaskErrorCreate() { public void testBeforeTaskErrorCreate() {
@@ -97,14 +99,18 @@ public class TaskExecutionListenerTests {
catch (Exception exception) { catch (Exception exception) {
exceptionFired = true; exceptionFired = true;
} }
assertTrue("Exception should have fired", exceptionFired); assertThat(exceptionFired).as("Exception should have fired").isTrue();
assertTrue("BeforeTask Listener should have executed", beforeTaskDidFireOnError); assertThat(beforeTaskDidFireOnError)
assertTrue("EndTask Listener should have executed", endTaskDidFireOnError); .as("BeforeTask Listener should have executed").isTrue();
assertTrue("FailedTask Listener should have executed", failedTaskDidFireOnError); assertThat(endTaskDidFireOnError).as("EndTask Listener should have executed")
.isTrue();
assertThat(failedTaskDidFireOnError)
.as("FailedTask Listener should have executed").isTrue();
} }
/** /**
* Verify that if a LifecycleProcessor executes AfterTask TaskExecutionListeners if FailedTask throws exception. * Verify that if a LifecycleProcessor executes AfterTask TaskExecutionListeners if
* FailedTask throws exception.
*/ */
@Test @Test
public void testFailedTaskErrorCreate() { public void testFailedTaskErrorCreate() {
@@ -115,42 +121,52 @@ public class TaskExecutionListenerTests {
catch (Exception exception) { catch (Exception exception) {
exceptionFired = true; exceptionFired = true;
} }
assertTrue("Exception should have fired", exceptionFired); assertThat(exceptionFired).as("Exception should have fired").isTrue();
assertTrue("EndTask Listener should have executed", endTaskDidFireOnError); assertThat(endTaskDidFireOnError).as("EndTask Listener should have executed")
assertTrue("FailedTask Listener should not have executed", failedTaskDidFireOnError); .isTrue();
assertThat(failedTaskDidFireOnError)
.as("FailedTask Listener should not have executed").isTrue();
} }
/** /**
* Verify that if a LifecycleProcessor stores the correct exit code if AfterTask listener fails. * Verify that if a LifecycleProcessor stores the correct exit code if AfterTask
* listener fails.
*/ */
@Test @Test
public void testAfterTaskErrorCreate() { public void testAfterTaskErrorCreate() {
setupContextForAfterTaskErrorAnnotatedListener(); setupContextForAfterTaskErrorAnnotatedListener();
AfterTaskErrorAnnotationConfiguration.AnnotatedTaskListener taskExecutionListener = AfterTaskErrorAnnotationConfiguration.AnnotatedTaskListener taskExecutionListener = this.context
context.getBean(AfterTaskErrorAnnotationConfiguration.AnnotatedTaskListener.class); .getBean(
context.publishEvent(new ApplicationReadyEvent(new SpringApplication(), new String[0], context)); AfterTaskErrorAnnotationConfiguration.AnnotatedTaskListener.class);
this.context.publishEvent(new ApplicationReadyEvent(new SpringApplication(),
new String[0], this.context));
assertTrue(taskExecutionListener.isTaskStartup()); assertThat(taskExecutionListener.isTaskStartup()).isTrue();
assertTrue(taskExecutionListener.isTaskEnd()); assertThat(taskExecutionListener.isTaskEnd()).isTrue();
assertEquals(TestListener.END_MESSAGE, taskExecutionListener.getTaskExecution().getExitMessage()); assertThat(taskExecutionListener.getTaskExecution().getExitMessage())
assertTrue(taskExecutionListener.getTaskExecution().getErrorMessage().contains("Failed to process @BeforeTask or @AfterTask annotation because: AfterTaskFailure")); .isEqualTo(TestListener.END_MESSAGE);
assertNull(taskExecutionListener.getThrowable()); assertThat(taskExecutionListener.getTaskExecution().getErrorMessage().contains(
"Failed to process @BeforeTask or @AfterTask annotation because: AfterTaskFailure"))
.isTrue();
assertThat(taskExecutionListener.getThrowable()).isNull();
} }
/** /**
* Verify that if a TaskExecutionListener Bean is present that the onTaskEnd method * Verify that if a TaskExecutionListener Bean is present that the onTaskEnd method is
* is called. * called.
*/ */
@Test @Test
public void testTaskUpdate() { public void testTaskUpdate() {
setupContextForTaskExecutionListener(); setupContextForTaskExecutionListener();
DefaultTaskListenerConfiguration.TestTaskExecutionListener taskExecutionListener = DefaultTaskListenerConfiguration.TestTaskExecutionListener taskExecutionListener = this.context
context.getBean(DefaultTaskListenerConfiguration.TestTaskExecutionListener.class); .getBean(
context.publishEvent(new ApplicationReadyEvent(new SpringApplication(), new String[0], context)); DefaultTaskListenerConfiguration.TestTaskExecutionListener.class);
this.context.publishEvent(new ApplicationReadyEvent(new SpringApplication(),
new String[0], this.context));
TaskExecution taskExecution = new TaskExecution(0, 0, "wombat", TaskExecution taskExecution = new TaskExecution(0, 0, "wombat", new Date(),
new Date(), new Date(), null, new ArrayList<>(), null, null); new Date(), null, new ArrayList<>(), null, null);
verifyListenerResults(true, false, taskExecution,taskExecutionListener); verifyListenerResults(true, false, taskExecution, taskExecutionListener);
} }
/** /**
@@ -162,14 +178,17 @@ public class TaskExecutionListenerTests {
RuntimeException exception = new RuntimeException(EXCEPTION_MESSAGE); RuntimeException exception = new RuntimeException(EXCEPTION_MESSAGE);
setupContextForTaskExecutionListener(); setupContextForTaskExecutionListener();
SpringApplication application = new SpringApplication(); SpringApplication application = new SpringApplication();
DefaultTaskListenerConfiguration.TestTaskExecutionListener taskExecutionListener = DefaultTaskListenerConfiguration.TestTaskExecutionListener taskExecutionListener = this.context
context.getBean(DefaultTaskListenerConfiguration.TestTaskExecutionListener.class); .getBean(
context.publishEvent(new ApplicationFailedEvent(application, new String[0], context, exception)); DefaultTaskListenerConfiguration.TestTaskExecutionListener.class);
context.publishEvent(new ApplicationReadyEvent(application, new String[0], context)); this.context.publishEvent(new ApplicationFailedEvent(application, new String[0],
this.context, exception));
this.context.publishEvent(
new ApplicationReadyEvent(application, new String[0], this.context));
TaskExecution taskExecution = new TaskExecution(0, 1, "wombat", new Date(), TaskExecution taskExecution = new TaskExecution(0, 1, "wombat", new Date(),
new Date(), null, new ArrayList<>(), null, null); new Date(), null, new ArrayList<>(), null, null);
verifyListenerResults(true, true, taskExecution,taskExecutionListener); verifyListenerResults(true, true, taskExecution, taskExecutionListener);
} }
/** /**
@@ -179,11 +198,11 @@ public class TaskExecutionListenerTests {
@Test @Test
public void testAnnotationCreate() { public void testAnnotationCreate() {
setupContextForAnnotatedListener(); setupContextForAnnotatedListener();
DefaultAnnotationConfiguration.AnnotatedTaskListener annotatedListener = DefaultAnnotationConfiguration.AnnotatedTaskListener annotatedListener = this.context
context.getBean(DefaultAnnotationConfiguration.AnnotatedTaskListener.class); .getBean(DefaultAnnotationConfiguration.AnnotatedTaskListener.class);
TaskExecution taskExecution = new TaskExecution(0, null, "wombat", TaskExecution taskExecution = new TaskExecution(0, null, "wombat", new Date(),
new Date(), new Date(), null, new ArrayList<>(), null, null); new Date(), null, new ArrayList<>(), null, null);
verifyListenerResults(false, false, taskExecution,annotatedListener); verifyListenerResults(false, false, taskExecution, annotatedListener);
} }
/** /**
@@ -193,13 +212,14 @@ public class TaskExecutionListenerTests {
@Test @Test
public void testAnnotationUpdate() { public void testAnnotationUpdate() {
setupContextForAnnotatedListener(); setupContextForAnnotatedListener();
DefaultAnnotationConfiguration.AnnotatedTaskListener annotatedListener = DefaultAnnotationConfiguration.AnnotatedTaskListener annotatedListener = this.context
context.getBean(DefaultAnnotationConfiguration.AnnotatedTaskListener.class); .getBean(DefaultAnnotationConfiguration.AnnotatedTaskListener.class);
context.publishEvent(new ApplicationReadyEvent(new SpringApplication(), new String[0], context)); this.context.publishEvent(new ApplicationReadyEvent(new SpringApplication(),
new String[0], this.context));
TaskExecution taskExecution = new TaskExecution(0, 0, "wombat", TaskExecution taskExecution = new TaskExecution(0, 0, "wombat", new Date(),
new Date(), new Date(), null, new ArrayList<>(), null, null); new Date(), null, new ArrayList<>(), null, null);
verifyListenerResults(true, false, taskExecution,annotatedListener); verifyListenerResults(true, false, taskExecution, annotatedListener);
} }
/** /**
@@ -211,73 +231,91 @@ public class TaskExecutionListenerTests {
RuntimeException exception = new RuntimeException(EXCEPTION_MESSAGE); RuntimeException exception = new RuntimeException(EXCEPTION_MESSAGE);
setupContextForAnnotatedListener(); setupContextForAnnotatedListener();
SpringApplication application = new SpringApplication(); SpringApplication application = new SpringApplication();
DefaultAnnotationConfiguration.AnnotatedTaskListener annotatedListener = DefaultAnnotationConfiguration.AnnotatedTaskListener annotatedListener = this.context
context.getBean(DefaultAnnotationConfiguration.AnnotatedTaskListener.class); .getBean(DefaultAnnotationConfiguration.AnnotatedTaskListener.class);
context.publishEvent(new ApplicationFailedEvent(application, new String[0], context, exception)); this.context.publishEvent(new ApplicationFailedEvent(application, new String[0],
context.publishEvent(new ApplicationReadyEvent(application, new String[0], context)); this.context, exception));
this.context.publishEvent(
new ApplicationReadyEvent(application, new String[0], this.context));
TaskExecution taskExecution = new TaskExecution(0, 1, "wombat", new Date(), TaskExecution taskExecution = new TaskExecution(0, 1, "wombat", new Date(),
new Date(), null, new ArrayList<>(), null, null); new Date(), null, new ArrayList<>(), null, null);
verifyListenerResults(true, true, taskExecution,annotatedListener); verifyListenerResults(true, true, taskExecution, annotatedListener);
} }
private void verifyListenerResults(boolean isTaskEnd, private void verifyListenerResults(boolean isTaskEnd, boolean isTaskFailed,
boolean isTaskFailed, TaskExecution taskExecution, TaskExecution taskExecution, TestListener actualListener) {
TestListener actualListener){ assertThat(actualListener.isTaskStartup()).isTrue();
assertTrue(actualListener.isTaskStartup()); assertThat(actualListener.isTaskEnd()).isEqualTo(isTaskEnd);
assertEquals(isTaskEnd,actualListener.isTaskEnd()); assertThat(actualListener.isTaskFailed()).isEqualTo(isTaskFailed);
assertEquals(isTaskFailed,actualListener.isTaskFailed()); if (isTaskFailed) {
if(isTaskFailed){ assertThat(actualListener.getTaskExecution().getExitMessage())
assertEquals(TestListener.END_MESSAGE, actualListener.getTaskExecution().getExitMessage()); .isEqualTo(TestListener.END_MESSAGE);
assertNotNull(actualListener.getThrowable()); assertThat(actualListener.getThrowable()).isNotNull();
assertTrue(actualListener.getThrowable() instanceof RuntimeException); assertThat(actualListener.getThrowable() instanceof RuntimeException)
assertTrue(actualListener.getTaskExecution().getErrorMessage().startsWith("java.lang.RuntimeException: This was expected")); .isTrue();
assertThat(actualListener.getTaskExecution().getErrorMessage()
.startsWith("java.lang.RuntimeException: This was expected"))
.isTrue();
} }
else if(isTaskEnd){ else if (isTaskEnd) {
assertEquals(TestListener.END_MESSAGE, actualListener.getTaskExecution().getExitMessage()); assertThat(actualListener.getTaskExecution().getExitMessage())
assertEquals(taskExecution.getErrorMessage(), actualListener.getTaskExecution().getErrorMessage()); .isEqualTo(TestListener.END_MESSAGE);
assertNull(actualListener.getThrowable()); assertThat(actualListener.getTaskExecution().getErrorMessage())
.isEqualTo(taskExecution.getErrorMessage());
assertThat(actualListener.getThrowable()).isNull();
} }
else { else {
assertEquals(TestListener.START_MESSAGE, actualListener.getTaskExecution().getExitMessage()); assertThat(actualListener.getTaskExecution().getExitMessage())
assertNull(actualListener.getTaskExecution().getErrorMessage()); .isEqualTo(TestListener.START_MESSAGE);
assertNull(actualListener.getThrowable()); assertThat(actualListener.getTaskExecution().getErrorMessage()).isNull();
assertThat(actualListener.getThrowable()).isNull();
} }
assertEquals(taskExecution.getExecutionId(), actualListener.getTaskExecution().getExecutionId()); assertThat(actualListener.getTaskExecution().getExecutionId())
assertEquals(taskExecution.getExitCode(), actualListener.getTaskExecution().getExitCode()); .isEqualTo(taskExecution.getExecutionId());
assertEquals(taskExecution.getExternalExecutionId(), actualListener.getTaskExecution().getExternalExecutionId()); assertThat(actualListener.getTaskExecution().getExitCode())
.isEqualTo(taskExecution.getExitCode());
assertThat(actualListener.getTaskExecution().getExternalExecutionId())
.isEqualTo(taskExecution.getExternalExecutionId());
} }
private void setupContextForTaskExecutionListener(){ private void setupContextForTaskExecutionListener() {
context = new AnnotationConfigApplicationContext(DefaultTaskListenerConfiguration.class, this.context = new AnnotationConfigApplicationContext(
DefaultTaskListenerConfiguration.class, TestDefaultConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.setId("testTask");
}
private void setupContextForAnnotatedListener() {
this.context = new AnnotationConfigApplicationContext(
TestDefaultConfiguration.class, DefaultAnnotationConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.setId("annotatedTask");
}
private void setupContextForBeforeTaskErrorAnnotatedListener() {
this.context = new AnnotationConfigApplicationContext(
TestDefaultConfiguration.class, TestDefaultConfiguration.class,
BeforeTaskErrorAnnotationConfiguration.class,
PropertyPlaceholderAutoConfiguration.class); PropertyPlaceholderAutoConfiguration.class);
context.setId("testTask"); this.context.setId("beforeTaskAnnotatedTask");
} }
private void setupContextForAnnotatedListener(){ private void setupContextForFailedTaskErrorAnnotatedListener() {
context = new AnnotationConfigApplicationContext(TestDefaultConfiguration.class, DefaultAnnotationConfiguration.class, this.context = new AnnotationConfigApplicationContext(
TestDefaultConfiguration.class,
FailedTaskErrorAnnotationConfiguration.class,
PropertyPlaceholderAutoConfiguration.class); PropertyPlaceholderAutoConfiguration.class);
context.setId("annotatedTask"); this.context.setId("failedTaskAnnotatedTask");
} }
private void setupContextForBeforeTaskErrorAnnotatedListener(){ private void setupContextForAfterTaskErrorAnnotatedListener() {
context = new AnnotationConfigApplicationContext(TestDefaultConfiguration.class, BeforeTaskErrorAnnotationConfiguration.class, this.context = new AnnotationConfigApplicationContext(
TestDefaultConfiguration.class,
AfterTaskErrorAnnotationConfiguration.class,
PropertyPlaceholderAutoConfiguration.class); PropertyPlaceholderAutoConfiguration.class);
context.setId("beforeTaskAnnotatedTask"); this.context.setId("afterTaskAnnotatedTask");
}
private void setupContextForFailedTaskErrorAnnotatedListener(){
context = new AnnotationConfigApplicationContext(TestDefaultConfiguration.class, FailedTaskErrorAnnotationConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
context.setId("failedTaskAnnotatedTask");
}
private void setupContextForAfterTaskErrorAnnotatedListener(){
context = new AnnotationConfigApplicationContext(TestDefaultConfiguration.class, AfterTaskErrorAnnotationConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
context.setId("afterTaskAnnotatedTask");
} }
@Configuration @Configuration
@@ -292,14 +330,14 @@ public class TaskExecutionListenerTests {
@BeforeTask @BeforeTask
public void methodA(TaskExecution taskExecution) { public void methodA(TaskExecution taskExecution) {
isTaskStartup = true; this.isTaskStartup = true;
this.taskExecution = taskExecution; this.taskExecution = taskExecution;
this.taskExecution.setExitMessage(START_MESSAGE); this.taskExecution.setExitMessage(START_MESSAGE);
} }
@AfterTask @AfterTask
public void methodB(TaskExecution taskExecution) { public void methodB(TaskExecution taskExecution) {
isTaskEnd = true; this.isTaskEnd = true;
this.taskExecution = taskExecution; this.taskExecution = taskExecution;
this.taskExecution.setExitMessage(END_MESSAGE); this.taskExecution.setExitMessage(END_MESSAGE);
@@ -307,12 +345,14 @@ public class TaskExecutionListenerTests {
@FailedTask @FailedTask
public void methodC(TaskExecution taskExecution, Throwable throwable) { public void methodC(TaskExecution taskExecution, Throwable throwable) {
isTaskFailed = true; this.isTaskFailed = true;
this.taskExecution = taskExecution; this.taskExecution = taskExecution;
this.throwable = throwable; this.throwable = throwable;
this.taskExecution.setExitMessage(ERROR_MESSAGE); this.taskExecution.setExitMessage(ERROR_MESSAGE);
} }
} }
} }
@Configuration @Configuration
@@ -345,7 +385,9 @@ public class TaskExecutionListenerTests {
public void methodC(TaskExecution taskExecution, Throwable throwable) { public void methodC(TaskExecution taskExecution, Throwable throwable) {
failedTaskDidFireOnError = true; failedTaskDidFireOnError = true;
} }
} }
} }
@Configuration @Configuration
@@ -356,7 +398,6 @@ public class TaskExecutionListenerTests {
return new AnnotatedTaskListener(); return new AnnotatedTaskListener();
} }
public static class AnnotatedTaskListener { public static class AnnotatedTaskListener {
@BeforeTask @BeforeTask
@@ -375,7 +416,9 @@ public class TaskExecutionListenerTests {
failedTaskDidFireOnError = true; failedTaskDidFireOnError = true;
throw new TaskExecutionException("FailedTaskFailure"); throw new TaskExecutionException("FailedTaskFailure");
} }
} }
} }
@Configuration @Configuration
@@ -386,21 +429,23 @@ public class TaskExecutionListenerTests {
return new AnnotatedTaskListener(); return new AnnotatedTaskListener();
} }
public static class AnnotatedTaskListener extends TestListener{ public static class AnnotatedTaskListener extends TestListener {
@BeforeTask @BeforeTask
public void methodA(TaskExecution taskExecution) { public void methodA(TaskExecution taskExecution) {
isTaskStartup = true; this.isTaskStartup = true;
} }
@AfterTask @AfterTask
public void methodB(TaskExecution taskExecution) { public void methodB(TaskExecution taskExecution) {
isTaskEnd = true; this.isTaskEnd = true;
this.taskExecution = taskExecution; this.taskExecution = taskExecution;
this.taskExecution.setExitMessage(END_MESSAGE); this.taskExecution.setExitMessage(END_MESSAGE);
throw new TaskExecutionException("AfterTaskFailure"); throw new TaskExecutionException("AfterTaskFailure");
} }
} }
} }
@Configuration @Configuration
@@ -411,31 +456,33 @@ public class TaskExecutionListenerTests {
return new TestTaskExecutionListener(); return new TestTaskExecutionListener();
} }
public static class TestTaskExecutionListener extends TestListener implements TaskExecutionListener { public static class TestTaskExecutionListener extends TestListener
implements TaskExecutionListener {
@Override @Override
public void onTaskStartup(TaskExecution taskExecution) { public void onTaskStartup(TaskExecution taskExecution) {
isTaskStartup = true; this.isTaskStartup = true;
this.taskExecution = taskExecution; this.taskExecution = taskExecution;
this.taskExecution.setExitMessage(START_MESSAGE); this.taskExecution.setExitMessage(START_MESSAGE);
} }
@Override @Override
public void onTaskEnd(TaskExecution taskExecution) { public void onTaskEnd(TaskExecution taskExecution) {
isTaskEnd = true; this.isTaskEnd = true;
this.taskExecution = taskExecution; this.taskExecution = taskExecution;
this.taskExecution.setExitMessage(END_MESSAGE); this.taskExecution.setExitMessage(END_MESSAGE);
} }
@Override @Override
public void onTaskFailed(TaskExecution taskExecution, Throwable throwable) { public void onTaskFailed(TaskExecution taskExecution, Throwable throwable) {
isTaskFailed = true; this.isTaskFailed = true;
this.taskExecution = taskExecution; this.taskExecution = taskExecution;
this.throwable = throwable; this.throwable = throwable;
this.taskExecution.setExitMessage(ERROR_MESSAGE); this.taskExecution.setExitMessage(ERROR_MESSAGE);
} }
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -51,32 +51,30 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import static org.junit.Assert.assertEquals; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
/** /**
* Verifies that the TaskLifecycleListener Methods record the appropriate log header entries and * Verifies that the TaskLifecycleListener Methods record the appropriate log header
* result codes. * entries and result codes.
* *
* @author Glenn Renfro * @author Glenn Renfro
* @author Michael Minella * @author Michael Minella
*/ */
public class TaskLifecycleListenerTests { public class TaskLifecycleListenerTests {
@Rule
public OutputCapture outputCapture = new OutputCapture();
private AnnotationConfigApplicationContext context; private AnnotationConfigApplicationContext context;
private TaskExplorer taskExplorer; private TaskExplorer taskExplorer;
@Rule
public OutputCapture outputCapture = new OutputCapture();
@Before @Before
public void setUp() { public void setUp() {
context = new AnnotationConfigApplicationContext(); this.context = new AnnotationConfigApplicationContext();
context.setId("testTask"); this.context.setId("testTask");
context.register(TestDefaultConfiguration.class, PropertyPlaceholderAutoConfiguration.class); this.context.register(TestDefaultConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
TestListener.getStartupOrderList().clear(); TestListener.getStartupOrderList().clear();
TestListener.getFailOrderList().clear(); TestListener.getFailOrderList().clear();
TestListener.getEndOrderList().clear(); TestListener.getEndOrderList().clear();
@@ -85,44 +83,47 @@ public class TaskLifecycleListenerTests {
@After @After
public void tearDown() { public void tearDown() {
if(context != null && context.isActive()) { if (this.context != null && this.context.isActive()) {
context.close(); this.context.close();
} }
} }
@Test @Test
public void testTaskCreate() { public void testTaskCreate() {
context.refresh(); this.context.refresh();
this.taskExplorer = context.getBean(TaskExplorer.class); this.taskExplorer = this.context.getBean(TaskExplorer.class);
verifyTaskExecution(0, false); verifyTaskExecution(0, false);
} }
@Test @Test
public void testTaskCreateWithArgs() { public void testTaskCreateWithArgs() {
context.register(ArgsConfiguration.class); this.context.register(ArgsConfiguration.class);
context.refresh(); this.context.refresh();
this.taskExplorer = context.getBean(TaskExplorer.class); this.taskExplorer = this.context.getBean(TaskExplorer.class);
verifyTaskExecution(2, false); verifyTaskExecution(2, false);
} }
@Test @Test
public void testTaskUpdate() { public void testTaskUpdate() {
context.refresh(); this.context.refresh();
this.taskExplorer = context.getBean(TaskExplorer.class); this.taskExplorer = this.context.getBean(TaskExplorer.class);
context.publishEvent(new ApplicationReadyEvent(new SpringApplication(), new String[0], context)); this.context.publishEvent(new ApplicationReadyEvent(new SpringApplication(),
new String[0], this.context));
verifyTaskExecution(0, true, 0); verifyTaskExecution(0, true, 0);
} }
@Test @Test
public void testTaskFailedUpdate() { public void testTaskFailedUpdate() {
context.refresh(); this.context.refresh();
RuntimeException exception = new RuntimeException("This was expected"); RuntimeException exception = new RuntimeException("This was expected");
SpringApplication application = new SpringApplication(); SpringApplication application = new SpringApplication();
this.taskExplorer = context.getBean(TaskExplorer.class); this.taskExplorer = this.context.getBean(TaskExplorer.class);
context.publishEvent(new ApplicationFailedEvent(application, new String[0], context, exception)); this.context.publishEvent(new ApplicationFailedEvent(application, new String[0],
context.publishEvent(new ApplicationReadyEvent(application, new String[0], context)); this.context, exception));
this.context.publishEvent(
new ApplicationReadyEvent(application, new String[0], this.context));
verifyTaskExecution(0, true, 1, exception, null); verifyTaskExecution(0, true, 1, exception, null);
} }
@@ -130,38 +131,44 @@ public class TaskLifecycleListenerTests {
@Test @Test
public void testTaskFailedWithExitCodeEvent() { public void testTaskFailedWithExitCodeEvent() {
final int exitCode = 10; final int exitCode = 10;
context.register(TestListener.class); this.context.register(TestListener.class);
context.register(TestListener2.class); this.context.register(TestListener2.class);
context.refresh(); this.context.refresh();
RuntimeException exception = new RuntimeException("This was expected"); RuntimeException exception = new RuntimeException("This was expected");
SpringApplication application = new SpringApplication(); SpringApplication application = new SpringApplication();
this.taskExplorer = context.getBean(TaskExplorer.class); this.taskExplorer = this.context.getBean(TaskExplorer.class);
context.publishEvent(new ExitCodeEvent(context, exitCode)); this.context.publishEvent(new ExitCodeEvent(this.context, exitCode));
context.publishEvent(new ApplicationFailedEvent(application, new String[0], context, exception)); this.context.publishEvent(new ApplicationFailedEvent(application, new String[0],
context.publishEvent(new ApplicationReadyEvent(application, new String[0], context)); this.context, exception));
this.context.publishEvent(
new ApplicationReadyEvent(application, new String[0], this.context));
verifyTaskExecution(0, true, exitCode, exception, null); verifyTaskExecution(0, true, exitCode, exception, null);
assertEquals(2, TestListener.getStartupOrderList().size()); assertThat(TestListener.getStartupOrderList().size()).isEqualTo(2);
assertEquals(Integer.valueOf(2), TestListener.getStartupOrderList().get(0)); assertThat(TestListener.getStartupOrderList().get(0))
assertEquals(Integer.valueOf(1), TestListener.getStartupOrderList().get(1)); .isEqualTo(Integer.valueOf(2));
assertThat(TestListener.getStartupOrderList().get(1))
.isEqualTo(Integer.valueOf(1));
assertEquals(2, TestListener.getEndOrderList().size()); assertThat(TestListener.getEndOrderList().size()).isEqualTo(2);
assertEquals(Integer.valueOf(1), TestListener.getEndOrderList().get(0)); assertThat(TestListener.getEndOrderList().get(0)).isEqualTo(Integer.valueOf(1));
assertEquals(Integer.valueOf(2), TestListener.getEndOrderList().get(1)); assertThat(TestListener.getEndOrderList().get(1)).isEqualTo(Integer.valueOf(2));
assertEquals(2, TestListener.getFailOrderList().size()); assertThat(TestListener.getFailOrderList().size()).isEqualTo(2);
assertEquals(Integer.valueOf(1), TestListener.getFailOrderList().get(0)); assertThat(TestListener.getFailOrderList().get(0)).isEqualTo(Integer.valueOf(1));
assertEquals(Integer.valueOf(2), TestListener.getFailOrderList().get(1)); assertThat(TestListener.getFailOrderList().get(1)).isEqualTo(Integer.valueOf(2));
} }
@Test @Test
public void testNoClosingOfContext() { public void testNoClosingOfContext() {
try (ConfigurableApplicationContext applicationContext = SpringApplication.run(new Class[] {TestDefaultConfiguration.class, PropertyPlaceholderAutoConfiguration.class}, try (ConfigurableApplicationContext applicationContext = SpringApplication.run(
new String[] {"--spring.cloud.task.closecontext_enabled=false"})) { new Class[] { TestDefaultConfiguration.class,
assertTrue(applicationContext.isActive()); PropertyPlaceholderAutoConfiguration.class },
new String[] { "--spring.cloud.task.closecontext_enabled=false" })) {
assertThat(applicationContext.isActive()).isTrue();
} }
} }
@@ -171,20 +178,21 @@ public class TaskLifecycleListenerTests {
MutablePropertySources propertySources = environment.getPropertySources(); MutablePropertySources propertySources = environment.getPropertySources();
Map<String, Object> myMap = new HashMap<>(); Map<String, Object> myMap = new HashMap<>();
myMap.put("spring.cloud.task.executionid", "55"); myMap.put("spring.cloud.task.executionid", "55");
propertySources.addFirst(new MapPropertySource("EnvrionmentTestPropsource", myMap)); propertySources
context.setEnvironment(environment); .addFirst(new MapPropertySource("EnvrionmentTestPropsource", myMap));
context.refresh(); this.context.setEnvironment(environment);
this.context.refresh();
} }
@Test @Test
public void testRestartExistingTask() { public void testRestartExistingTask() {
context.refresh(); this.context.refresh();
TaskLifecycleListener taskLifecycleListener = TaskLifecycleListener taskLifecycleListener = this.context
context.getBean(TaskLifecycleListener.class); .getBean(TaskLifecycleListener.class);
taskLifecycleListener.start(); taskLifecycleListener.start();
String output = this.outputCapture.toString(); String output = this.outputCapture.toString();
assertTrue("Test results do not show error message: " + output, assertThat(output.contains("Multiple start events have been received"))
output.contains("Multiple start events have been received")); .as("Test results do not show error message: " + output).isTrue();
} }
@Test @Test
@@ -193,10 +201,11 @@ public class TaskLifecycleListenerTests {
MutablePropertySources propertySources = environment.getPropertySources(); MutablePropertySources propertySources = environment.getPropertySources();
Map<String, Object> myMap = new HashMap<>(); Map<String, Object> myMap = new HashMap<>();
myMap.put("spring.cloud.task.external-execution-id", "myid"); myMap.put("spring.cloud.task.external-execution-id", "myid");
propertySources.addFirst(new MapPropertySource("EnvrionmentTestPropsource", myMap)); propertySources
context.setEnvironment(environment); .addFirst(new MapPropertySource("EnvrionmentTestPropsource", myMap));
context.refresh(); this.context.setEnvironment(environment);
this.taskExplorer = context.getBean(TaskExplorer.class); this.context.refresh();
this.taskExplorer = this.context.getBean(TaskExplorer.class);
verifyTaskExecution(0, false, null, null, "myid"); verifyTaskExecution(0, false, null, null, "myid");
} }
@@ -207,15 +216,17 @@ public class TaskLifecycleListenerTests {
MutablePropertySources propertySources = environment.getPropertySources(); MutablePropertySources propertySources = environment.getPropertySources();
Map<String, Object> myMap = new HashMap<>(); Map<String, Object> myMap = new HashMap<>();
myMap.put("spring.cloud.task.parentExecutionId", 789); myMap.put("spring.cloud.task.parentExecutionId", 789);
propertySources.addFirst(new MapPropertySource("EnvrionmentTestPropsource", myMap)); propertySources
context.setEnvironment(environment); .addFirst(new MapPropertySource("EnvrionmentTestPropsource", myMap));
context.refresh(); this.context.setEnvironment(environment);
this.taskExplorer = context.getBean(TaskExplorer.class); this.context.refresh();
this.taskExplorer = this.context.getBean(TaskExplorer.class);
verifyTaskExecution(0, false, null, null, null, 789L); verifyTaskExecution(0, false, null, null, null, 789L);
} }
private void verifyTaskExecution(int numberOfParams, boolean update, Integer exitCode) { private void verifyTaskExecution(int numberOfParams, boolean update,
Integer exitCode) {
verifyTaskExecution(numberOfParams, update, exitCode, null, null); verifyTaskExecution(numberOfParams, update, exitCode, null, null);
} }
@@ -223,47 +234,48 @@ public class TaskLifecycleListenerTests {
verifyTaskExecution(numberOfParams, update, null, null, null); verifyTaskExecution(numberOfParams, update, null, null, null);
} }
private void verifyTaskExecution(int numberOfParams, boolean update, private void verifyTaskExecution(int numberOfParams, boolean update, Integer exitCode,
Integer exitCode, Throwable exception, String externalExecutionId) { Throwable exception, String externalExecutionId) {
verifyTaskExecution(numberOfParams, update, exitCode, exception, verifyTaskExecution(numberOfParams, update, exitCode, exception,
externalExecutionId, null); externalExecutionId, null);
} }
private void verifyTaskExecution(int numberOfParams, boolean update, private void verifyTaskExecution(int numberOfParams, boolean update, Integer exitCode,
Integer exitCode, Throwable exception, String externalExecutionId, Throwable exception, String externalExecutionId, Long parentExecutionId) {
Long parentExecutionId) {
Sort sort = Sort.by("id"); Sort sort = Sort.by("id");
PageRequest request = PageRequest.of(0, Integer.MAX_VALUE, sort); PageRequest request = PageRequest.of(0, Integer.MAX_VALUE, sort);
Page<TaskExecution> taskExecutionsByName = this.taskExplorer.findTaskExecutionsByName("testTask", Page<TaskExecution> taskExecutionsByName = this.taskExplorer
request); .findTaskExecutionsByName("testTask", request);
assertTrue(taskExecutionsByName.iterator().hasNext()); assertThat(taskExecutionsByName.iterator().hasNext()).isTrue();
TaskExecution taskExecution = taskExecutionsByName.iterator().next(); TaskExecution taskExecution = taskExecutionsByName.iterator().next();
assertEquals(numberOfParams, taskExecution.getArguments().size()); assertThat(taskExecution.getArguments().size()).isEqualTo(numberOfParams);
assertEquals(exitCode, taskExecution.getExitCode()); assertThat(taskExecution.getExitCode()).isEqualTo(exitCode);
assertEquals(externalExecutionId, taskExecution.getExternalExecutionId()); assertThat(taskExecution.getExternalExecutionId()).isEqualTo(externalExecutionId);
assertEquals(parentExecutionId, taskExecution.getParentExecutionId()); assertThat(taskExecution.getParentExecutionId()).isEqualTo(parentExecutionId);
if(exception != null) { if (exception != null) {
assertTrue(taskExecution.getErrorMessage().length() > exception.getStackTrace().length); assertThat(taskExecution.getErrorMessage()
.length() > exception.getStackTrace().length).isTrue();
} }
else { else {
assertNull(taskExecution.getExitMessage()); assertThat(taskExecution.getExitMessage()).isNull();
} }
if(update) { if (update) {
assertTrue(taskExecution.getEndTime().getTime() >= taskExecution.getStartTime().getTime()); assertThat(taskExecution.getEndTime().getTime() >= taskExecution
assertNotNull(taskExecution.getExitCode()); .getStartTime().getTime()).isTrue();
assertThat(taskExecution.getExitCode()).isNotNull();
} }
else { else {
assertNull(taskExecution.getEndTime()); assertThat(taskExecution.getEndTime()).isNull();
assertTrue(taskExecution.getExitCode() == null); assertThat(taskExecution.getExitCode() == null).isTrue();
} }
assertEquals("testTask", taskExecution.getTaskName()); assertThat(taskExecution.getTaskName()).isEqualTo("testTask");
} }
@Configuration @Configuration
@@ -278,23 +290,25 @@ public class TaskLifecycleListenerTests {
return new SimpleApplicationArgs(args); return new SimpleApplicationArgs(args);
} }
} }
private static class SimpleApplicationArgs implements ApplicationArguments { private static class SimpleApplicationArgs implements ApplicationArguments {
private Map<String, String> args; private Map<String, String> args;
public SimpleApplicationArgs(Map<String, String> args) { SimpleApplicationArgs(Map<String, String> args) {
this.args = args; this.args = args;
} }
@Override @Override
public String[] getSourceArgs() { public String[] getSourceArgs() {
String [] sourceArgs = new String[this.args.size()]; String[] sourceArgs = new String[this.args.size()];
int i = 0; int i = 0;
for (Map.Entry<String, String> stringStringEntry : args.entrySet()) { for (Map.Entry<String, String> stringStringEntry : this.args.entrySet()) {
sourceArgs[i] = "--" + stringStringEntry.getKey() + "=" + stringStringEntry.getValue(); sourceArgs[i] = "--" + stringStringEntry.getKey() + "="
+ stringStringEntry.getValue();
i++; i++;
} }
@@ -320,6 +334,7 @@ public class TaskLifecycleListenerTests {
public List<String> getNonOptionArgs() { public List<String> getNonOptionArgs() {
throw new UnsupportedOperationException("Not supported at this time."); throw new UnsupportedOperationException("Not supported at this time.");
} }
} }
private static class TestListener2 extends TestListener { private static class TestListener2 extends TestListener {
@@ -328,34 +343,17 @@ public class TaskLifecycleListenerTests {
private static class TestListener implements TaskExecutionListener { private static class TestListener implements TaskExecutionListener {
static List<Integer> startupOrderList = new ArrayList<>();
static List<Integer> endOrderList = new ArrayList<>();
static List<Integer> failOrderList = new ArrayList<>();
private static int currentCount = 0; private static int currentCount = 0;
private int id = 0; private int id = 0;
static List<Integer> startupOrderList = new ArrayList<>(); TestListener() {
static List<Integer> endOrderList = new ArrayList<>();
static List<Integer> failOrderList = new ArrayList<>();
public TestListener() {
currentCount++; currentCount++;
id = currentCount; this.id = currentCount;
}
@Override
public void onTaskStartup(TaskExecution taskExecution) {
startupOrderList.add(id);
}
@Override
public void onTaskEnd(TaskExecution taskExecution) {
endOrderList.add(id);
}
@Override
public void onTaskFailed(TaskExecution taskExecution, Throwable throwable) {
failOrderList.add(id);
} }
public static List<Integer> getStartupOrderList() { public static List<Integer> getStartupOrderList() {
@@ -369,5 +367,22 @@ public class TaskLifecycleListenerTests {
public static List<Integer> getFailOrderList() { public static List<Integer> getFailOrderList() {
return failOrderList; return failOrderList;
} }
@Override
public void onTaskStartup(TaskExecution taskExecution) {
startupOrderList.add(this.id);
}
@Override
public void onTaskEnd(TaskExecution taskExecution) {
endOrderList.add(this.id);
}
@Override
public void onTaskFailed(TaskExecution taskExecution, Throwable throwable) {
failOrderList.add(this.id);
}
} }
} }

View File

@@ -1,17 +1,17 @@
/* /*
* Copyright 2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.cloud.task.listener; package org.springframework.cloud.task.listener;
@@ -46,7 +46,8 @@ import static org.assertj.core.api.Assertions.assertThat;
* @since 2.1.0 * @since 2.1.0
*/ */
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@ContextConfiguration(classes = { TaskListenerExecutorObjectFactoryTests.TaskExecutionListenerConfiguration.class }) @ContextConfiguration(classes = {
TaskListenerExecutorObjectFactoryTests.TaskExecutionListenerConfiguration.class })
@DirtiesContext @DirtiesContext
public class TaskListenerExecutorObjectFactoryTests { public class TaskListenerExecutorObjectFactoryTests {
@@ -68,13 +69,15 @@ public class TaskListenerExecutorObjectFactoryTests {
@Before @Before
public void setup() { public void setup() {
taskExecutionListenerResults.clear(); taskExecutionListenerResults.clear();
this.taskListenerExecutorObjectFactory = new TaskListenerExecutorObjectFactory(this.context); this.taskListenerExecutorObjectFactory = new TaskListenerExecutorObjectFactory(
this.context);
this.taskListenerExecutor = this.taskListenerExecutorObjectFactory.getObject(); this.taskListenerExecutor = this.taskListenerExecutorObjectFactory.getObject();
} }
@Test @Test
public void verifyTaskStartupListener() { public void verifyTaskStartupListener() {
this.taskListenerExecutor.onTaskStartup(createSampleTaskExecution(BEFORE_LISTENER)); this.taskListenerExecutor
.onTaskStartup(createSampleTaskExecution(BEFORE_LISTENER));
validateSingleEntry(BEFORE_LISTENER); validateSingleEntry(BEFORE_LISTENER);
} }
@@ -93,14 +96,18 @@ public class TaskListenerExecutorObjectFactoryTests {
@Test @Test
public void verifyAllListener() { public void verifyAllListener() {
this.taskListenerExecutor.onTaskStartup(createSampleTaskExecution(BEFORE_LISTENER)); this.taskListenerExecutor
.onTaskStartup(createSampleTaskExecution(BEFORE_LISTENER));
this.taskListenerExecutor.onTaskFailed(createSampleTaskExecution(FAIL_LISTENER), this.taskListenerExecutor.onTaskFailed(createSampleTaskExecution(FAIL_LISTENER),
new IllegalStateException("oops")); new IllegalStateException("oops"));
this.taskListenerExecutor.onTaskEnd(createSampleTaskExecution(AFTER_LISTENER)); this.taskListenerExecutor.onTaskEnd(createSampleTaskExecution(AFTER_LISTENER));
assertThat(taskExecutionListenerResults.size()).isEqualTo(3); assertThat(taskExecutionListenerResults.size()).isEqualTo(3);
assertThat(taskExecutionListenerResults.get(0).getTaskName()).isEqualTo(BEFORE_LISTENER); assertThat(taskExecutionListenerResults.get(0).getTaskName())
assertThat(taskExecutionListenerResults.get(1).getTaskName()).isEqualTo(FAIL_LISTENER); .isEqualTo(BEFORE_LISTENER);
assertThat(taskExecutionListenerResults.get(2).getTaskName()).isEqualTo(AFTER_LISTENER); assertThat(taskExecutionListenerResults.get(1).getTaskName())
.isEqualTo(FAIL_LISTENER);
assertThat(taskExecutionListenerResults.get(2).getTaskName())
.isEqualTo(AFTER_LISTENER);
} }
private TaskExecution createSampleTaskExecution(String taskName) { private TaskExecution createSampleTaskExecution(String taskName) {
@@ -121,23 +128,29 @@ public class TaskListenerExecutorObjectFactoryTests {
public TaskRunComponent taskRunComponent() { public TaskRunComponent taskRunComponent() {
return new TaskRunComponent(); return new TaskRunComponent();
} }
} }
public static class TaskRunComponent { public static class TaskRunComponent {
@BeforeTask @BeforeTask
public void initBeforeListener(TaskExecution taskExecution) { public void initBeforeListener(TaskExecution taskExecution) {
TaskListenerExecutorObjectFactoryTests.taskExecutionListenerResults.add(taskExecution); TaskListenerExecutorObjectFactoryTests.taskExecutionListenerResults
.add(taskExecution);
} }
@AfterTask @AfterTask
public void initAfterListener(TaskExecution taskExecution) { public void initAfterListener(TaskExecution taskExecution) {
TaskListenerExecutorObjectFactoryTests.taskExecutionListenerResults.add(taskExecution); TaskListenerExecutorObjectFactoryTests.taskExecutionListenerResults
.add(taskExecution);
} }
@FailedTask @FailedTask
public void initFailedListener(TaskExecution taskExecution, Throwable exception) { public void initFailedListener(TaskExecution taskExecution, Throwable exception) {
TaskListenerExecutorObjectFactoryTests.taskExecutionListenerResults.add(taskExecution); TaskListenerExecutorObjectFactoryTests.taskExecutionListenerResults
.add(taskExecution);
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -18,22 +18,20 @@ package org.springframework.cloud.task.repository.dao;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List; import java.util.List;
import java.util.TimeZone; import java.util.TimeZone;
import org.junit.Test; import org.junit.Test;
import org.springframework.cloud.task.repository.TaskExecution; import org.springframework.cloud.task.repository.TaskExecution;
import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.annotation.DirtiesContext;
import static org.junit.Assert.assertEquals; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertNotNull; import static org.assertj.core.api.Assertions.fail;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/** /**
* Defines test cases that shall be shared between {@link JdbcTaskExecutionDaoTests} and {@link MapTaskExecutionDaoTests}. * Defines test cases that shall be shared between {@link JdbcTaskExecutionDaoTests} and
* {@link MapTaskExecutionDaoTests}.
* *
* @author Gunnar Hillert * @author Gunnar Hillert
*/ */
@@ -43,12 +41,13 @@ public class BaseTaskExecutionDaoTestCases {
@Test @Test
@DirtiesContext @DirtiesContext
public void getLatestTaskExecutionsByTaskNamesWithNullParameter() { public void getLatestTaskExecutionsByTaskNamesWithNullParameter() {
try { try {
dao.getLatestTaskExecutionsByTaskNames(null); this.dao.getLatestTaskExecutionsByTaskNames(null);
} }
catch (IllegalArgumentException e) { catch (IllegalArgumentException e) {
assertEquals("At least 1 task name must be provided.", e.getMessage()); assertThat(e.getMessage())
.isEqualTo("At least 1 task name must be provided.");
return; return;
} }
fail("Expected an IllegalArgumentException to be thrown."); fail("Expected an IllegalArgumentException to be thrown.");
@@ -56,12 +55,13 @@ public class BaseTaskExecutionDaoTestCases {
@Test @Test
@DirtiesContext @DirtiesContext
public void getLatestTaskExecutionsByTaskNamesWithEmptyArrayParameter() { public void getLatestTaskExecutionsByTaskNamesWithEmptyArrayParameter() {
try { try {
dao.getLatestTaskExecutionsByTaskNames(new String[0]); this.dao.getLatestTaskExecutionsByTaskNames(new String[0]);
} }
catch (IllegalArgumentException e) { catch (IllegalArgumentException e) {
assertEquals("At least 1 task name must be provided.", e.getMessage()); assertThat(e.getMessage())
.isEqualTo("At least 1 task name must be provided.");
return; return;
} }
fail("Expected an IllegalArgumentException to be thrown."); fail("Expected an IllegalArgumentException to be thrown.");
@@ -69,12 +69,13 @@ public class BaseTaskExecutionDaoTestCases {
@Test @Test
@DirtiesContext @DirtiesContext
public void getLatestTaskExecutionsByTaskNamesWithArrayParametersContainingNullAndEmptyValues() { public void getLatestTaskExecutionsByTaskNamesWithArrayParametersContainingNullAndEmptyValues() {
try { try {
dao.getLatestTaskExecutionsByTaskNames("foo", null, "bar", " "); this.dao.getLatestTaskExecutionsByTaskNames("foo", null, "bar", " ");
} }
catch (IllegalArgumentException e) { catch (IllegalArgumentException e) {
assertEquals("Task names must not contain any empty elements but 2 of 4 were empty or null.", e.getMessage()); assertThat(e.getMessage()).isEqualTo(
"Task names must not contain any empty elements but 2 of 4 were empty or null.");
return; return;
} }
fail("Expected an IllegalArgumentException to be thrown."); fail("Expected an IllegalArgumentException to be thrown.");
@@ -82,95 +83,105 @@ public class BaseTaskExecutionDaoTestCases {
@Test @Test
@DirtiesContext @DirtiesContext
public void getLatestTaskExecutionsByTaskNamesWithSingleTaskName() { public void getLatestTaskExecutionsByTaskNamesWithSingleTaskName() {
initializeRepositoryNotInOrderWithMultipleTaskExecutions(); initializeRepositoryNotInOrderWithMultipleTaskExecutions();
final List<TaskExecution> latestTaskExecutions = dao.getLatestTaskExecutionsByTaskNames("FOO1"); final List<TaskExecution> latestTaskExecutions = this.dao
assertTrue("Expected only 1 taskExecution but got " + latestTaskExecutions.size(), latestTaskExecutions.size() == 1); .getLatestTaskExecutionsByTaskNames("FOO1");
assertThat(latestTaskExecutions.size() == 1).as(
"Expected only 1 taskExecution but got " + latestTaskExecutions.size())
.isTrue();
final TaskExecution lastTaskExecution = latestTaskExecutions.get(0); final TaskExecution lastTaskExecution = latestTaskExecutions.get(0);
assertEquals("FOO1", lastTaskExecution.getTaskName()); assertThat(lastTaskExecution.getTaskName()).isEqualTo("FOO1");
final Calendar dateTime = Calendar.getInstance(TimeZone.getTimeZone("UTC")); final Calendar dateTime = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
dateTime.setTime(lastTaskExecution.getStartTime()); dateTime.setTime(lastTaskExecution.getStartTime());
assertEquals(2015, dateTime.get(Calendar.YEAR)); assertThat(dateTime.get(Calendar.YEAR)).isEqualTo(2015);
assertEquals(2, dateTime.get(Calendar.MONTH) + 1); assertThat(dateTime.get(Calendar.MONTH) + 1).isEqualTo(2);
assertEquals(22, dateTime.get(Calendar.DAY_OF_MONTH)); assertThat(dateTime.get(Calendar.DAY_OF_MONTH)).isEqualTo(22);
assertEquals(23, dateTime.get(Calendar.HOUR_OF_DAY)); assertThat(dateTime.get(Calendar.HOUR_OF_DAY)).isEqualTo(23);
assertEquals(59, dateTime.get(Calendar.MINUTE)); assertThat(dateTime.get(Calendar.MINUTE)).isEqualTo(59);
assertEquals(0, dateTime.get(Calendar.SECOND)); assertThat(dateTime.get(Calendar.SECOND)).isEqualTo(0);
} }
@Test @Test
@DirtiesContext @DirtiesContext
public void getLatestTaskExecutionsByTaskNamesWithMultipleTaskNames() { public void getLatestTaskExecutionsByTaskNamesWithMultipleTaskNames() {
initializeRepositoryNotInOrderWithMultipleTaskExecutions(); initializeRepositoryNotInOrderWithMultipleTaskExecutions();
final List<TaskExecution> latestTaskExecutions = dao.getLatestTaskExecutionsByTaskNames("FOO1", "FOO3", "FOO4"); final List<TaskExecution> latestTaskExecutions = this.dao
assertTrue("Expected 3 taskExecutions but got " + latestTaskExecutions.size(), latestTaskExecutions.size() == 3); .getLatestTaskExecutionsByTaskNames("FOO1", "FOO3", "FOO4");
assertThat(latestTaskExecutions.size() == 3)
.as("Expected 3 taskExecutions but got " + latestTaskExecutions.size())
.isTrue();
final Calendar dateTimeFoo3 = Calendar.getInstance(TimeZone.getTimeZone("UTC")); final Calendar dateTimeFoo3 = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
dateTimeFoo3.setTime(latestTaskExecutions.get(0).getStartTime()); dateTimeFoo3.setTime(latestTaskExecutions.get(0).getStartTime());
assertEquals(2016, dateTimeFoo3.get(Calendar.YEAR)); assertThat(dateTimeFoo3.get(Calendar.YEAR)).isEqualTo(2016);
assertEquals(8, dateTimeFoo3.get(Calendar.MONTH) + 1); assertThat(dateTimeFoo3.get(Calendar.MONTH) + 1).isEqualTo(8);
assertEquals(20, dateTimeFoo3.get(Calendar.DAY_OF_MONTH)); assertThat(dateTimeFoo3.get(Calendar.DAY_OF_MONTH)).isEqualTo(20);
assertEquals(14, dateTimeFoo3.get(Calendar.HOUR_OF_DAY)); assertThat(dateTimeFoo3.get(Calendar.HOUR_OF_DAY)).isEqualTo(14);
assertEquals(45, dateTimeFoo3.get(Calendar.MINUTE)); assertThat(dateTimeFoo3.get(Calendar.MINUTE)).isEqualTo(45);
assertEquals(0, dateTimeFoo3.get(Calendar.SECOND)); assertThat(dateTimeFoo3.get(Calendar.SECOND)).isEqualTo(0);
final Calendar dateTimeFoo1 = Calendar.getInstance(TimeZone.getTimeZone("UTC")); final Calendar dateTimeFoo1 = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
dateTimeFoo1.setTime(latestTaskExecutions.get(1).getStartTime()); dateTimeFoo1.setTime(latestTaskExecutions.get(1).getStartTime());
assertEquals(2015, dateTimeFoo1.get(Calendar.YEAR)); assertThat(dateTimeFoo1.get(Calendar.YEAR)).isEqualTo(2015);
assertEquals(2, dateTimeFoo1.get(Calendar.MONTH) + 1); assertThat(dateTimeFoo1.get(Calendar.MONTH) + 1).isEqualTo(2);
assertEquals(22, dateTimeFoo1.get(Calendar.DAY_OF_MONTH)); assertThat(dateTimeFoo1.get(Calendar.DAY_OF_MONTH)).isEqualTo(22);
assertEquals(23, dateTimeFoo1.get(Calendar.HOUR_OF_DAY)); assertThat(dateTimeFoo1.get(Calendar.HOUR_OF_DAY)).isEqualTo(23);
assertEquals(59, dateTimeFoo1.get(Calendar.MINUTE)); assertThat(dateTimeFoo1.get(Calendar.MINUTE)).isEqualTo(59);
assertEquals(0, dateTimeFoo1.get(Calendar.SECOND)); assertThat(dateTimeFoo1.get(Calendar.SECOND)).isEqualTo(0);
final Calendar dateTimeFoo4 = Calendar.getInstance(TimeZone.getTimeZone("UTC")); final Calendar dateTimeFoo4 = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
dateTimeFoo4.setTime(latestTaskExecutions.get(2).getStartTime()); dateTimeFoo4.setTime(latestTaskExecutions.get(2).getStartTime());
assertEquals(2015, dateTimeFoo4.get(Calendar.YEAR)); assertThat(dateTimeFoo4.get(Calendar.YEAR)).isEqualTo(2015);
assertEquals(2, dateTimeFoo4.get(Calendar.MONTH) + 1); assertThat(dateTimeFoo4.get(Calendar.MONTH) + 1).isEqualTo(2);
assertEquals(20, dateTimeFoo4.get(Calendar.DAY_OF_MONTH)); assertThat(dateTimeFoo4.get(Calendar.DAY_OF_MONTH)).isEqualTo(20);
assertEquals(14, dateTimeFoo4.get(Calendar.HOUR_OF_DAY)); assertThat(dateTimeFoo4.get(Calendar.HOUR_OF_DAY)).isEqualTo(14);
assertEquals(45, dateTimeFoo4.get(Calendar.MINUTE)); assertThat(dateTimeFoo4.get(Calendar.MINUTE)).isEqualTo(45);
assertEquals(0, dateTimeFoo4.get(Calendar.SECOND)); assertThat(dateTimeFoo4.get(Calendar.SECOND)).isEqualTo(0);
} }
/** /**
* This test is a special use-case. While not common, it is theoretically possible, that a task may have * This test is a special use-case. While not common, it is theoretically possible,
* executed with the exact same start time multiple times. In that case we should still only get 1 returned * that a task may have executed with the exact same start time multiple times. In
* {@link TaskExecution}. * that case we should still only get 1 returned {@link TaskExecution}.
*/ */
@Test @Test
@DirtiesContext @DirtiesContext
public void getLatestTaskExecutionsByTaskNamesWithIdenticalTaskExecutions() { public void getLatestTaskExecutionsByTaskNamesWithIdenticalTaskExecutions() {
long executionIdOffset = initializeRepositoryNotInOrderWithMultipleTaskExecutions(); long executionIdOffset = initializeRepositoryNotInOrderWithMultipleTaskExecutions();
final List<TaskExecution> latestTaskExecutions = dao.getLatestTaskExecutionsByTaskNames("FOO5"); final List<TaskExecution> latestTaskExecutions = this.dao
assertTrue("Expected only 1 taskExecution but got " + latestTaskExecutions.size(), latestTaskExecutions.size() == 1); .getLatestTaskExecutionsByTaskNames("FOO5");
assertThat(latestTaskExecutions.size() == 1).as(
"Expected only 1 taskExecution but got " + latestTaskExecutions.size())
.isTrue();
final Calendar dateTime = Calendar.getInstance(TimeZone.getTimeZone("UTC")); final Calendar dateTime = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
dateTime.setTime(latestTaskExecutions.get(0).getStartTime()); dateTime.setTime(latestTaskExecutions.get(0).getStartTime());
assertEquals(2015, dateTime.get(Calendar.YEAR)); assertThat(dateTime.get(Calendar.YEAR)).isEqualTo(2015);
assertEquals(2, dateTime.get(Calendar.MONTH) + 1); assertThat(dateTime.get(Calendar.MONTH) + 1).isEqualTo(2);
assertEquals(22, dateTime.get(Calendar.DAY_OF_MONTH)); assertThat(dateTime.get(Calendar.DAY_OF_MONTH)).isEqualTo(22);
assertEquals(23, dateTime.get(Calendar.HOUR_OF_DAY)); assertThat(dateTime.get(Calendar.HOUR_OF_DAY)).isEqualTo(23);
assertEquals(59, dateTime.get(Calendar.MINUTE)); assertThat(dateTime.get(Calendar.MINUTE)).isEqualTo(59);
assertEquals(0, dateTime.get(Calendar.SECOND)); assertThat(dateTime.get(Calendar.SECOND)).isEqualTo(0);
assertEquals(9 + executionIdOffset, latestTaskExecutions.get(0).getExecutionId()); assertThat(latestTaskExecutions.get(0).getExecutionId())
.isEqualTo(9 + executionIdOffset);
} }
@Test @Test
@DirtiesContext @DirtiesContext
public void getLatestTaskExecutionForTaskNameWithNullParameter() { public void getLatestTaskExecutionForTaskNameWithNullParameter() {
try { try {
dao.getLatestTaskExecutionForTaskName(null); this.dao.getLatestTaskExecutionForTaskName(null);
} }
catch (IllegalArgumentException e) { catch (IllegalArgumentException e) {
assertEquals("The task name must not be empty.", e.getMessage()); assertThat(e.getMessage()).isEqualTo("The task name must not be empty.");
return; return;
} }
fail("Expected an IllegalArgumentException to be thrown."); fail("Expected an IllegalArgumentException to be thrown.");
@@ -178,12 +189,12 @@ public class BaseTaskExecutionDaoTestCases {
@Test @Test
@DirtiesContext @DirtiesContext
public void getLatestTaskExecutionForTaskNameWithEmptyStringParameter() { public void getLatestTaskExecutionForTaskNameWithEmptyStringParameter() {
try { try {
dao.getLatestTaskExecutionForTaskName(""); this.dao.getLatestTaskExecutionForTaskName("");
} }
catch (IllegalArgumentException e) { catch (IllegalArgumentException e) {
assertEquals("The task name must not be empty.", e.getMessage()); assertThat(e.getMessage()).isEqualTo("The task name must not be empty.");
return; return;
} }
fail("Expected an IllegalArgumentException to be thrown."); fail("Expected an IllegalArgumentException to be thrown.");
@@ -191,61 +202,71 @@ public class BaseTaskExecutionDaoTestCases {
@Test @Test
@DirtiesContext @DirtiesContext
public void getLatestTaskExecutionForNonExistingTaskName() { public void getLatestTaskExecutionForNonExistingTaskName() {
initializeRepositoryNotInOrderWithMultipleTaskExecutions(); initializeRepositoryNotInOrderWithMultipleTaskExecutions();
final TaskExecution latestTaskExecution = dao.getLatestTaskExecutionForTaskName("Bar5"); final TaskExecution latestTaskExecution = this.dao
assertNull("Expected the latestTaskExecution to be null but got" + latestTaskExecution, latestTaskExecution); .getLatestTaskExecutionForTaskName("Bar5");
assertThat(latestTaskExecution)
.as("Expected the latestTaskExecution to be null but got"
+ latestTaskExecution)
.isNull();
} }
@Test @Test
@DirtiesContext @DirtiesContext
public void getLatestTaskExecutionForExistingTaskName() { public void getLatestTaskExecutionForExistingTaskName() {
initializeRepositoryNotInOrderWithMultipleTaskExecutions(); initializeRepositoryNotInOrderWithMultipleTaskExecutions();
final TaskExecution latestTaskExecution = dao.getLatestTaskExecutionForTaskName("FOO1"); final TaskExecution latestTaskExecution = this.dao
assertNotNull("Expected the latestTaskExecution not to be null", latestTaskExecution); .getLatestTaskExecutionForTaskName("FOO1");
assertThat(latestTaskExecution)
.as("Expected the latestTaskExecution not to be null").isNotNull();
final Calendar dateTime = Calendar.getInstance(TimeZone.getTimeZone("UTC")); final Calendar dateTime = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
dateTime.setTime(latestTaskExecution.getStartTime()); dateTime.setTime(latestTaskExecution.getStartTime());
assertEquals(2015, dateTime.get(Calendar.YEAR)); assertThat(dateTime.get(Calendar.YEAR)).isEqualTo(2015);
assertEquals(2, dateTime.get(Calendar.MONTH) + 1); assertThat(dateTime.get(Calendar.MONTH) + 1).isEqualTo(2);
assertEquals(22, dateTime.get(Calendar.DAY_OF_MONTH)); assertThat(dateTime.get(Calendar.DAY_OF_MONTH)).isEqualTo(22);
assertEquals(23, dateTime.get(Calendar.HOUR_OF_DAY)); assertThat(dateTime.get(Calendar.HOUR_OF_DAY)).isEqualTo(23);
assertEquals(59, dateTime.get(Calendar.MINUTE)); assertThat(dateTime.get(Calendar.MINUTE)).isEqualTo(59);
assertEquals(0, dateTime.get(Calendar.SECOND)); assertThat(dateTime.get(Calendar.SECOND)).isEqualTo(0);
} }
/** /**
* This test is a special use-case. While not common, it is theoretically possible, that a task may have * This test is a special use-case. While not common, it is theoretically possible,
* executed with the exact same start time multiple times. In that case we should still only get 1 returned * that a task may have executed with the exact same start time multiple times. In
* {@link TaskExecution}. * that case we should still only get 1 returned {@link TaskExecution}.
*/ */
@Test @Test
@DirtiesContext @DirtiesContext
public void getLatestTaskExecutionForTaskNameWithIdenticalTaskExecutions() { public void getLatestTaskExecutionForTaskNameWithIdenticalTaskExecutions() {
long executionIdOffset = initializeRepositoryNotInOrderWithMultipleTaskExecutions(); long executionIdOffset = initializeRepositoryNotInOrderWithMultipleTaskExecutions();
final TaskExecution latestTaskExecution = dao.getLatestTaskExecutionForTaskName("FOO5"); final TaskExecution latestTaskExecution = this.dao
assertNotNull("Expected the latestTaskExecution not to be null", latestTaskExecution); .getLatestTaskExecutionForTaskName("FOO5");
assertThat(latestTaskExecution)
.as("Expected the latestTaskExecution not to be null").isNotNull();
final Calendar dateTime = Calendar.getInstance(TimeZone.getTimeZone("UTC")); final Calendar dateTime = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
dateTime.setTime(latestTaskExecution.getStartTime()); dateTime.setTime(latestTaskExecution.getStartTime());
assertEquals(2015, dateTime.get(Calendar.YEAR)); assertThat(dateTime.get(Calendar.YEAR)).isEqualTo(2015);
assertEquals(2, dateTime.get(Calendar.MONTH) + 1); assertThat(dateTime.get(Calendar.MONTH) + 1).isEqualTo(2);
assertEquals(22, dateTime.get(Calendar.DAY_OF_MONTH)); assertThat(dateTime.get(Calendar.DAY_OF_MONTH)).isEqualTo(22);
assertEquals(23, dateTime.get(Calendar.HOUR_OF_DAY)); assertThat(dateTime.get(Calendar.HOUR_OF_DAY)).isEqualTo(23);
assertEquals(59, dateTime.get(Calendar.MINUTE)); assertThat(dateTime.get(Calendar.MINUTE)).isEqualTo(59);
assertEquals(0, dateTime.get(Calendar.SECOND)); assertThat(dateTime.get(Calendar.SECOND)).isEqualTo(0);
assertEquals(9 + executionIdOffset, latestTaskExecution.getExecutionId()); assertThat(latestTaskExecution.getExecutionId()).isEqualTo(9 + executionIdOffset);
} }
@Test @Test
@DirtiesContext @DirtiesContext
public void getRunningTaskExecutions() { public void getRunningTaskExecutions() {
initializeRepositoryNotInOrderWithMultipleTaskExecutions(); initializeRepositoryNotInOrderWithMultipleTaskExecutions();
assertEquals(dao.getTaskExecutionCount(), dao.getRunningTaskExecutionCount()); assertThat(this.dao.getRunningTaskExecutionCount())
dao.completeTaskExecution(1, 0, new Date(), "c'est fini!" ); .isEqualTo(this.dao.getTaskExecutionCount());
assertEquals(dao.getTaskExecutionCount() - 1, dao.getRunningTaskExecutionCount()); this.dao.completeTaskExecution(1, 0, new Date(), "c'est fini!");
assertThat(this.dao.getRunningTaskExecutionCount())
.isEqualTo(this.dao.getTaskExecutionCount() - 1);
} }
protected long initializeRepositoryNotInOrderWithMultipleTaskExecutions() { protected long initializeRepositoryNotInOrderWithMultipleTaskExecutions() {
@@ -304,7 +325,8 @@ public class BaseTaskExecutionDaoTestCases {
} }
private long createTaskExecution(TaskExecution te) { private long createTaskExecution(TaskExecution te) {
return dao.createTaskExecution(te.getTaskName(), te.getStartTime(), te.getArguments(), te.getExternalExecutionId()).getExecutionId(); return this.dao.createTaskExecution(te.getTaskName(), te.getStartTime(),
te.getArguments(), te.getExternalExecutionId()).getExecutionId();
} }
protected TaskExecution getTaskExecution(String taskName, protected TaskExecution getTaskExecution(String taskName,
@@ -315,4 +337,5 @@ public class BaseTaskExecutionDaoTestCases {
taskExecution.setStartTime(new Date()); taskExecution.setStartTime(new Date());
return taskExecution; return taskExecution;
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2015-2018 the original author or authors. * Copyright 2015-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -44,7 +44,7 @@ import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import static org.junit.Assert.assertEquals; import static org.assertj.core.api.Assertions.assertThat;
/** /**
* Executes unit tests on JdbcTaskExecutionDao. * Executes unit tests on JdbcTaskExecutionDao.
@@ -53,83 +53,95 @@ import static org.junit.Assert.assertEquals;
* @author Gunnar Hillert * @author Gunnar Hillert
*/ */
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@ContextConfiguration(classes = {TestConfiguration.class, @ContextConfiguration(classes = { TestConfiguration.class,
EmbeddedDataSourceConfiguration.class, EmbeddedDataSourceConfiguration.class,
PropertyPlaceholderAutoConfiguration.class}) PropertyPlaceholderAutoConfiguration.class })
public class JdbcTaskExecutionDaoTests extends BaseTaskExecutionDaoTestCases { public class JdbcTaskExecutionDaoTests extends BaseTaskExecutionDaoTestCases {
@Autowired
private DataSource dataSource;
@Autowired @Autowired
TaskRepository repository; TaskRepository repository;
@Autowired
private DataSource dataSource;
@Before @Before
public void setup(){ public void setup() {
final JdbcTaskExecutionDao dao = new JdbcTaskExecutionDao(dataSource); final JdbcTaskExecutionDao dao = new JdbcTaskExecutionDao(this.dataSource);
dao.setTaskIncrementer(TestDBUtils.getIncrementer(dataSource)); dao.setTaskIncrementer(TestDBUtils.getIncrementer(this.dataSource));
super.dao = dao; super.dao = dao;
} }
@Test @Test
@DirtiesContext @DirtiesContext
public void testStartTaskExecution() { public void testStartTaskExecution() {
TaskExecution expectedTaskExecution = dao.createTaskExecution(null, null, TaskExecution expectedTaskExecution = this.dao.createTaskExecution(null, null,
new ArrayList<String>(0), null); new ArrayList<>(0), null);
expectedTaskExecution.setArguments(Collections.singletonList("foo=" + UUID.randomUUID().toString())); expectedTaskExecution.setArguments(
Collections.singletonList("foo=" + UUID.randomUUID().toString()));
expectedTaskExecution.setStartTime(new Date()); expectedTaskExecution.setStartTime(new Date());
expectedTaskExecution.setTaskName(UUID.randomUUID().toString()); expectedTaskExecution.setTaskName(UUID.randomUUID().toString());
dao.startTaskExecution(expectedTaskExecution.getExecutionId(), expectedTaskExecution.getTaskName(), this.dao.startTaskExecution(expectedTaskExecution.getExecutionId(),
expectedTaskExecution.getStartTime(), expectedTaskExecution.getArguments(), expectedTaskExecution.getTaskName(), expectedTaskExecution.getStartTime(),
expectedTaskExecution.getArguments(),
expectedTaskExecution.getExternalExecutionId()); expectedTaskExecution.getExternalExecutionId());
TestVerifierUtils.verifyTaskExecution(expectedTaskExecution, TestVerifierUtils.verifyTaskExecution(expectedTaskExecution,
TestDBUtils.getTaskExecutionFromDB(dataSource, expectedTaskExecution.getExecutionId())); TestDBUtils.getTaskExecutionFromDB(this.dataSource,
expectedTaskExecution.getExecutionId()));
} }
@Test @Test
@DirtiesContext @DirtiesContext
public void createTaskExecution() { public void createTaskExecution() {
TaskExecution expectedTaskExecution = TestVerifierUtils.createSampleTaskExecutionNoArg(); TaskExecution expectedTaskExecution = TestVerifierUtils
expectedTaskExecution = dao.createTaskExecution(expectedTaskExecution.getTaskName(), expectedTaskExecution.getStartTime(), .createSampleTaskExecutionNoArg();
expectedTaskExecution.getArguments(), expectedTaskExecution.getExternalExecutionId()); expectedTaskExecution = this.dao.createTaskExecution(
expectedTaskExecution.getTaskName(), expectedTaskExecution.getStartTime(),
expectedTaskExecution.getArguments(),
expectedTaskExecution.getExternalExecutionId());
TestVerifierUtils.verifyTaskExecution(expectedTaskExecution, TestVerifierUtils.verifyTaskExecution(expectedTaskExecution,
TestDBUtils.getTaskExecutionFromDB(dataSource, expectedTaskExecution.getExecutionId())); TestDBUtils.getTaskExecutionFromDB(this.dataSource,
expectedTaskExecution.getExecutionId()));
} }
@Test @Test
@DirtiesContext @DirtiesContext
public void createEmptyTaskExecution() { public void createEmptyTaskExecution() {
TaskExecution expectedTaskExecution = dao.createTaskExecution(null, null, TaskExecution expectedTaskExecution = this.dao.createTaskExecution(null, null,
new ArrayList<String>(0), null); new ArrayList<>(0), null);
TestVerifierUtils.verifyTaskExecution(expectedTaskExecution, TestVerifierUtils.verifyTaskExecution(expectedTaskExecution,
TestDBUtils.getTaskExecutionFromDB(dataSource, expectedTaskExecution.getExecutionId())); TestDBUtils.getTaskExecutionFromDB(this.dataSource,
expectedTaskExecution.getExecutionId()));
} }
@Test @Test
@DirtiesContext @DirtiesContext
public void completeTaskExecution() { public void completeTaskExecution() {
TaskExecution expectedTaskExecution = TestVerifierUtils.endSampleTaskExecutionNoArg(); TaskExecution expectedTaskExecution = TestVerifierUtils
expectedTaskExecution = dao.createTaskExecution(expectedTaskExecution.getTaskName(), .endSampleTaskExecutionNoArg();
expectedTaskExecution.getStartTime(), expectedTaskExecution.getArguments(), expectedTaskExecution = this.dao.createTaskExecution(
expectedTaskExecution.getTaskName(), expectedTaskExecution.getStartTime(),
expectedTaskExecution.getArguments(),
expectedTaskExecution.getExternalExecutionId()); expectedTaskExecution.getExternalExecutionId());
dao.completeTaskExecution(expectedTaskExecution.getExecutionId(), this.dao.completeTaskExecution(expectedTaskExecution.getExecutionId(),
expectedTaskExecution.getExitCode(), expectedTaskExecution.getEndTime(), expectedTaskExecution.getExitCode(), expectedTaskExecution.getEndTime(),
expectedTaskExecution.getExitMessage()); expectedTaskExecution.getExitMessage());
TestVerifierUtils.verifyTaskExecution(expectedTaskExecution, TestVerifierUtils.verifyTaskExecution(expectedTaskExecution,
TestDBUtils.getTaskExecutionFromDB(dataSource, expectedTaskExecution.getExecutionId())); TestDBUtils.getTaskExecutionFromDB(this.dataSource,
expectedTaskExecution.getExecutionId()));
} }
@Test(expected = IllegalStateException.class) @Test(expected = IllegalStateException.class)
@DirtiesContext @DirtiesContext
public void completeTaskExecutionWithNoCreate() { public void completeTaskExecutionWithNoCreate() {
JdbcTaskExecutionDao dao = new JdbcTaskExecutionDao(dataSource); JdbcTaskExecutionDao dao = new JdbcTaskExecutionDao(this.dataSource);
TaskExecution expectedTaskExecution = TestVerifierUtils.endSampleTaskExecutionNoArg(); TaskExecution expectedTaskExecution = TestVerifierUtils
.endSampleTaskExecutionNoArg();
dao.completeTaskExecution(expectedTaskExecution.getExecutionId(), dao.completeTaskExecution(expectedTaskExecution.getExecutionId(),
expectedTaskExecution.getExitCode(), expectedTaskExecution.getEndTime(), expectedTaskExecution.getExitCode(), expectedTaskExecution.getEndTime(),
expectedTaskExecution.getExitMessage()); expectedTaskExecution.getExitMessage());
@@ -137,89 +149,90 @@ public class JdbcTaskExecutionDaoTests extends BaseTaskExecutionDaoTestCases {
@Test @Test
@DirtiesContext @DirtiesContext
public void testFindAllPageableSort() { public void testFindAllPageableSort() {
initializeRepositoryNotInOrder(); initializeRepositoryNotInOrder();
Sort sort = Sort.by(new Sort.Order(Sort.Direction.ASC, Sort sort = Sort.by(new Sort.Order(Sort.Direction.ASC, "EXTERNAL_EXECUTION_ID"));
"EXTERNAL_EXECUTION_ID"));
Iterator<TaskExecution> iter = getPageIterator(0, 2, sort); Iterator<TaskExecution> iter = getPageIterator(0, 2, sort);
TaskExecution taskExecution = iter.next(); TaskExecution taskExecution = iter.next();
assertEquals("FOO2", taskExecution.getTaskName()); assertThat(taskExecution.getTaskName()).isEqualTo("FOO2");
taskExecution = iter.next(); taskExecution = iter.next();
assertEquals("FOO3", taskExecution.getTaskName()); assertThat(taskExecution.getTaskName()).isEqualTo("FOO3");
iter = getPageIterator(1, 2, sort); iter = getPageIterator(1, 2, sort);
taskExecution = iter.next(); taskExecution = iter.next();
assertEquals("FOO1", taskExecution.getTaskName()); assertThat(taskExecution.getTaskName()).isEqualTo("FOO1");
} }
@Test @Test
@DirtiesContext @DirtiesContext
public void testFindAllDefaultSort() { public void testFindAllDefaultSort() {
initializeRepository(); initializeRepository();
Iterator<TaskExecution> iter = getPageIterator(0, 2, null); Iterator<TaskExecution> iter = getPageIterator(0, 2, null);
TaskExecution taskExecution = iter.next(); TaskExecution taskExecution = iter.next();
assertEquals("FOO1", taskExecution.getTaskName()); assertThat(taskExecution.getTaskName()).isEqualTo("FOO1");
taskExecution = iter.next(); taskExecution = iter.next();
assertEquals("FOO2", taskExecution.getTaskName()); assertThat(taskExecution.getTaskName()).isEqualTo("FOO2");
iter = getPageIterator(1, 2, null); iter = getPageIterator(1, 2, null);
taskExecution = iter.next(); taskExecution = iter.next();
assertEquals("FOO3", taskExecution.getTaskName()); assertThat(taskExecution.getTaskName()).isEqualTo("FOO3");
} }
@Test @Test
@DirtiesContext @DirtiesContext
public void testStartExecutionWithNullExternalExecutionIdExisting() { public void testStartExecutionWithNullExternalExecutionIdExisting() {
TaskExecution expectedTaskExecution = TaskExecution expectedTaskExecution = initializeTaskExecutionWithExternalExecutionId();
initializeTaskExecutionWithExternalExecutionId();
dao.startTaskExecution(expectedTaskExecution.getExecutionId(), expectedTaskExecution.getTaskName(), this.dao.startTaskExecution(expectedTaskExecution.getExecutionId(),
expectedTaskExecution.getStartTime(), expectedTaskExecution.getArguments(), expectedTaskExecution.getTaskName(), expectedTaskExecution.getStartTime(),
null); expectedTaskExecution.getArguments(), null);
TestVerifierUtils.verifyTaskExecution(expectedTaskExecution, TestVerifierUtils.verifyTaskExecution(expectedTaskExecution,
TestDBUtils.getTaskExecutionFromDB(dataSource, expectedTaskExecution.getExecutionId())); TestDBUtils.getTaskExecutionFromDB(this.dataSource,
expectedTaskExecution.getExecutionId()));
} }
@Test @Test
@DirtiesContext @DirtiesContext
public void testStartExecutionWithNullExternalExecutionIdNonExisting() { public void testStartExecutionWithNullExternalExecutionIdNonExisting() {
TaskExecution expectedTaskExecution = TaskExecution expectedTaskExecution = initializeTaskExecutionWithExternalExecutionId();
initializeTaskExecutionWithExternalExecutionId();
dao.startTaskExecution(expectedTaskExecution.getExecutionId(), expectedTaskExecution.getTaskName(), this.dao.startTaskExecution(expectedTaskExecution.getExecutionId(),
expectedTaskExecution.getStartTime(), expectedTaskExecution.getArguments(), expectedTaskExecution.getTaskName(), expectedTaskExecution.getStartTime(),
"BAR"); expectedTaskExecution.getArguments(), "BAR");
expectedTaskExecution.setExternalExecutionId("BAR"); expectedTaskExecution.setExternalExecutionId("BAR");
TestVerifierUtils.verifyTaskExecution(expectedTaskExecution, TestVerifierUtils.verifyTaskExecution(expectedTaskExecution,
TestDBUtils.getTaskExecutionFromDB(dataSource, expectedTaskExecution.getExecutionId())); TestDBUtils.getTaskExecutionFromDB(this.dataSource,
expectedTaskExecution.getExecutionId()));
} }
private TaskExecution initializeTaskExecutionWithExternalExecutionId() { private TaskExecution initializeTaskExecutionWithExternalExecutionId() {
TaskExecution expectedTaskExecution = TestVerifierUtils.createSampleTaskExecutionNoArg(); TaskExecution expectedTaskExecution = TestVerifierUtils
.createSampleTaskExecutionNoArg();
return this.dao.createTaskExecution(expectedTaskExecution.getTaskName(), return this.dao.createTaskExecution(expectedTaskExecution.getTaskName(),
expectedTaskExecution.getStartTime(), expectedTaskExecution.getArguments(), expectedTaskExecution.getStartTime(),
"FOO1"); expectedTaskExecution.getArguments(), "FOO1");
} }
private Iterator<TaskExecution> getPageIterator(int pageNum, int pageSize, Sort sort) { private Iterator<TaskExecution> getPageIterator(int pageNum, int pageSize,
Pageable pageable = (sort == null) ? Sort sort) {
PageRequest.of(pageNum, pageSize) : Pageable pageable = (sort == null) ? PageRequest.of(pageNum, pageSize)
PageRequest.of(pageNum, pageSize, sort); : PageRequest.of(pageNum, pageSize, sort);
Page<TaskExecution> page = dao.findAll(pageable); Page<TaskExecution> page = this.dao.findAll(pageable);
assertEquals(3, page.getTotalElements()); assertThat(page.getTotalElements()).isEqualTo(3);
assertEquals(2, page.getTotalPages()); assertThat(page.getTotalPages()).isEqualTo(2);
return page.iterator(); return page.iterator();
} }
private void initializeRepository() { private void initializeRepository() {
repository.createTaskExecution(getTaskExecution("FOO3", "externalA")); this.repository.createTaskExecution(getTaskExecution("FOO3", "externalA"));
repository.createTaskExecution(getTaskExecution("FOO2", "externalB")); this.repository.createTaskExecution(getTaskExecution("FOO2", "externalB"));
repository.createTaskExecution(getTaskExecution("FOO1", "externalC")); this.repository.createTaskExecution(getTaskExecution("FOO1", "externalC"));
} }
private void initializeRepositoryNotInOrder() { private void initializeRepositoryNotInOrder() {
repository.createTaskExecution(getTaskExecution("FOO1", "externalC")); this.repository.createTaskExecution(getTaskExecution("FOO1", "externalC"));
repository.createTaskExecution(getTaskExecution("FOO2", "externalA")); this.repository.createTaskExecution(getTaskExecution("FOO2", "externalA"));
repository.createTaskExecution(getTaskExecution("FOO3", "externalB")); this.repository.createTaskExecution(getTaskExecution("FOO3", "externalB"));
} }
} }

Some files were not shown because too many files have changed in this diff Show More