Initial commit of POC functionality

This commit provides the inital code from a POC of spring-cloud-task
functionality.  Further cleanup will be done and tracked via future
stories.
This commit is contained in:
Glenn Renfro
2015-11-19 17:29:01 -05:00
committed by Michael Minella
parent d83cf5797b
commit bd1243cae6
13 changed files with 681 additions and 1 deletions

32
.gitignore vendored Normal file
View File

@@ -0,0 +1,32 @@
*~
.#*
*#
*.sw*
_site/
.factorypath
.gradletasknamecache
.DS_Store
/application.yml
/application.properties
asciidoctor.css
atlassian-ide-plugin.xml
bin/
build/
dump.rdb
out
spring-shell.log
target/
test-output
# Eclipse artifacts, including WTP generated manifests
.classpath
.project
.settings/
.springBeans
spring-*/src/main/java/META-INF/MANIFEST.MF
# IDEA artifacts and output dirs
*.iml
*.ipr
*.iws
.idea/*

32
README.adoc Normal file
View File

@@ -0,0 +1,32 @@
= Spring Cloud Task
Is a project centered around the idea of processing on demand. A user is able to develop
a “task” that can be deployed, executed and removed on demand, yet the result of the
process persists beyond the life of the task for future reporting.
== Requirements:
* Java 7 or Above
== Build:
[source,shell,indent=2]
----
$ mvn clean install
----
== Example:
[source,java,indent=2]
----
@Task("imSampleB")
public class SampleB implements CommandLineRunner {
@Override
public void run(String... args) {
System.out.println("hello world");
}
}
----

View File

@@ -1 +0,0 @@
# spring-cloud-task

33
pom.xml Executable file
View File

@@ -0,0 +1,33 @@
<?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">
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.3.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-task-parent</artifactId>
<packaging>pom</packaging>
<name>spring-cloud-task-parent</name>
<version>1.0.0.BUILD-SNAPSHOT</version>
<description>Spring Cloud Task Parent</description>
<modules>
<module>spring-cloud-task-core</module>
</modules>
</project>

27
spring-cloud-task-core/pom.xml Executable file
View File

@@ -0,0 +1,27 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-task-parent</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
</parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-task-core</artifactId>
<packaging>jar</packaging>
<name>spring-cloud-task-core</name>
<version>1.0.0.BUILD-SNAPSHOT</version>
<description>Spring Cloud Task</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,49 @@
/*
* 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.config.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.
*
* @author Glenn Renfro
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Component
@Import({ DefaultTaskConfigurer.class })
public @interface Task {
/**
* Establishes the name associated with the task. The default is empty.
*/
public String value() default "";
}

View File

@@ -0,0 +1,44 @@
/*
* 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.config;
import org.springframework.cloud.task.repository.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;
/**
* If no TaskConfigurer is present this configuration will be used.
* @author Glenn Renfro
*/
@Configuration
public class DefaultTaskConfigurer {
@Bean
@Scope("prototype")
public TaskHandler taskHandler() {
return new TaskHandler();
}
@Bean
public TaskRepository taskRepository() {
return new LoggerTaskRepository();
}
}

View File

@@ -0,0 +1,36 @@
/*
* 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.config;
import org.springframework.cloud.task.repository.TaskRepository;
/**
* Provides a strategy interface for providing configuration
* customization to the task system.
*
* @author Glenn Renfro
*/
public interface TaskConfigurer {
/**
* Create a Task Repository for the Task.
*
* @return A TaskRepository
*/
public TaskRepository taskRepository();
}

View File

