SCT-4 Added SimpleTaskConfiguration

* Added unit tests
* Introduced @EnableTask
* Readme updated to include @EnableTask
* Removed warnings from build
* Cleanup
This commit is contained in:
Glenn Renfro
2015-11-23 15:52:03 -05:00
committed by Michael Minella
parent 93e4698175
commit ce8854b89e
19 changed files with 697 additions and 38 deletions

View File

@@ -0,0 +1,68 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.task.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.cloud.task.configuration.DefaultTaskConfigurer;
import org.springframework.cloud.task.configuration.SimpleTaskConfiguration;
import org.springframework.cloud.task.configuration.TaskConfigurer;
import org.springframework.cloud.task.repository.TaskRepository;
import org.springframework.context.annotation.Import;
/**
* <p>
* Enable Spring Task features and provide a base configuration for setting up
* {@link Task} objects in an &#064;Configuration class.
*
* <pre class="code">
* &#064;Configuration
* &#064;EnableTask
* public class AppConfig {
*
* &#064;Bean
* public MyCommandLineRunner myCommandLineRunner() {
* return new MyCommandLineRunner()
* }
* }
* </pre>
*
* Note that only one of your configuration classes needs to have the <code>&#064;EnableTask</code>
* annotation. Once you have an <code>&#064;EnableTask</code> class in your configuration
* you will have an instance of {@link TaskConfigurer}. If one is not specified then the
* {@link DefaultTaskConfigurer} will be used.
* You will also be able to <code>&#064;Autowired</code> some useful stuff into your context:
*
* <ul>
* <li>a {@link TaskRepository} (bean name "taskRepository").</li>
* </ul>
*
* @author Glenn Renfro
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(SimpleTaskConfiguration.class)
public @interface EnableTask {
}

View File

@@ -23,10 +23,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.cloud.task.configuration.DefaultTaskConfigurer;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Component;
/**
* Annotation that identifies a class as a task. This annotation will serve as the
* main “hook” to activate the various Spring Cloud Task features.
@@ -37,12 +33,11 @@ import org.springframework.stereotype.Component;
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Component
@Import({ DefaultTaskConfigurer.class })
public @interface Task {
/**
* Establishes the name associated with the task. The default is empty.
* @return returns name associated with the task or an empty string.
*/
public String value() default "";

View File

