Repository: camel Updated Branches: refs/heads/camel-2.18.x 1a2874674 -> 82ba1b804
CAMEL-10550: spring-boot: add a global option to disable data-format, languages and component auto configurations (cherry picked from commit 21b0fe2cf5602894f254d788de6d6e4755163c8a) Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/2d902abd Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/2d902abd Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/2d902abd Branch: refs/heads/camel-2.18.x Commit: 2d902abd200ab86ee268337c772dc0e6e2a4ee3a Parents: 1a28746 Author: lburgazzoli <[email protected]> Authored: Tue Dec 6 14:31:53 2016 +0100 Committer: lburgazzoli <[email protected]> Committed: Tue Dec 6 14:31:53 2016 +0100 ---------------------------------------------------------------------- .../boot/ComponentConfigurationProperties.java | 33 ++++ .../boot/DataFormatConfigurationProperties.java | 33 ++++ .../boot/LanguageConfigurationProperties.java | 33 ++++ spring-boot-dm/pom.xml | 2 +- .../maven/camel-package-maven-plugin/pom.xml | 6 + .../SpringBootAutoConfigurationMojo.java | 161 +++++++++++++++++-- 6 files changed, 255 insertions(+), 13 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/2d902abd/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/ComponentConfigurationProperties.java ---------------------------------------------------------------------- diff --git a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/ComponentConfigurationProperties.java b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/ComponentConfigurationProperties.java new file mode 100644 index 0000000..804dc45 --- /dev/null +++ b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/ComponentConfigurationProperties.java @@ -0,0 +1,33 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.camel.spring.boot; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties(prefix = "camel.component") +public class ComponentConfigurationProperties { + private boolean enabled = true; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/2d902abd/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/DataFormatConfigurationProperties.java ---------------------------------------------------------------------- diff --git a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/DataFormatConfigurationProperties.java b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/DataFormatConfigurationProperties.java new file mode 100644 index 0000000..5c0e3d8 --- /dev/null +++ b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/DataFormatConfigurationProperties.java @@ -0,0 +1,33 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.camel.spring.boot; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties(prefix = "camel.dataformat") +public class DataFormatConfigurationProperties { + private boolean enabled = true; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/2d902abd/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/LanguageConfigurationProperties.java ---------------------------------------------------------------------- diff --git a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/LanguageConfigurationProperties.java b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/LanguageConfigurationProperties.java new file mode 100644 index 0000000..d577a3a --- /dev/null +++ b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/LanguageConfigurationProperties.java @@ -0,0 +1,33 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.camel.spring.boot; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties(prefix = "camel.language") +public class LanguageConfigurationProperties { + private boolean enabled = true; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/2d902abd/spring-boot-dm/pom.xml ---------------------------------------------------------------------- diff --git a/spring-boot-dm/pom.xml b/spring-boot-dm/pom.xml index c60b213..eae9dd8 100644 --- a/spring-boot-dm/pom.xml +++ b/spring-boot-dm/pom.xml @@ -36,7 +36,7 @@ <properties> <!-- Spring-Boot target version --> - <spring-boot-version>1.4.1.RELEASE</spring-boot-version> + <spring-boot-version>1.4.2.RELEASE</spring-boot-version> <!-- The following dependencies should be aligned with the ones in standard camel parent --> <avro-version>1.8.1</avro-version> http://git-wip-us.apache.org/repos/asf/camel/blob/2d902abd/tooling/maven/camel-package-maven-plugin/pom.xml ---------------------------------------------------------------------- diff --git a/tooling/maven/camel-package-maven-plugin/pom.xml b/tooling/maven/camel-package-maven-plugin/pom.xml index af3f163..fcccb424 100644 --- a/tooling/maven/camel-package-maven-plugin/pom.xml +++ b/tooling/maven/camel-package-maven-plugin/pom.xml @@ -91,6 +91,12 @@ <artifactId>commons-io</artifactId> </dependency> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <version>${gson-version}</version> + </dependency> + <!-- roaster to create java source for Spring Boot auto configuration support --> <dependency> <groupId>org.jboss.forge.roaster</groupId> http://git-wip-us.apache.org/repos/asf/camel/blob/2d902abd/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SpringBootAutoConfigurationMojo.java ---------------------------------------------------------------------- diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SpringBootAutoConfigurationMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SpringBootAutoConfigurationMojo.java index 65e14c0..19e3375 100644 --- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SpringBootAutoConfigurationMojo.java +++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/SpringBootAutoConfigurationMojo.java @@ -16,9 +16,11 @@ */ package org.apache.camel.maven.packaging; +import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Modifier; @@ -39,6 +41,8 @@ import java.util.TreeSet; import java.util.regex.Pattern; import java.util.stream.Collectors; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import org.apache.camel.maven.packaging.model.ComponentModel; import org.apache.camel.maven.packaging.model.ComponentOptionModel; import org.apache.camel.maven.packaging.model.DataFormatModel; @@ -63,13 +67,22 @@ import org.jboss.forge.roaster.model.source.JavaClassSource; import org.jboss.forge.roaster.model.source.MethodSource; import org.jboss.forge.roaster.model.source.PropertySource; import org.jboss.forge.roaster.model.util.Strings; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionMessage; +import org.springframework.boot.autoconfigure.condition.ConditionOutcome; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.SpringBootCondition; +import org.springframework.boot.bind.RelaxedPropertyResolver; import org.springframework.boot.context.properties.DeprecatedConfigurationProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.NestedConfigurationProperty; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; +import org.springframework.core.type.AnnotatedTypeMetadata; import static org.apache.camel.maven.packaging.JSonSchemaHelper.getSafeValue; import static org.apache.camel.maven.packaging.PackageHelper.loadText; @@ -196,7 +209,7 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo { } createComponentConfigurationSource(pkg, model, overrideComponentName); - createComponentAutoConfigurationSource(pkg, model, aliases); + createComponentAutoConfigurationSource(pkg, model, aliases, overrideComponentName); createComponentSpringFactorySource(pkg, model); } } @@ -246,7 +259,7 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo { } createDataFormatConfigurationSource(pkg, model, overrideDataformatName); - createDataFormatAutoConfigurationSource(pkg, model, aliases); + createDataFormatAutoConfigurationSource(pkg, model, aliases, overrideDataformatName); createDataFormatSpringFactorySource(pkg, model); } } @@ -296,7 +309,7 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo { } createLanguageConfigurationSource(pkg, model, overrideLanguageName); - createLanguageAutoConfigurationSource(pkg, model, aliases); + createLanguageAutoConfigurationSource(pkg, model, aliases, overrideLanguageName); createLanguageSpringFactorySource(pkg, model); } } @@ -754,12 +767,13 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo { writeSourceIfChanged(javaClass, fileName); } - private void createComponentAutoConfigurationSource(String packageName, ComponentModel model, List<String> componentAliases) throws MojoFailureException { + private void createComponentAutoConfigurationSource(String packageName, ComponentModel model, List<String> componentAliases, String overrideComponentName) throws MojoFailureException { final JavaClassSource javaClass = Roaster.create(JavaClassSource.class); int pos = model.getJavaType().lastIndexOf("."); String name = model.getJavaType().substring(pos + 1); name = name.replace("Component", "ComponentAutoConfiguration"); + javaClass.setPackage(packageName).setName(name); String doc = "Generated by camel-package-maven-plugin - do not edit this file!"; @@ -770,6 +784,7 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo { String configurationName = name.replace("ComponentAutoConfiguration", "ComponentConfiguration"); AnnotationSource<JavaClassSource> ann = javaClass.addAnnotation(EnableConfigurationProperties.class); ann.setLiteralValue("value", configurationName + ".class"); + javaClass.addAnnotation(Conditional.class).setLiteralValue(name + ".Condition.class"); // add method for auto configure @@ -799,19 +814,30 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo { method.addAnnotation(ConditionalOnClass.class).setLiteralValue("value", "CamelContext.class"); method.addAnnotation(ConditionalOnMissingBean.class).setLiteralValue("value", model.getShortJavaType() + ".class"); + // Generate Condition + javaClass.addNestedType(createConditionType( + javaClass, + "camel.component", + (overrideComponentName != null ? overrideComponentName : model.getScheme()).toLowerCase(Locale.US) + )); + sortImports(javaClass); String fileName = packageName.replaceAll("\\.", "\\/") + "/" + name + ".java"; - writeSourceIfChanged(javaClass, fileName); + writeAdditionalSpringMetaData( + "camel", + "component", + (overrideComponentName != null ? overrideComponentName : model.getScheme()).toLowerCase(Locale.US)); } - private void createDataFormatAutoConfigurationSource(String packageName, DataFormatModel model, List<String> dataFormatAliases) throws MojoFailureException { + private void createDataFormatAutoConfigurationSource(String packageName, DataFormatModel model, List<String> dataFormatAliases, String overrideDataFormatName) throws MojoFailureException { final JavaClassSource javaClass = Roaster.create(JavaClassSource.class); int pos = model.getJavaType().lastIndexOf("."); String name = model.getJavaType().substring(pos + 1); - name = name.replace("DataFormat", "DataFormatAutoConfiguration"); + name = name.replace("DataFormat", "DataFormatAutoConfiguration"); + javaClass.setPackage(packageName).setName(name); String doc = "Generated by camel-package-maven-plugin - do not edit this file!"; @@ -822,6 +848,8 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo { String configurationName = name.replace("DataFormatAutoConfiguration", "DataFormatConfiguration"); AnnotationSource<JavaClassSource> ann = javaClass.addAnnotation(EnableConfigurationProperties.class); ann.setLiteralValue("value", configurationName + ".class"); + + javaClass.addAnnotation(Conditional.class).setLiteralValue(name + ".Condition.class"); // add method for auto configure @@ -845,7 +873,6 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo { method.addParameter("CamelContext", "camelContext"); method.addParameter(configurationName, "configuration"); - // Determine all the aliases // adding the '-dataformat' suffix to prevent collision with component names String[] springBeanAliases = dataFormatAliases.stream().map(alias -> alias + "-dataformat").toArray(size -> new String[size]); @@ -854,19 +881,30 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo { method.addAnnotation(ConditionalOnClass.class).setLiteralValue("value", "CamelContext.class"); method.addAnnotation(ConditionalOnMissingBean.class).setLiteralValue("value", model.getShortJavaType() + ".class"); + // Generate Condition + javaClass.addNestedType(createConditionType( + javaClass, + "camel.dataformat", + (overrideDataFormatName != null ? overrideDataFormatName : model.getName()).toLowerCase(Locale.US) + )); + sortImports(javaClass); String fileName = packageName.replaceAll("\\.", "\\/") + "/" + name + ".java"; - writeSourceIfChanged(javaClass, fileName); + writeAdditionalSpringMetaData( + "camel", + "dataformat", + (overrideDataFormatName != null ? overrideDataFormatName : model.getName()).toLowerCase(Locale.US)); } - private void createLanguageAutoConfigurationSource(String packageName, LanguageModel model, List<String> languageAliases) throws MojoFailureException { + private void createLanguageAutoConfigurationSource(String packageName, LanguageModel model, List<String> languageAliases, String overrideLanguageName) throws MojoFailureException { final JavaClassSource javaClass = Roaster.create(JavaClassSource.class); int pos = model.getJavaType().lastIndexOf("."); String name = model.getJavaType().substring(pos + 1); name = name.replace("Language", "LanguageAutoConfiguration"); + javaClass.setPackage(packageName).setName(name); String doc = "Generated by camel-package-maven-plugin - do not edit this file!"; @@ -877,6 +915,7 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo { String configurationName = name.replace("LanguageAutoConfiguration", "LanguageConfiguration"); AnnotationSource<JavaClassSource> ann = javaClass.addAnnotation(EnableConfigurationProperties.class); ann.setLiteralValue("value", configurationName + ".class"); + javaClass.addAnnotation(Conditional.class).setLiteralValue(name + ".Condition.class"); // add method for auto configure @@ -900,7 +939,6 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo { method.addParameter("CamelContext", "camelContext"); method.addParameter(configurationName, "configuration"); - // Determine all the aliases // adding the '-language' suffix to prevent collision with component names String[] springBeanAliases = languageAliases.stream().map(alias -> alias + "-language").toArray(size -> new String[size]); @@ -909,11 +947,21 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo { method.addAnnotation(ConditionalOnClass.class).setLiteralValue("value", "CamelContext.class"); method.addAnnotation(ConditionalOnMissingBean.class).setLiteralValue("value", model.getShortJavaType() + ".class"); + // Generate Condition + javaClass.addNestedType(createConditionType( + javaClass, + "camel.language", + (overrideLanguageName != null ? overrideLanguageName : model.getName()).toLowerCase(Locale.US) + )); + sortImports(javaClass); String fileName = packageName.replaceAll("\\.", "\\/") + "/" + name + ".java"; - writeSourceIfChanged(javaClass, fileName); + writeAdditionalSpringMetaData( + "camel", + "language", + (overrideLanguageName != null ? overrideLanguageName : model.getName()).toLowerCase(Locale.US)); } private void createComponentSpringFactorySource(String packageName, ComponentModel model) throws MojoFailureException { @@ -1409,6 +1457,52 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo { } } + private void writeAdditionalSpringMetaData(String prefix, String type, String name) throws MojoFailureException { + String fullQualifiedName = prefix + "." + type + "." + name + "." + "enabled"; + String fileName = "META-INF/additional-spring-configuration-metadata.json"; + File target = new File(SpringBootHelper.starterResourceDir(baseDir, project.getArtifactId()), fileName); + + deleteFileOnMainArtifact(target); + + try { + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + Map<String, Object> map = null; + List<Map<String, Object>> properties = null; + + if (target.exists()) { + BufferedReader br = new BufferedReader(new FileReader(target)); + map = gson.fromJson(br, Map.class); + + properties = (List<Map<String, Object>>)map.get("properties"); + if (properties != null && properties.stream().anyMatch(m -> fullQualifiedName.equals(m.get("name")))) { + getLog().debug("No changes to existing file: " + target); + return; + } + } + + Map<String, Object> meta = new HashMap(); + meta.put("name", fullQualifiedName); + meta.put("type", "java.lang.Boolean"); + meta.put("defaultValue", true); + meta.put("description", "Enable " + name + " " + type); + + if (properties == null) { + properties = new ArrayList<>(1); + } + + if (map == null) { + map = new HashMap(); + } + + properties.add(meta); + map.put("properties", properties); + + FileUtils.write(target, gson.toJson(map)); + } catch (Exception e) { + throw new MojoFailureException("IOError with file " + target, e); + } + } + private void deleteFileOnMainArtifact(File starterFile) { if (!DELETE_FILES_ON_MAIN_ARTIFACTS) { return; @@ -1424,4 +1518,47 @@ public class SpringBootAutoConfigurationMojo extends AbstractMojo { } } + private JavaClassSource createConditionType(JavaClassSource parentClass, String prefix, String type) { + parentClass.addImport(ConditionMessage.class); + parentClass.addImport(ConditionContext.class); + parentClass.addImport(ConditionOutcome.class); + parentClass.addImport(RelaxedPropertyResolver.class); + parentClass.addImport(AnnotatedTypeMetadata.class); + parentClass.addImport(SpringBootCondition.class); + + JavaClassSource condition = Roaster.create(JavaClassSource.class); + condition.setName("Condition"); + condition.extendSuperType(SpringBootCondition.class); + condition.setPublic(); + condition.setStatic(true); + + String fullQualifiedType = prefix.endsWith(".") ? prefix + type : prefix + "." + type; + + MethodSource<JavaClassSource> isEnabled = condition.addMethod(); + isEnabled.setName("isEnabled"); + isEnabled.setPrivate(); + isEnabled.addParameter(ConditionContext.class, "context"); + isEnabled.addParameter(String.class, "prefix"); + isEnabled.addParameter(boolean.class, "defaultValue"); + isEnabled.setReturnType(boolean.class); + isEnabled.setBody(new StringBuilder() + .append("RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(context.getEnvironment(), prefix);\n") + .append("return resolver.getProperty(\"enabled\", Boolean.class, defaultValue);") + .toString() + ); + + MethodSource<JavaClassSource> matchMethod = condition.getMethod("getMatchOutcome", ConditionContext.class, AnnotatedTypeMetadata.class); + matchMethod.setBody(new StringBuilder() + .append("boolean groupEnabled = isEnabled(conditionContext, \"").append(prefix).append(".\", true);\n") + .append("ConditionMessage.Builder message = ConditionMessage.forCondition(\"").append(fullQualifiedType).append("\");\n") + .append("if (isEnabled(conditionContext, \"").append(fullQualifiedType).append(".\", groupEnabled)) {\n") + .append(" return ConditionOutcome.match(message.because(\"enabled\"));\n") + .append("}\n") + .append("return ConditionOutcome.noMatch(message.because(\"not enabled\"));\n") + .toString() + ); + + return condition; + } + }