@@ -0,0 +1,115 @@
/*
* 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.config;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
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.ExitCodeGenerator;
import org.springframework.cloud.task.annotation.Task;
import org.springframework.cloud.task.repository.TaskExecution;
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.
*
* @author Glenn Renfro
*/
@Aspect
public class TaskHandler {
@Autowired
private ApplicationContext context;
@Autowired
private TaskRepository repository;
private String taskName;
private String executionId;
private TaskExecution taskExecution;
/**
* Looks for any 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
*/
@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) {
executionId = UUID.randomUUID().toString();
taskExecution = new TaskExecution();
Task a = joinPoint.getTarget().getClass().getAnnotation(Task.class);
taskName = a.value();
if (taskName == null || taskName.length() == 0) {
taskName = joinPoint.getTarget().getClass().getName();
}
taskExecution.setTaskName(taskName);
taskExecution.setStartTime(new Date());
taskExecution.setExecutionId(executionId);
repository.createTaskExecution(taskExecution);
}
/**
* Looks for any 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
*/
@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) {
int result = 0;
List<ExitCodeGenerator> generators = new ArrayList<ExitCodeGenerator>();
generators
.addAll(context.getBeansOfType(ExitCodeGenerator.class).values());
for (ExitCodeGenerator generator : generators) {
result = generator.getExitCode();
}
taskExecution.setEndTime(new Date());
taskExecution.setExitCode(result);
repository.update(taskExecution);
}
/**
* Looks for any 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
*/
@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) {
taskExecution.setEndTime(new Date());
taskExecution.setExitCode(1);
repository.update(taskExecution);
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.task.repository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Glenn Renfro
*/
public class LoggerTaskRepository implements TaskRepository {
private final static Logger logger = LoggerFactory.getLogger(LoggerTaskRepository.class);
@Override
public void update(TaskExecution taskExecution) {
logger.info("Updating: " + taskExecution.toString());
}
@Override
public void createTaskExecution(TaskExecution taskExecution) {
logger.info("Creating: " + taskExecution.toString());
}
}

View File

@@ -0,0 +1,163 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.task.repository;
import java.util.Date;
import java.util.List;
/**
* Represents the state of the Task for each execution.
*
* @author Glenn Renfro
*/
public class TaskExecution {
public TaskExecution() {
}
public TaskExecution(String executionId, int exitCode, String taskName,
Date startTime, Date endTime, String statusCode,
String exitMessage, List<String> parameters) {
this.executionId = executionId;
this.exitCode = exitCode;
this.taskName = taskName;
this.startTime = startTime;
this.endTime = endTime;
this.statusCode = statusCode;
this.exitMessage = exitMessage;
this.parameters = parameters;
}
/**
* The unique id associated with the task execution.
*/
private String executionId;
/**
* The recorded exit code for the task.
*/
private int exitCode;
/**
* User defined name for the task.
*/
private String taskName;
/**
* Time of when the task was started.
*/
private Date startTime;
/**
* Timestamp of when the task was completed/terminated.
*/
private Date endTime;
/**
* TBD.
*/
private String statusCode;
/**
* Message returned from the task or stacktrace.parameters.
*/
private String exitMessage;
/**
* The parameters that were used for this task execution.
*/
private List<String> parameters;
public String getExecutionId() {
return executionId;
}
public void setExecutionId(String executionId) {
this.executionId = executionId;
}
public int getExitCode() {
return exitCode;
}
public void setExitCode(int exitCode) {
this.exitCode = exitCode;
}
public String getTaskName() {
return taskName;
}
public void setTaskName(String taskName) {
this.taskName = taskName;
}
public Date getStartTime() {
return startTime;
}
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
public Date getEndTime() {
return endTime;
}
public void setEndTime(Date endTime) {
this.endTime = endTime;
}
public String getStatusCode() {
return statusCode;
}
public void setStatusCode(String statusCode) {
this.statusCode = statusCode;
}
public String getExitMessage() {
return exitMessage;
}
public void setExitMessage(String exitMessage) {
this.exitMessage = exitMessage;
}
public List<String> getParameters() {
return parameters;
}
public void setParameters(List<String> parameters) {
this.parameters = parameters;
}
@Override
public String toString() {
return "TaskExecution{" +
"executionId='" + executionId + '\'' +
", exitCode=" + exitCode +
", taskName='" + taskName + '\'' +
", startTime=" + startTime +
", endTime=" + endTime +
", statusCode='" + statusCode + '\'' +
", exitMessage='" + exitMessage + '\'' +
", parameters=" + parameters +
'}';
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.task.repository;
import java.util.List;
import java.util.Set;
/**
* Offers methods that allow users to query the task executions that are available.
*
* @author Glenn Renfro
*/
public interface TaskExplorer {
/**
* Retrieve a {@link TaskExecution} by its id.
*
* @param executionId the task execution id
* @return the {@link TaskExecution} with this id, or null if not found
*/
public TaskExecution getTaskExecution(Long executionId);
/**
* Retrieve a collection of taskExecutions that have the task name provided.
*
* @param taskName the name of the task
* @return the set of running executions for tasks with the specified name
*/
public Set<TaskExecution> findRunningTaskExecutions(String taskName);
/**
* Retrieve a list of available task names.
*
* @return the set of task names that have been executed
*/
public List<String> getTaskNames();
/**
* Get number of executions for a taskName.
*
* @param taskName the name of the task to be searched
* @return the number of running tasks that have the taskname specified
*/
public long getTaskExecutionCount(String taskName);
/**
* Get a collection/page of executions
*
* @param taskName the name of the task to be searched
* @param start the position of the first execution to return
* @param count the number of executions to return
* @return list of task executions
*/
public List<TaskExecution> getTaskExecutionsByName(String taskName, int start, int count);
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.task.repository;
/**
* TaskRepository interface offers methods that create and update task execution
* information. The interface will support the following methods:
*
* @author Glenn Renfro
*/
public interface TaskRepository {
/**
* Notifies the repository that a taskExecution needs to be updated.
*
* @param taskExecution taskExecution to be updated
*/
public void update(TaskExecution taskExecution);
/**
* Notifies the repository that a taskExecution needs to be created.
*
* @param taskExecution taskExecution to be recorded
*/
public void createTaskExecution(TaskExecution taskExecution);
}