@@ -16,28 +16,26 @@
package org.springframework.cloud.task.configuration;
import org.springframework.cloud.task.repository.support.LoggerTaskRepository;
import org.springframework.cloud.task.repository.TaskRepository;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.cloud.task.repository.support.LoggerTaskRepository;
/**
* If no TaskConfigurer is present this configuration will be used.
* If no {@link TaskConfigurer} is present, then this configuration will be used.
* The following defaults will be used:
*
* <ul>
* <li>{@link LoggerTaskRepository} will be the default {@link TaskRepository}.</li>
* </ul>
*
*
* @author Glenn Renfro
*/
@Configuration
public class DefaultTaskConfigurer {
public class DefaultTaskConfigurer implements TaskConfigurer{
@Bean
@Scope("prototype")
public TaskHandler taskHandler() {
return new TaskHandler();
public DefaultTaskConfigurer(){
}
@Bean
public TaskRepository taskRepository() {
public TaskRepository getTaskRepository() {
return new LoggerTaskRepository();
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.task.configuration;
import java.util.Collection;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.task.repository.TaskRepository;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
/**
* Base {@code Configuration} class providing common structure for enabling and using
* Spring Task. Customization is
* available by implementing the {@link TaskConfigurer} interface.
*
* @author Glenn Renfro
*/
@Configuration
public class SimpleTaskConfiguration {
@Autowired
private ApplicationContext context;
private boolean initialized = false;
private TaskRepository taskRepository;
private TaskConfigurer configurer;
@Bean
@Scope("prototype")
public TaskHandler taskHandler() {
return new TaskHandler();
}
@Bean
public TaskRepository taskRepository(){
return taskRepository;
}
/**
* Sets up the basic components by extracting them from the {@link TaskConfigurer}, defaulting to some
* sensible values as long as a unique DataSource is available.
*/
@PostConstruct
private void initialize() {
if (initialized) {
return;
}
TaskConfigurer configurer = getConfigurer(context.getBeansOfType(TaskConfigurer.class).values());
taskRepository = configurer.getTaskRepository();
initialized = true;
}
private TaskConfigurer getConfigurer(Collection<TaskConfigurer> configurers) {
if (this.configurer != null) {
return this.configurer;
}
if (configurers == null || configurers.isEmpty()) {
DefaultTaskConfigurer configurer = new DefaultTaskConfigurer();
this.configurer = configurer;
return configurer;
}
if (configurers.size() > 1) {
throw new IllegalStateException(
"To use a custom TaskConfigurer the context must contain precisely one, found "
+ configurers.size());
}
this.configurer = configurers.iterator().next();
return this.configurer;
}
}

View File

@@ -31,6 +31,6 @@ public interface TaskConfigurer {
*
* @return A TaskRepository
*/
public TaskRepository taskRepository();
public TaskRepository getTaskRepository();
}

View File

@@ -26,6 +26,8 @@ import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.ExitCodeGenerator;
import org.springframework.cloud.task.annotation.Task;
import org.springframework.cloud.task.repository.TaskExecution;
@@ -33,8 +35,9 @@ import org.springframework.cloud.task.repository.TaskRepository;
import org.springframework.context.ApplicationContext;
/**
* Offers the advice on how to record tasks to the repository for both applicationrunner
* and commandlinerunner spring boot applications.
* Offers the advice on how to record tasks to the repository for both
* {@link org.springframework.boot.ApplicationRunner} and
* {@link org.springframework.boot.CommandLineRunner} spring boot applications.
*
* @author Glenn Renfro
*/
@@ -54,11 +57,12 @@ public class TaskHandler {
private TaskExecution taskExecution;
/**
* Looks for any CommandLineRunner.run method with its class annotated with @Task
* Looks for any {@link CommandLineRunner}.run method with its class annotated with @Task
* and calls the repository implementation to store the start of the task in the repo
* before the run starts.
*
* @param joinPoint
* @param joinPoint the point where the run method in a {@link CommandLineRunner} or
* {@link ApplicationRunner} is executed
*/
@Before("within( @org.springframework.cloud.task.annotation.Task *) && (execution(* org.springframework.boot.CommandLineRunner.run(..)) || execution(* org.springframework.boot.ApplicationRunner.run(..)))")
public void beforeCommandLineRunner(JoinPoint joinPoint) {
@@ -78,11 +82,12 @@ public class TaskHandler {
}
/**
* Looks for any CommandLineRunner.run method with its class annotated with @Task
* Looks for any {@link CommandLineRunner}.run method with its class annotated with @Task
* and calls repository implementation to store the exit of the task in the repo after
* run returns result.
*
* @param joinPoint
* @param joinPoint the point where the run method in a {@link CommandLineRunner} or
* {@link ApplicationRunner} is executed
*/
@AfterReturning("within( @org.springframework.cloud.task.annotation.Task *) && (execution(* org.springframework.boot.CommandLineRunner.run(..)) || execution(* org.springframework.boot.ApplicationRunner.run(..)))")
public void afterReturnCommandLineRunner(JoinPoint joinPoint) {
@@ -99,11 +104,12 @@ public class TaskHandler {
}
/**
* Looks for any CommandLineRunner. run method with its class annotated with @Task
* Looks for any {@link CommandLineRunner}.run method with its class annotated with @Task
* and calls the repository implementation to store the exitCode of 1
* for the task in the repo in the case of an exception.
*
* @param joinPoint
* @param joinPoint the point where the run method in a {@link CommandLineRunner} or
* {@link ApplicationRunner} is executed
*/
@AfterThrowing("within( @org.springframework.cloud.task.annotation.Task *) && (execution(* org.springframework.boot.CommandLineRunner.run(..)) || execution(* org.springframework.boot.ApplicationRunner.run(..)))")
public void logExceptionCommandLineRunner(JoinPoint joinPoint) {
@@ -112,4 +118,7 @@ public class TaskHandler {
repository.update(taskExecution);
}
public TaskExecution getTaskExecution() {
return taskExecution;
}
}

View File

@@ -18,7 +18,7 @@ package org.springframework.cloud.task.repository;
/**
* TaskRepository interface offers methods that create and update task execution
* information. The interface will support the following methods:
* information.
*
* @author Glenn Renfro
*/

View File

@@ -24,6 +24,8 @@ import org.springframework.cloud.task.repository.TaskExecution;
import org.springframework.cloud.task.repository.TaskRepository;
/**
* {@link TaskRepository} implementation that will log the task execution information.
*
* @author Glenn Renfro
*/
public class LoggerTaskRepository implements TaskRepository {