diff --git a/spring-cloud-task-dependencies/pom.xml b/spring-cloud-task-dependencies/pom.xml index 72aab721..87f13020 100644 --- a/spring-cloud-task-dependencies/pom.xml +++ b/spring-cloud-task-dependencies/pom.xml @@ -21,6 +21,7 @@ 1.0.0.M1 1.0.0.M1 1.0.0.RC3 + 1.0.0.M1 @@ -70,6 +71,11 @@ spring-cloud-deployer-local ${spring-cloud-deployer-spi.version} + + org.springframework.cloud + spring-cloud-deployer-resource-support + ${spring.cloud.deployer.resource.support} + org.springframework.cloud spring-cloud-starter-stream-rabbit diff --git a/spring-cloud-task-samples/taskprocessor/src/main/java/io/spring/TaskProcessor.java b/spring-cloud-task-samples/taskprocessor/src/main/java/io/spring/TaskProcessor.java index c9f03e98..5f570cb9 100644 --- a/spring-cloud-task-samples/taskprocessor/src/main/java/io/spring/TaskProcessor.java +++ b/spring-cloud-task-samples/taskprocessor/src/main/java/io/spring/TaskProcessor.java @@ -58,9 +58,7 @@ public class TaskProcessor { } properties.put("payload", message); - TaskLaunchRequest request = new TaskLaunchRequest(processorProperties.getArtifact(), - processorProperties.getGroup(), processorProperties.getVersion(), processorProperties.getExtension(), - processorProperties.getClassifiers(), properties); + TaskLaunchRequest request = new TaskLaunchRequest(processorProperties.getUri(), null, properties); return new GenericMessage(request); } diff --git a/spring-cloud-task-samples/taskprocessor/src/main/java/io/spring/TaskProcessorProperties.java b/spring-cloud-task-samples/taskprocessor/src/main/java/io/spring/TaskProcessorProperties.java index 2b177f41..b3541b42 100644 --- a/spring-cloud-task-samples/taskprocessor/src/main/java/io/spring/TaskProcessorProperties.java +++ b/spring-cloud-task-samples/taskprocessor/src/main/java/io/spring/TaskProcessorProperties.java @@ -24,24 +24,11 @@ import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties public class TaskProcessorProperties { - private static final String DEFAULT_GROUP = "io.spring.cloud"; - - private static final String DEFAULT_ARTIFACT = "timestamp-task"; - - private static final String DEFAULT_VERSION = "1.0.0.BUILD-SNAPSHOT"; - - private static final String DEFAULT_EXTENSION = "jar"; + private static final String DEFAULT_URI = "maven://org.springframework.cloud.task.app:" + + "timestamp-task:jar:1.0.0.BUILD-SNAPSHOT"; - private String group = DEFAULT_GROUP; - - private String artifact = DEFAULT_ARTIFACT; - - private String version = DEFAULT_VERSION; - - private String extension = DEFAULT_EXTENSION; - - private String classifiers; + private String uri = DEFAULT_URI; private String dataSourceUrl; @@ -52,21 +39,6 @@ public class TaskProcessorProperties { private String dataSourcePassword; - public String getExtension() { - return extension; - } - - public void setExtension(String extension) { - this.extension = extension; - } - - public String getClassifiers() { - return classifiers; - } - - public void setClassifiers(String classifiers) { - this.classifiers = classifiers; - } public String getDataSourceUrl() { return dataSourceUrl; @@ -100,27 +72,11 @@ public class TaskProcessorProperties { this.dataSourcePassword = dataSourcePassword; } - public void setGroup(String group) { - this.group = group; + public String getUri() { + return uri; } - public String getGroup() { - return group; - } - - public String getArtifact() { - return artifact; - } - - public void setArtifact(String artifact) { - this.artifact = artifact; - } - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; + public void setUri(String uri) { + this.uri = uri; } } diff --git a/spring-cloud-task-samples/taskprocessor/src/test/java/io/spring/TaskProcessorApplicationTests.java b/spring-cloud-task-samples/taskprocessor/src/test/java/io/spring/TaskProcessorApplicationTests.java index 25e8abdd..6867e652 100644 --- a/spring-cloud-task-samples/taskprocessor/src/test/java/io/spring/TaskProcessorApplicationTests.java +++ b/spring-cloud-task-samples/taskprocessor/src/test/java/io/spring/TaskProcessorApplicationTests.java @@ -55,8 +55,8 @@ public class TaskProcessorApplicationTests { channels.input().send(new GenericMessage(DEFAULT_PAYLOAD)); Map properties = new HashMap(); properties.put("payload", DEFAULT_PAYLOAD); - TaskLaunchRequest expectedRequest = new TaskLaunchRequest("timestamp-task", - "io.spring.cloud", "1.0.0.BUILD-SNAPSHOT", "jar", null, properties); + TaskLaunchRequest expectedRequest = new TaskLaunchRequest("maven://org.springframework.cloud.task.app:" + + "timestamp-task:jar:1.0.0.BUILD-SNAPSHOT", null, properties); assertThat(collector.forChannel(channels.output()), receivesPayloadThat(is(expectedRequest))); } diff --git a/spring-cloud-task-samples/tasksink/src/test/java/io/spring/TaskSinkApplicationTests.java b/spring-cloud-task-samples/tasksink/src/test/java/io/spring/TaskSinkApplicationTests.java index b2703408..2a3ce4da 100644 --- a/spring-cloud-task-samples/tasksink/src/test/java/io/spring/TaskSinkApplicationTests.java +++ b/spring-cloud-task-samples/tasksink/src/test/java/io/spring/TaskSinkApplicationTests.java @@ -59,9 +59,8 @@ public class TaskSinkApplicationTests { Map properties = new HashMap(); properties.put("server.port", "0"); - TaskLaunchRequest request = new TaskLaunchRequest("timestamp-task", - "org.springframework.cloud.task.module","1.0.0.BUILD-SNAPSHOT", "jar", - "exec", properties); + TaskLaunchRequest request = new TaskLaunchRequest("maven://org.springframework.cloud.task.app:" + + "timestamp-task:jar:1.0.0.BUILD-SNAPSHOT", null, properties); GenericMessage message = new GenericMessage(request); this.sink.input().send(message); assertEquals(LaunchState.complete, testTaskLauncher.status("TESTSTATUS").getState()); diff --git a/spring-cloud-task-stream/pom.xml b/spring-cloud-task-stream/pom.xml index cfc5a2d0..2aa21f5f 100644 --- a/spring-cloud-task-stream/pom.xml +++ b/spring-cloud-task-stream/pom.xml @@ -13,7 +13,6 @@ spring-cloud-task-parent 1.0.0.BUILD-SNAPSHOT - org.springframework.batch @@ -57,5 +56,9 @@ spring-cloud-task-batch test + + org.springframework.cloud + spring-cloud-deployer-resource-support + diff --git a/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/launcher/TaskLaunchRequest.java b/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/launcher/TaskLaunchRequest.java index d2afeffb..40acd20c 100644 --- a/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/launcher/TaskLaunchRequest.java +++ b/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/launcher/TaskLaunchRequest.java @@ -18,11 +18,13 @@ package org.springframework.cloud.task.launcher; import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.springframework.util.Assert; -import org.springframework.util.StringUtils; /** * Request that contains the maven repository and property information required by the @@ -33,76 +35,37 @@ import org.springframework.util.StringUtils; public class TaskLaunchRequest implements Serializable{ private static final long serialVersionUID = 1L; - private String artifact; - private String taskGroupId; - private String taskVersion; - private String taskExtension; - private String taskClassifier; + private String uri; + private List commandlineArguments; private Map properties; /** * Constructor for the TaskLaunchRequest; - * @param artifact is maven artifact coordinate for the task. Must not be empty nor null. - * @param taskGroupId is maven groupId coordinate for the task. Must not be empty nor null. - * @param taskVersion is maven version coordinate for the task. Must not be empty nor null. - * @param taskExtension is maven extension coordinate for the task. - * @param taskClassifier is maven classifier coordinate for the task. + * @param uri the URI to the task artifact to be launched. + * @param commandlineArguments list of commandlineArguments to be used by the task * @param properties is the environment variables for this task. */ - public TaskLaunchRequest(String artifact, String taskGroupId, String taskVersion, - String taskExtension, String taskClassifier, + public TaskLaunchRequest(String uri, List commandlineArguments, Map properties) { - Assert.hasText(artifact, "artifact must not be empty nor null."); - Assert.hasText(taskGroupId, "taskGroupID must not be empty nor null."); - Assert.hasText(taskVersion, "taskVersion must not be empty nor null."); - Assert.hasText(taskExtension, "taskExtension must not be empty nor null."); + Assert.hasText(uri, "uri must not be empty nor null."); - this.artifact = artifact; - this.taskGroupId = taskGroupId; - this.taskVersion = taskVersion; - this.taskExtension = taskExtension; - this.taskClassifier = taskClassifier; + this.uri = uri; + this.commandlineArguments = (commandlineArguments == null) ? new ArrayList() : commandlineArguments; this.properties = properties == null ? new HashMap() : properties; } /** - * Retrieves the group maven coordinate for the task. - * @return group maven coordinate for the task. + * Returns the current uri to the artifact for this launch request. */ - public String getTaskGroupId() { - return taskGroupId; + public String getUri() { + return uri; } /** - * Retrieves the version maven coordinate for the task. - * @return version maven coordinate for the task. + * Returns an unmodifiable list of parameters that will be used for the task execution */ - public String getTaskVersion() { - return taskVersion; - } - - /** - * Retrieves the extension maven coordinate for the task. - * @return extension maven coordinate for the task. - */ - public String getTaskExtension() { - return taskExtension; - } - - /** - * Retrieves the classifier maven coordinate for the task. - * @return classifier maven coordinate for the task. - */ - public String getTaskClassifier() { - return taskClassifier; - } - - /** - * Retrieves the artifact maven coordinate for the task. - * @return artifact maven coordinate for the task. - */ - public String getArtifact() { - return artifact; + public List getCommandlineArguments() { + return Collections.unmodifiableList(commandlineArguments); } /** @@ -116,12 +79,11 @@ public class TaskLaunchRequest implements Serializable{ @Override public String toString() { - String coordinates = taskGroupId + ":" + artifact + ":" + taskVersion ; - if(StringUtils.hasText(taskClassifier)){ - coordinates = coordinates + ":" + taskClassifier; - } - coordinates = coordinates + ":" + taskExtension; - return coordinates; + return "TaskLaunchRequest{" + + "uri='" + uri + '\'' + + ", commandlineArguments=" + commandlineArguments + + ", properties=" + properties + + '}'; } @Override @@ -135,19 +97,10 @@ public class TaskLaunchRequest implements Serializable{ TaskLaunchRequest that = (TaskLaunchRequest) o; - if (!artifact.equals(that.artifact)){ + if (!uri.equals(that.uri)){ return false; } - if (!taskGroupId.equals(that.taskGroupId)){ - return false; - } - if (!taskVersion.equals(that.taskVersion)){ - return false; - } - if (!taskExtension.equals(that.taskExtension)){ - return false; - } - if (taskClassifier != null ? !taskClassifier.equals(that.taskClassifier) : that.taskClassifier != null){ + if (!(commandlineArguments != null ? commandlineArguments.equals(that.commandlineArguments) : that.commandlineArguments == null)){ return false; } return properties != null ? properties.equals(that.properties) : that.properties == null; @@ -156,11 +109,8 @@ public class TaskLaunchRequest implements Serializable{ @Override public int hashCode() { - int result = artifact != null ? artifact.hashCode() : 0; - result = 31 * result + (taskGroupId != null ? taskGroupId.hashCode() : 0); - result = 31 * result + (taskVersion != null ? taskVersion.hashCode() : 0); - result = 31 * result + (taskExtension != null ? taskExtension.hashCode() : 0); - result = 31 * result + (taskClassifier != null ? taskClassifier.hashCode() : 0); + int result = uri != null ? uri.hashCode() : 0; + result = 31 * result + (commandlineArguments != null ? commandlineArguments.hashCode() : 0); result = 31 * result + (properties != null ? properties.hashCode() : 0); return result; } diff --git a/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/launcher/TaskLauncherConfiguration.java b/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/launcher/TaskLauncherConfiguration.java index df96aa33..350fc8c2 100644 --- a/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/launcher/TaskLauncherConfiguration.java +++ b/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/launcher/TaskLauncherConfiguration.java @@ -16,13 +16,21 @@ package org.springframework.cloud.task.launcher; +import java.util.HashMap; +import java.util.Map; + import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.deployer.resource.maven.MavenProperties; +import org.springframework.cloud.deployer.resource.maven.MavenResourceLoader; +import org.springframework.cloud.deployer.resource.support.DelegatingResourceLoader; import org.springframework.cloud.deployer.spi.local.LocalDeployerProperties; import org.springframework.cloud.deployer.spi.local.LocalTaskLauncher; import org.springframework.cloud.deployer.spi.task.TaskLauncher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.ResourceLoader; /** * Creates the appropriate Task Launcher Configuration based on the TaskLauncher @@ -44,4 +52,25 @@ public class TaskLauncherConfiguration { } } + @Bean + public MavenResourceLoader mavenResourceLoader(MavenProperties properties) { + return new MavenResourceLoader(properties); + } + + @Bean + @ConditionalOnMissingBean(DelegatingResourceLoader.class) + public DelegatingResourceLoader delegatingResourceLoader(MavenResourceLoader mavenResourceLoader) { + Map loaders = new HashMap<>(); + loaders.put("maven", mavenResourceLoader); + return new DelegatingResourceLoader(loaders); + } + + @Bean + public MavenProperties mavenProperties() { + return new MavenConfigurationProperties(); + } + + @ConfigurationProperties(prefix = "maven") + static class MavenConfigurationProperties extends MavenProperties { + } } diff --git a/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/launcher/TaskLauncherSink.java b/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/launcher/TaskLauncherSink.java index 2c0f1f74..6a097eaa 100644 --- a/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/launcher/TaskLauncherSink.java +++ b/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/launcher/TaskLauncherSink.java @@ -19,15 +19,17 @@ package org.springframework.cloud.task.launcher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cloud.deployer.resource.maven.MavenResource; +import org.springframework.cloud.deployer.resource.support.DelegatingResourceLoader; import org.springframework.cloud.deployer.spi.core.AppDefinition; import org.springframework.cloud.deployer.spi.core.AppDeploymentRequest; import org.springframework.cloud.deployer.spi.task.TaskLauncher; import org.springframework.cloud.stream.annotation.EnableBinding; import org.springframework.cloud.stream.messaging.Sink; +import org.springframework.core.io.Resource; import org.springframework.integration.annotation.ServiceActivator; import org.springframework.util.Assert; + /** * A sink stream application that launches a tasks. * @@ -42,6 +44,9 @@ public class TaskLauncherSink { @Autowired public TaskLauncher taskLauncher; + @Autowired + private DelegatingResourceLoader delegatingResourceLoader; + /** * Launches a task upon the receipt of a valid TaskLaunchRequest. * @param request is a TaskLaunchRequest containing the information required to launch @@ -55,15 +60,9 @@ public class TaskLauncherSink { private void launchTask(TaskLaunchRequest taskLaunchRequest) { Assert.notNull(taskLauncher, "TaskLauncher has not been initialized"); logger.info("Launching Task for the following resource " + taskLaunchRequest); - MavenResource resource = new MavenResource.Builder() - .artifactId(taskLaunchRequest.getArtifact()) - .groupId(taskLaunchRequest.getTaskGroupId()) - .version(taskLaunchRequest.getTaskVersion()) - .extension(taskLaunchRequest.getTaskExtension()) - .classifier(taskLaunchRequest.getTaskClassifier()) - .build(); - AppDefinition definition = new AppDefinition(taskLaunchRequest.getArtifact(), taskLaunchRequest.getProperties()); - AppDeploymentRequest request = new AppDeploymentRequest(definition, resource); + Resource resource = delegatingResourceLoader.getResource(taskLaunchRequest.getUri()); + AppDefinition definition = new AppDefinition("Task-" + taskLaunchRequest.hashCode(), taskLaunchRequest.getProperties()); + AppDeploymentRequest request = new AppDeploymentRequest(definition, resource, null, taskLaunchRequest.getCommandlineArguments()); taskLauncher.launch(request); } diff --git a/spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/launcher/TaskLauncherSinkTests.java b/spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/launcher/TaskLauncherSinkTests.java index aa1fdf17..804b6d04 100644 --- a/spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/launcher/TaskLauncherSinkTests.java +++ b/spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/launcher/TaskLauncherSinkTests.java @@ -16,9 +16,12 @@ package org.springframework.cloud.task.launcher; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; +import org.junit.Before; import org.junit.ClassRule; import org.junit.Test; import org.junit.runner.RunWith; @@ -41,6 +44,12 @@ import static org.junit.Assert.assertEquals; @SpringApplicationConfiguration(classes = {TaskLauncherSinkApplication.class, TaskConfiguration.class} ) public class TaskLauncherSinkTests { + private final static String PARAM1 = "FOO"; + + private final static String PARAM2 = "BAR"; + + private Map properties; + @ClassRule public static RabbitTestSupport rabbitTestSupport = new RabbitTestSupport(); @@ -53,19 +62,32 @@ public class TaskLauncherSinkTests { @Bindings(TaskLauncherSink.class) private Sink sink; - @Test - public void testSuccess() { - TaskConfiguration.TestTaskLauncher testTaskLauncher = - context.getBean(TaskConfiguration.TestTaskLauncher.class); - - Map properties = new HashMap<>(); + @Before + public void setup() { + properties = new HashMap<>(); properties.put("server.port", "0"); - TaskLaunchRequest request = new TaskLaunchRequest("timestamp-task", - "org.springframework.cloud.task.module","1.0.0.BUILD-SNAPSHOT", "jar", - "exec", properties); - GenericMessage message = new GenericMessage<>(request); - this.sink.input().send(message); + } + + @Test + public void testSuccessWithParams() { + + List commandLineArgs = new ArrayList<>(); + commandLineArgs.add(PARAM1); + commandLineArgs.add(PARAM2); + + TaskConfiguration.TestTaskLauncher testTaskLauncher = launchTask(commandLineArgs); + assertEquals(LaunchState.complete, testTaskLauncher.status(DEFAULT_STATUS).getState()); + assertEquals(2, testTaskLauncher.getCommandlineArguments().size()); + assertEquals(testTaskLauncher.getCommandlineArguments().get(0), PARAM1); + assertEquals(testTaskLauncher.getCommandlineArguments().get(1), PARAM2); + } + + @Test + public void testSuccessNoParams() { + TaskConfiguration.TestTaskLauncher testTaskLauncher= launchTask(null); + assertEquals(LaunchState.complete, testTaskLauncher.status(DEFAULT_STATUS).getState()); + assertEquals(0, testTaskLauncher.getCommandlineArguments().size()); } @Test @@ -78,11 +100,19 @@ public class TaskLauncherSinkTests { @Test(expected = IllegalArgumentException.class) public void testNoTaskLauncher() { - Map properties = new HashMap<>(); - properties.put("server.port", "0"); TaskLauncherSink sink = new TaskLauncherSink(); - sink.taskLauncherSink(new TaskLaunchRequest("timestamp-task", - "org.springframework.cloud.task.module","1.0.0.BUILD-SNAPSHOT", "jar", - "exec", properties)); + sink.taskLauncherSink(new TaskLaunchRequest("maven://org.springframework.cloud.task.app:" + + "timestamp-task:jar:1.0.0.BUILD-SNAPSHOT",null, properties)); + } + + private TaskConfiguration.TestTaskLauncher launchTask(List commandLineArgs) { + TaskConfiguration.TestTaskLauncher testTaskLauncher = + context.getBean(TaskConfiguration.TestTaskLauncher.class); + + TaskLaunchRequest request = new TaskLaunchRequest("maven://org.springframework.cloud.task.app:" + + "timestamp-task:jar:1.0.0.BUILD-SNAPSHOT",commandLineArgs, properties); + GenericMessage message = new GenericMessage<>(request); + this.sink.input().send(message); + return testTaskLauncher; } } diff --git a/spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/launcher/configuration/TaskConfiguration.java b/spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/launcher/configuration/TaskConfiguration.java index 00848056..df50d9a8 100644 --- a/spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/launcher/configuration/TaskConfiguration.java +++ b/spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/launcher/configuration/TaskConfiguration.java @@ -16,6 +16,8 @@ package org.springframework.cloud.task.launcher.configuration; +import java.util.List; + import org.springframework.cloud.deployer.spi.core.AppDeploymentRequest; import org.springframework.cloud.deployer.spi.task.LaunchState; import org.springframework.cloud.deployer.spi.task.TaskLauncher; @@ -41,9 +43,12 @@ public class TaskConfiguration { private LaunchState state = LaunchState.unknown; + private List commandlineArguments; + @Override public String launch(AppDeploymentRequest request) { state = LaunchState.complete; + this.commandlineArguments = request.getCommandlineArguments(); return null; } @@ -56,5 +61,9 @@ public class TaskConfiguration { public TaskStatus status(String id) { return new TaskStatus(LAUNCH_ID, state, null); } + + public List getCommandlineArguments() { + return commandlineArguments; + } } }