diff --git a/build.gradle b/build.gradle index 087cebc79..e2cd4cec4 100644 --- a/build.gradle +++ b/build.gradle @@ -872,6 +872,7 @@ project('spring-xd-module') { compile "org.codehaus.groovy:groovy-all" compile "org.springframework.integration:spring-integration-core" compile "org.springframework.boot:spring-boot-autoconfigure" + compile "org.springframework.boot:spring-boot-configuration-metadata" compile "org.springframework.boot:spring-boot-loader" compile "com.fasterxml.jackson.core:jackson-databind" compile "org.slf4j:slf4j-api" diff --git a/dependencies.properties b/dependencies.properties index 57bccb11b..ba222b743 100644 --- a/dependencies.properties +++ b/dependencies.properties @@ -311,51 +311,52 @@ org.springframework\:spring-webmvc-portlet=4.2.0.RC2 org.springframework\:spring-websocket=4.2.0.RC2 org.springframework.amqp\:spring-amqp=1.5.0.M1 org.springframework.amqp\:spring-rabbit=1.5.0.M1 -org.springframework.batch\:spring-batch-core=3.0.4.RELEASE -org.springframework.batch\:spring-batch-infrastructure=3.0.4.RELEASE -org.springframework.batch\:spring-batch-integration=3.0.4.RELEASE -org.springframework.batch\:spring-batch-test=3.0.4.RELEASE -org.springframework.boot\:spring-boot=1.2.3.RELEASE -org.springframework.boot\:spring-boot-actuator=1.2.3.RELEASE -org.springframework.boot\:spring-boot-autoconfigure=1.2.3.RELEASE -org.springframework.boot\:spring-boot-dependency-tools=1.2.3.RELEASE -org.springframework.boot\:spring-boot-gradle-plugin=1.2.3.RELEASE -org.springframework.boot\:spring-boot-loader=1.2.3.RELEASE -org.springframework.boot\:spring-boot-loader-tools=1.2.3.RELEASE -org.springframework.boot\:spring-boot-maven-plugin=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-actuator=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-amqp=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-aop=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-batch=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-data-elasticsearch=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-data-gemfire=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-data-jpa=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-data-mongodb=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-data-rest=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-data-solr=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-freemarker=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-groovy-templates=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-hornetq=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-integration=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-jdbc=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-jetty=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-log4j=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-logging=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-mobile=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-redis=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-remote-shell=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-security=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-social-facebook=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-social-linkedin=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-social-twitter=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-test=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-thymeleaf=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-tomcat=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-velocity=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-web=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-websocket=1.2.3.RELEASE -org.springframework.boot\:spring-boot-starter-ws=1.2.3.RELEASE +org.springframework.batch\:spring-batch-core=3.1.0.BUILD-SNAPSHOT +org.springframework.batch\:spring-batch-infrastructure=3.1.0.BUILD-SNAPSHOT +org.springframework.batch\:spring-batch-integration=3.1.0.BUILD-SNAPSHOT +org.springframework.batch\:spring-batch-test=3.1.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-actuator=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-autoconfigure=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-configuration-metadata=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-dependency-tools=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-gradle-plugin=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-loader=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-loader-tools=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-maven-plugin=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-actuator=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-amqp=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-aop=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-batch=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-data-elasticsearch=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-data-gemfire=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-data-jpa=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-data-mongodb=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-data-rest=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-data-solr=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-freemarker=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-groovy-templates=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-hornetq=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-integration=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-jdbc=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-jetty=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-log4j=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-logging=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-mobile=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-redis=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-remote-shell=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-security=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-social-facebook=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-social-linkedin=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-social-twitter=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-test=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-thymeleaf=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-tomcat=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-velocity=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-web=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-websocket=1.3.0.BUILD-SNAPSHOT +org.springframework.boot\:spring-boot-starter-ws=1.3.0.BUILD-SNAPSHOT org.springframework.build.gradle\:propdeps-plugin=0.0.7 org.springframework.cloud\:spring-cloud-cloudfoundry-connector=1.1.1.RELEASE org.springframework.cloud\:spring-cloud-core=1.1.1.RELEASE diff --git a/spring-xd-dirt/src/main/java/org/springframework/xd/dirt/server/ParentConfiguration.java b/spring-xd-dirt/src/main/java/org/springframework/xd/dirt/server/ParentConfiguration.java index e09ee78c7..799489bec 100644 --- a/spring-xd-dirt/src/main/java/org/springframework/xd/dirt/server/ParentConfiguration.java +++ b/spring-xd-dirt/src/main/java/org/springframework/xd/dirt/server/ParentConfiguration.java @@ -16,12 +16,19 @@ package org.springframework.xd.dirt.server; + +import javax.annotation.PostConstruct; + import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.actuate.autoconfigure.AuditAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.HealthIndicatorAutoConfiguration; import org.springframework.boot.actuate.health.ApplicationHealthIndicator; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration; import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; @@ -31,6 +38,9 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ImportResource; import org.springframework.jmx.support.MBeanServerFactoryBean; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.xd.dirt.util.ConfigLocations; /** @@ -63,4 +73,25 @@ public ApplicationHealthIndicator healthIndicator() { return new ApplicationHealthIndicator(); } + /** + * Create a dedicated thread pool for "framework" tasks. + */ + @Bean + @Qualifier("framework") + public TaskScheduler frameworkTaskScheduler() { + return new ThreadPoolTaskScheduler(); + } + + @Autowired + private ScheduledAnnotationBeanPostProcessor postProcessor; + + @Autowired + @Qualifier("framework") + private TaskScheduler frameworkTaskScheduler; + + @PostConstruct + public void forceScheduledTaskExecutor() { + postProcessor.setScheduler(frameworkTaskScheduler); + } + } diff --git a/spring-xd-dirt/src/main/java/org/springframework/xd/dirt/server/admin/AdminServerApplication.java b/spring-xd-dirt/src/main/java/org/springframework/xd/dirt/server/admin/AdminServerApplication.java index 239d55b70..45db85b33 100644 --- a/spring-xd-dirt/src/main/java/org/springframework/xd/dirt/server/admin/AdminServerApplication.java +++ b/spring-xd-dirt/src/main/java/org/springframework/xd/dirt/server/admin/AdminServerApplication.java @@ -19,12 +19,15 @@ import java.io.IOException; import java.net.ServerSocket; +import javax.annotation.PostConstruct; import javax.servlet.Filter; import org.apache.commons.lang.exception.ExceptionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.actuate.autoconfigure.AuditAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration; @@ -46,6 +49,8 @@ import org.springframework.context.annotation.Import; import org.springframework.context.annotation.ImportResource; import org.springframework.context.event.SourceFilteringListener; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor; import org.springframework.web.filter.HttpPutFormContentFilter; import org.springframework.xd.batch.XdBatchDatabaseInitializer; import org.springframework.xd.dirt.rest.RestConfiguration; @@ -189,4 +194,18 @@ public ApplicationListener xdInitializer(ApplicationContext context) { public BatchDatabaseInitializer batchDatabaseInitializer() { return new XdBatchDatabaseInitializer(); } + + + @Autowired + private ScheduledAnnotationBeanPostProcessor postProcessor; + + @Autowired + @Qualifier("framework") + private TaskScheduler frameworkTaskScheduler; + + @PostConstruct + public void forceScheduledTaskExecutor() { + postProcessor.setScheduler(frameworkTaskScheduler); + } + } diff --git a/spring-xd-dirt/src/main/java/org/springframework/xd/dirt/server/container/ContainerConfiguration.java b/spring-xd-dirt/src/main/java/org/springframework/xd/dirt/server/container/ContainerConfiguration.java index 46d6d57e8..a86ef07b9 100644 --- a/spring-xd-dirt/src/main/java/org/springframework/xd/dirt/server/container/ContainerConfiguration.java +++ b/spring-xd-dirt/src/main/java/org/springframework/xd/dirt/server/container/ContainerConfiguration.java @@ -16,7 +16,10 @@ package org.springframework.xd.dirt.server.container; +import javax.annotation.PostConstruct; + import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.actuate.autoconfigure.AuditAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration; @@ -28,6 +31,8 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.SourceFilteringListener; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor; import org.springframework.xd.dirt.cluster.ContainerAttributes; import org.springframework.xd.dirt.container.store.ContainerRepository; import org.springframework.xd.dirt.job.JobFactory; @@ -131,4 +136,18 @@ private void initializeZooKeeperConnection() { } } + + @Autowired + private ScheduledAnnotationBeanPostProcessor postProcessor; + + @Autowired + @Qualifier("framework") + private TaskScheduler frameworkTaskScheduler; + + @PostConstruct + public void forceScheduledTaskExecutor() { + postProcessor.setScheduler(frameworkTaskScheduler); + } + + } diff --git a/spring-xd-dirt/src/main/resources/META-INF/spring-xd/internal/repositories.xml b/spring-xd-dirt/src/main/resources/META-INF/spring-xd/internal/repositories.xml index d9b4b99bd..ec36e0e8c 100644 --- a/spring-xd-dirt/src/main/resources/META-INF/spring-xd/internal/repositories.xml +++ b/spring-xd-dirt/src/main/resources/META-INF/spring-xd/internal/repositories.xml @@ -40,6 +40,7 @@ explicitly set as a module option. + diff --git a/spring-xd-module/src/main/java/org/springframework/xd/module/core/SimpleModule.java b/spring-xd-module/src/main/java/org/springframework/xd/module/core/SimpleModule.java index cd46c43da..5a0319cc2 100644 --- a/spring-xd-module/src/main/java/org/springframework/xd/module/core/SimpleModule.java +++ b/spring-xd-module/src/main/java/org/springframework/xd/module/core/SimpleModule.java @@ -50,6 +50,7 @@ import org.springframework.xd.module.ModuleDescriptor; import org.springframework.xd.module.SimpleModuleDefinition; import org.springframework.xd.module.options.ModuleOptions; +import org.springframework.xd.module.options.ModuleUtils; import org.springframework.xd.module.options.PassthruModuleOptionsMetadata; /** @@ -263,13 +264,7 @@ public void destroy() { throw new IllegalStateException(e); } } - if (classLoader instanceof Closeable) { - try { - ((Closeable) classLoader).close(); - } - catch (IOException e) { - } - } + ModuleUtils.closeClassLoader(classLoader); } private static ModuleOptions defaultModuleOptions() { diff --git a/spring-xd-module/src/main/java/org/springframework/xd/module/options/BootModuleOptionsMetadataResolver.java b/spring-xd-module/src/main/java/org/springframework/xd/module/options/BootModuleOptionsMetadataResolver.java new file mode 100644 index 000000000..352b773a0 --- /dev/null +++ b/spring-xd-module/src/main/java/org/springframework/xd/module/options/BootModuleOptionsMetadataResolver.java @@ -0,0 +1,96 @@ +/* + * 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.xd.module.options; + +import java.io.IOException; +import java.util.Map; + +import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty; +import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepository; +import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepositoryJsonBuilder; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.xd.module.ModuleDefinition; +import org.springframework.xd.module.SimpleModuleDefinition; + +/** + * A ModuleOptionsMetadataResolver that knows how to read Spring Boot metadata for configuration properties + * and exposes some of the properties as module options. + * + * @author Eric Bottard + */ +public class BootModuleOptionsMetadataResolver implements ModuleOptionsMetadataResolver { + + + private ResourcePatternResolver resourceLoader = new PathMatchingResourcePatternResolver(); + + /** + * The prefix with which configuration options must start to be considered module options. + * + *

The prefix-less form will be used for module options, while at runtime, + * the module may expect the long form.

+ */ + private String prefix = "module."; + + + @Override + public ModuleOptionsMetadata resolve(ModuleDefinition moduleDefinition) { + if (moduleDefinition.isComposed()) { + return null; + } + SimpleModuleDefinition simpleModuleDefinition = (SimpleModuleDefinition) moduleDefinition; + Resource resource = resourceLoader.getResource(simpleModuleDefinition.getLocation()); + ClassLoader moduleClassLoader = ModuleUtils.createModuleDiscoveryClassLoader(resource, BootModuleOptionsMetadataResolver.class.getClassLoader()); + + ResourcePatternResolver moduleResourceLoader = new PathMatchingResourcePatternResolver(moduleClassLoader); + + ConfigurationMetadataRepositoryJsonBuilder builder = ConfigurationMetadataRepositoryJsonBuilder.create(); + + try { + for (Resource r : moduleResourceLoader.getResources("classpath*:/META-INF/*spring-configuration-metadata.json")) { + builder.withJsonResource(r.getInputStream()); + } + } + catch (IOException e) { + throw new RuntimeException(e); + } + ModuleUtils.closeClassLoader(moduleClassLoader); + + ConfigurationMetadataRepository repo = builder.build(); + SimpleModuleOptionsMetadata result = new SimpleModuleOptionsMetadata(); + + for (Map.Entry kv : repo.getAllProperties().entrySet()) { + String key = kv.getKey(); + if (!key.startsWith(prefix)) { + continue; + } + ConfigurationMetadataProperty value = kv.getValue(); + ModuleOption mo = new ModuleOption(key.substring(prefix.length()), value.getDescription()) + .withDefaultValue(value.getDefaultValue()) + .withType(value.getType()); + result.add(mo); + + } + + return result; + } + + +} diff --git a/spring-xd-module/src/main/java/org/springframework/xd/module/options/DefaultModuleOptionsMetadataResolver.java b/spring-xd-module/src/main/java/org/springframework/xd/module/options/DefaultModuleOptionsMetadataResolver.java index a4cc0f6be..79efb2fcc 100644 --- a/spring-xd-module/src/main/java/org/springframework/xd/module/options/DefaultModuleOptionsMetadataResolver.java +++ b/spring-xd-module/src/main/java/org/springframework/xd/module/options/DefaultModuleOptionsMetadataResolver.java @@ -16,6 +16,7 @@ package org.springframework.xd.module.options; +import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; diff --git a/spring-xd-module/src/main/java/org/springframework/xd/module/options/ModuleUtils.java b/spring-xd-module/src/main/java/org/springframework/xd/module/options/ModuleUtils.java index 2490aec93..3852fa6c1 100644 --- a/spring-xd-module/src/main/java/org/springframework/xd/module/options/ModuleUtils.java +++ b/spring-xd-module/src/main/java/org/springframework/xd/module/options/ModuleUtils.java @@ -15,6 +15,7 @@ package org.springframework.xd.module.options; +import java.io.Closeable; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -97,6 +98,21 @@ public static ClassLoader createModuleDiscoveryClassLoader(Resource moduleLocati return createModuleClassLoader(moduleLocation, parent, DEFAULT_EXTRA_LIBS); } + /** + * Close the given classloader if it is actually {@link Closeable}. Does nothing otherwise. + */ + public static void closeClassLoader(ClassLoader classLoader) { + if (classLoader instanceof Closeable) { + Closeable loader = (Closeable) classLoader; + try { + loader.close(); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + } + private static ClassLoader createModuleClassLoader(Resource moduleLocation, ClassLoader parent, Iterable patterns) {