| /* |
| * 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.k.tooling.maven; |
| |
| |
| import java.io.IOException; |
| import java.nio.file.Paths; |
| import java.util.Comparator; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| import javax.lang.model.element.Modifier; |
| |
| import com.fasterxml.jackson.core.Version; |
| import com.fasterxml.jackson.databind.Module; |
| import com.squareup.javapoet.ClassName; |
| import com.squareup.javapoet.CodeBlock; |
| import com.squareup.javapoet.JavaFile; |
| import com.squareup.javapoet.MethodSpec; |
| import com.squareup.javapoet.TypeSpec; |
| import org.apache.camel.catalog.CamelCatalog; |
| import org.apache.camel.catalog.DefaultCamelCatalog; |
| import org.apache.camel.k.tooling.maven.support.ToolingSupport; |
| import org.apache.camel.util.AntPathMatcher; |
| import org.apache.camel.util.StringHelper; |
| import org.apache.maven.plugin.MojoFailureException; |
| import org.apache.maven.plugins.annotations.LifecyclePhase; |
| import org.apache.maven.plugins.annotations.Mojo; |
| import org.apache.maven.plugins.annotations.Parameter; |
| import org.apache.maven.plugins.annotations.ResolutionScope; |
| import org.jboss.jandex.AnnotationInstance; |
| import org.jboss.jandex.AnnotationValue; |
| import org.jboss.jandex.ClassInfo; |
| |
| @Mojo( |
| name = "generate-yaml-loader-support-classes", |
| inheritByDefault = false, |
| defaultPhase = LifecyclePhase.GENERATE_SOURCES, |
| requiresDependencyResolution = ResolutionScope.COMPILE, |
| threadSafe = true, |
| requiresProject = false) |
| public class GenerateYamlLoaderSupportClasses extends GenerateYamlSupport { |
| @Parameter |
| protected List<String> bannedDefinitions; |
| @Parameter(defaultValue = "${project.build.directory}/generated-sources/camel") |
| protected String output; |
| |
| @Override |
| public void execute() throws MojoFailureException { |
| try { |
| JavaFile.builder("org.apache.camel.k.loader.yaml", generateJacksonModule()) |
| .indent(" ") |
| .build() |
| .writeTo(Paths.get(output)); |
| JavaFile.builder("org.apache.camel.k.loader.yaml", generateReifiers()) |
| .indent(" ") |
| .build() |
| .writeTo(Paths.get(output)); |
| JavaFile.builder("org.apache.camel.k.loader.yaml", generateResolver()) |
| .indent(" ") |
| .build() |
| .writeTo(Paths.get(output)); |
| } catch (IOException e) { |
| throw new MojoFailureException(e.getMessage(), e); |
| } |
| } |
| |
| public final TypeSpec generateJacksonModule() { |
| TypeSpec.Builder type = TypeSpec.classBuilder("YamlModule"); |
| type.addModifiers(Modifier.PUBLIC, Modifier.FINAL); |
| type.superclass(Module.class); |
| type.addMethod( |
| MethodSpec.methodBuilder("getModuleName") |
| .addModifiers(Modifier.PUBLIC) |
| .addAnnotation(Override.class) |
| .returns(String.class) |
| .addCode(CodeBlock.builder().addStatement("return $S", "camel-yaml").build()) |
| .build() |
| ); |
| type.addMethod( |
| MethodSpec.methodBuilder("version") |
| .addModifiers(Modifier.PUBLIC) |
| .addAnnotation(Override.class) |
| .returns(Version.class) |
| .addCode(CodeBlock.builder().addStatement("return $L", "Version.unknownVersion()").build()) |
| .build() |
| ); |
| |
| MethodSpec.Builder mb = MethodSpec.methodBuilder("setupModule") |
| .addModifiers(Modifier.PUBLIC) |
| .addParameter(Module.SetupContext.class, "context"); |
| |
| definitions(EXPRESSION_DEFINITION_CLASS).forEach( |
| (k, v) -> mb.addStatement("context.registerSubtypes(new com.fasterxml.jackson.databind.jsontype.NamedType($L.class, $S))", v.name().toString(), k) |
| ); |
| definitions(DATAFORMAT_DEFINITION_CLASS).forEach( |
| (k, v) -> mb.addStatement("context.registerSubtypes(new com.fasterxml.jackson.databind.jsontype.NamedType($L.class, $S))", v.name().toString(), k) |
| ); |
| definitions(LOAD_BALANCE_DEFINITION_CLASS).forEach( |
| (k, v) -> mb.addStatement("context.registerSubtypes(new com.fasterxml.jackson.databind.jsontype.NamedType($L.class, $S))", v.name().toString(), k) |
| ); |
| |
| annotated(YAML_MIXIN_ANNOTATION).forEach(i -> { |
| final AnnotationInstance annotation = i.classAnnotation(YAML_MIXIN_ANNOTATION); |
| final AnnotationValue targets = annotation.value("value"); |
| |
| String name = i.toString(); |
| if (i.nestingType() == ClassInfo.NestingType.INNER) { |
| name = i.enclosingClass().toString() + "." + i.simpleName(); |
| } |
| |
| if (targets != null) { |
| for (String target: targets.asStringArray()) { |
| mb.addStatement("context.setMixInAnnotations($L.class, $L.class);", target, name); |
| } |
| } |
| }); |
| |
| |
| type.addMethod(mb.build()); |
| |
| return type.build(); |
| } |
| |
| public final TypeSpec generateReifiers() { |
| TypeSpec.Builder type = TypeSpec.classBuilder("YamlReifiers"); |
| type.addModifiers(Modifier.PUBLIC, Modifier.FINAL); |
| |
| MethodSpec.Builder mb = MethodSpec.methodBuilder("registerReifiers") |
| .addModifiers(Modifier.PUBLIC) |
| .addModifiers(Modifier.STATIC); |
| |
| annotated(YAML_NODE_DEFINITION_ANNOTATION).forEach(i -> { |
| final AnnotationInstance annotation = i.classAnnotation(YAML_NODE_DEFINITION_ANNOTATION); |
| final AnnotationValue reifiers = annotation.value("reifiers"); |
| |
| if (reifiers != null) { |
| String name = i.toString(); |
| if (i.nestingType() == ClassInfo.NestingType.INNER) { |
| name = i.enclosingClass().toString() + "." + i.simpleName(); |
| } |
| |
| for (String reifier: reifiers.asStringArray()) { |
| mb.addStatement("org.apache.camel.reifier.ProcessorReifier.registerReifier($L.class, $L::new)", name, reifier); |
| } |
| } |
| }); |
| |
| type.addMethod(mb.build()); |
| |
| return type.build(); |
| } |
| |
| public final TypeSpec generateResolver() { |
| Set<String> ids = new HashSet<>(); |
| |
| MethodSpec.Builder mb = MethodSpec.methodBuilder("resolve") |
| .addAnnotation(Override.class) |
| .addModifiers(Modifier.PUBLIC) |
| .addParameter(ClassName.get("org.apache.camel", "CamelContext"), "camelContext") |
| .addParameter(ClassName.get("java.lang", "String"), "id") |
| .returns(ClassName.get("org.apache.camel.k.loader.yaml.spi", "StepParser")); |
| |
| mb.beginControlFlow("switch(id)"); |
| |
| mb.addComment("custom parsers"); |
| |
| annotated(YAML_STEP_PARSER_ANNOTATION) |
| .sorted(Comparator.comparing(i -> i.name().toString())) |
| .forEach( |
| i -> { |
| AnnotationValue id = i.classAnnotation(YAML_STEP_PARSER_ANNOTATION).value("id"); |
| if (id != null && ids.add(id.asString())) { |
| mb.beginControlFlow("case $S:", id.asString()); |
| mb.addStatement("return new $L()", i.name().toString()); |
| mb.endControlFlow(); |
| } |
| |
| AnnotationValue aliases = i.classAnnotation(YAML_STEP_PARSER_ANNOTATION).value("aliases"); |
| if (aliases != null) { |
| for (String alias : aliases.asStringArray()) { |
| if (ids.add(alias)) { |
| mb.beginControlFlow("case $S:", alias); |
| mb.addStatement("return new $L()", i.name().toString()); |
| mb.endControlFlow(); |
| } |
| } |
| } |
| } |
| ); |
| |
| mb.addComment("auto generated parsers"); |
| |
| annotated(XML_ROOT_ELEMENT_ANNOTATION_CLASS) |
| .forEach( |
| i -> { |
| AnnotationInstance meta = i.classAnnotation(METADATA_ANNOTATION); |
| AnnotationInstance root = i.classAnnotation(XML_ROOT_ELEMENT_ANNOTATION_CLASS); |
| |
| if (meta == null || root == null) { |
| return; |
| } |
| |
| AnnotationValue name = root.value("name"); |
| AnnotationValue label = meta.value("label"); |
| |
| if (name == null || label == null) { |
| return; |
| } |
| |
| if (bannedDefinitions != null) { |
| for (String bannedDefinition: bannedDefinitions) { |
| if (AntPathMatcher.INSTANCE.match(bannedDefinition.replace('.', '/'), i.name().toString('/'))) { |
| getLog().debug("Skipping definition: " + i.name().toString()); |
| return; |
| } |
| } |
| } |
| |
| Set<String> labels = Set.of(label.asString().split(",", -1)); |
| if (labels.contains("eip")) { |
| String id = StringHelper.camelCaseToDash(name.asString()); |
| if (ids.add(id)) { |
| mb.beginControlFlow("case $S:", id); |
| mb.addStatement("return new org.apache.camel.k.loader.yaml.parser.TypedProcessorStepParser($L.class)", i.name().toString()); |
| mb.endControlFlow(); |
| } |
| } |
| } |
| ); |
| |
| mb.addComment("endpoint dsl"); |
| |
| CamelCatalog catalog = new DefaultCamelCatalog(); |
| catalog.findComponentNames().stream() |
| .sorted() |
| .map(catalog::componentModel) |
| .flatMap(component -> ToolingSupport.combine(component.getScheme(), component.getAlternativeSchemes())) |
| .filter(ids::add) |
| .forEach(scheme -> { |
| mb.beginControlFlow("case $S:", scheme); |
| mb.addStatement("return new org.apache.camel.k.loader.yaml.parser.EndpointStepParser($S)", scheme); |
| mb.endControlFlow(); |
| }); |
| |
| mb.beginControlFlow("default:"); |
| mb.addStatement("return lookup(camelContext, id)"); |
| mb.endControlFlow(); |
| mb.endControlFlow(); |
| |
| return TypeSpec.classBuilder("YamlStepResolver") |
| .addModifiers(Modifier.PUBLIC, Modifier.FINAL) |
| .addSuperinterface(ClassName.get("org.apache.camel.k.loader.yaml.spi", "StepParser.Resolver")) |
| .addMethod(mb.build()) |
| .build(); |
| } |
| } |