This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
commit ec24d17061351141d99be99dcb4417a77b1a3fd8 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Mon Aug 12 22:08:43 2019 +0200 CAMEL-13850: Optimize model classes to provide changeable properties that support property placeholders to avoid reflection. Work in progress. --- .../model/DefinitionPropertiesProviderHelper.java | 47 ------------- .../DefinitionPropertyPlaceholderConfigurable.java | 5 +- .../apt/CoreEipAnnotationProcessorHelper.java | 77 +++++++++++++++++++--- .../camel/tools/apt/ModelAnnotationProcessor.java | 62 +++++++++++++---- .../tools/apt/SpringAnnotationProcessorHelper.java | 3 +- 5 files changed, 122 insertions(+), 72 deletions(-) diff --git a/core/camel-core/src/main/java/org/apache/camel/model/DefinitionPropertiesProviderHelper.java b/core/camel-core/src/main/java/org/apache/camel/model/DefinitionPropertiesProviderHelper.java deleted file mode 100644 index 86cb92e..0000000 --- a/core/camel-core/src/main/java/org/apache/camel/model/DefinitionPropertiesProviderHelper.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * 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 - * <p> - * http://www.apache.org/licenses/LICENSE-2.0 - * <p> - * 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.model; - -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.function.Function; - -import org.apache.camel.model.placeholder.FromDefinitionPropertyPlaceholderProvider; -import org.apache.camel.model.placeholder.LogDefinitionPropertyPlaceholderProvider; -import org.apache.camel.model.placeholder.ToDefinitionPropertyPlaceholderProvider; - -public class DefinitionPropertiesProviderHelper { - - private static final Map<Class, Function<Object, DefinitionPropertyPlaceholderConfigurable>> MAP; - static { - Map<Class, Function<Object, DefinitionPropertyPlaceholderConfigurable>> map = new HashMap<>(); - map.put(FromDefinition.class, FromDefinitionPropertyPlaceholderProvider::new); - map.put(LogDefinition.class, LogDefinitionPropertyPlaceholderProvider::new); - map.put(ToDefinition.class, ToDefinitionPropertyPlaceholderProvider::new); - MAP = map; - } - - public static Optional<DefinitionPropertyPlaceholderConfigurable> provider(Object definition) { - Function<Object, DefinitionPropertyPlaceholderConfigurable> func = MAP.get(definition.getClass()); - if (func != null) { - return Optional.of(func.apply(definition)); - } - return Optional.empty(); - } - -} diff --git a/core/camel-core/src/main/java/org/apache/camel/model/DefinitionPropertyPlaceholderConfigurable.java b/core/camel-core/src/main/java/org/apache/camel/model/DefinitionPropertyPlaceholderConfigurable.java index 9c82f6b..8d5758c 100644 --- a/core/camel-core/src/main/java/org/apache/camel/model/DefinitionPropertyPlaceholderConfigurable.java +++ b/core/camel-core/src/main/java/org/apache/camel/model/DefinitionPropertyPlaceholderConfigurable.java @@ -21,6 +21,7 @@ import java.util.function.Consumer; import java.util.function.Supplier; import org.apache.camel.CamelContext; +import org.apache.camel.model.placeholder.DefinitionPropertiesPlaceholderProviderHelper; /** * To be used for configuring property placeholder options on the EIP models. @@ -34,7 +35,7 @@ public interface DefinitionPropertyPlaceholderConfigurable { * @return key/values of options */ default Map<String, Supplier<String>> getReadPropertyPlaceholderOptions(CamelContext camelContext) { - DefinitionPropertyPlaceholderConfigurable aware = DefinitionPropertiesProviderHelper.provider(this).orElse(null); + DefinitionPropertyPlaceholderConfigurable aware = DefinitionPropertiesPlaceholderProviderHelper.provider(this).orElse(null); return aware != null ? aware.getReadPropertyPlaceholderOptions(camelContext) : null; } @@ -43,7 +44,7 @@ public interface DefinitionPropertyPlaceholderConfigurable { * This will be all the string based options. */ default Map<String, Consumer<String>> getWritePropertyPlaceholderOptions(CamelContext camelContext) { - DefinitionPropertyPlaceholderConfigurable aware = DefinitionPropertiesProviderHelper.provider(this).orElse(null); + DefinitionPropertyPlaceholderConfigurable aware = DefinitionPropertiesPlaceholderProviderHelper.provider(this).orElse(null); return aware != null ? aware.getWritePropertyPlaceholderOptions(camelContext) : null; } diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/CoreEipAnnotationProcessorHelper.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/CoreEipAnnotationProcessorHelper.java index edb48d7..fc00956 100644 --- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/CoreEipAnnotationProcessorHelper.java +++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/CoreEipAnnotationProcessorHelper.java @@ -18,13 +18,13 @@ package org.apache.camel.tools.apt; import java.io.PrintWriter; import java.io.Writer; +import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.TreeSet; -import java.util.function.Consumer; import java.util.stream.Collectors; import javax.annotation.processing.ProcessingEnvironment; @@ -92,7 +92,8 @@ public class CoreEipAnnotationProcessorHelper { private boolean skipUnwanted = true; - protected void processModelClass(final ProcessingEnvironment processingEnv, final RoundEnvironment roundEnv, final TypeElement classElement) { + protected void processModelClass(final ProcessingEnvironment processingEnv, final RoundEnvironment roundEnv, + final TypeElement classElement, Set<String> propertyPlaceholderDefinitions, final boolean last) { final String javaTypeName = canonicalClassName(classElement.getQualifiedName().toString()); String packageName = javaTypeName.substring(0, javaTypeName.lastIndexOf(".")); @@ -128,13 +129,20 @@ public class CoreEipAnnotationProcessorHelper { fileName = name + ".json"; } - // write json schema - processFile(processingEnv, packageName, fileName, writer -> writeJSonSchemeDocumentation(processingEnv, writer, roundEnv, classElement, rootElement, javaTypeName, name)); - } + // write json schema and property placeholder provider + processFile(processingEnv, packageName, fileName, writer -> writeJSonSchemeDocumentation(processingEnv, writer, + roundEnv, classElement, rootElement, javaTypeName, name, propertyPlaceholderDefinitions)); + // if last then generate + if (last) { + // lets sort themfirst + writePropertyPlaceholderDefinitionsHelper(processingEnv, roundEnv, propertyPlaceholderDefinitions); + } + } + // TODO: rename this protected void writeJSonSchemeDocumentation(ProcessingEnvironment processingEnv, PrintWriter writer, RoundEnvironment roundEnv, TypeElement classElement, - XmlRootElement rootElement, String javaTypeName, String modelName) { + XmlRootElement rootElement, String javaTypeName, String modelName, Set<String> propertyPlaceholderDefinitions) { // gather eip information EipModel eipModel = findEipModelProperties(processingEnv, roundEnv, classElement, javaTypeName, modelName); @@ -152,11 +160,11 @@ public class CoreEipAnnotationProcessorHelper { writer.println(json); // write property placeholder source code - writePropertyPlaceholderProviderSource(processingEnv, writer, roundEnv, classElement, eipModel, eipOptions); + writePropertyPlaceholderProviderSource(processingEnv, writer, roundEnv, classElement, eipModel, eipOptions, propertyPlaceholderDefinitions); } protected void writePropertyPlaceholderProviderSource(ProcessingEnvironment processingEnv, PrintWriter writer, RoundEnvironment roundEnv, TypeElement classElement, - EipModel eipModel, Set<EipOption> options) { + EipModel eipModel, Set<EipOption> options, Set<String> propertyPlaceholderDefinitions) { // the following are valid class elements which we want to generate boolean rest = classElement.getQualifiedName().toString().startsWith("org.apache.camel.model.rest"); @@ -175,6 +183,7 @@ public class CoreEipAnnotationProcessorHelper { String fqn = "org.apache.camel.model.placeholder." + cn; doWritePropertyPlaceholderProviderSource(processingEnv, parent, def, fqnDef, cn, fqn, options); + propertyPlaceholderDefinitions.add(fqnDef); // we also need to generate from when we generate route as from can also configure property placeholders if ("RouteDefinition".equals(def)) { @@ -188,6 +197,7 @@ public class CoreEipAnnotationProcessorHelper { options.add(new EipOption("uri", null, null, "java.lang.String", false, null, null, false, null, false, null, false, null, false)); doWritePropertyPlaceholderProviderSource(processingEnv, parent, def, fqnDef, cn, fqn, options); + propertyPlaceholderDefinitions.add(fqnDef); } } @@ -301,6 +311,57 @@ public class CoreEipAnnotationProcessorHelper { return option.getName(); } + private void writePropertyPlaceholderDefinitionsHelper(ProcessingEnvironment processingEnv, RoundEnvironment roundEnv, + Set<String> propertyPlaceholderDefinitions) { + Writer w = null; + try { + JavaFileObject src = processingEnv.getFiler().createSourceFile("org.apache.camel.model.placeholder.DefinitionPropertiesPlaceholderProviderHelper"); + w = src.openWriter(); + + w.write("/* Generated by camel-apt */\n"); + w.write("package org.apache.camel.model.placeholder;\n"); + w.write("\n"); + w.write("import java.util.HashMap;\n"); + w.write("import java.util.Map;\n"); + w.write("import java.util.Optional;\n"); + w.write("import java.util.function.Function;\n"); + w.write("import java.util.function.Supplier;\n"); + w.write("\n"); + w.write("import org.apache.camel.model.DefinitionPropertyPlaceholderConfigurable;\n"); + for (String def : propertyPlaceholderDefinitions) { + w.write("import " + def + ";\n"); + } + w.write("\n"); + w.write("public class DefinitionPropertiesPlaceholderProviderHelper {\n"); + w.write("\n"); + w.write(" private static final Map<Class, Function<Object, DefinitionPropertyPlaceholderConfigurable>> MAP;\n"); + w.write(" static {\n"); + w.write(" Map<Class, Function<Object, DefinitionPropertyPlaceholderConfigurable>> map = new HashMap<>();\n"); + for (String def : propertyPlaceholderDefinitions) { + String cn = def.substring(def.lastIndexOf('.') + 1); + w.write(" map.put(" + cn + ".class, " + cn + "PropertyPlaceholderProvider::new);\n"); + } + w.write(" MAP = map;\n"); + w.write(" }\n"); + w.write("\n"); + w.write(" public static Optional<DefinitionPropertyPlaceholderConfigurable> provider(Object definition) {\n"); + w.write(" Function<Object, DefinitionPropertyPlaceholderConfigurable> func = MAP.get(definition.getClass());\n"); + w.write(" if (func != null) {\n"); + w.write(" return Optional.of(func.apply(definition));\n"); + w.write(" }\n"); + w.write(" return Optional.empty();\n"); + w.write(" }\n"); + w.write("\n"); + w.write("}\n"); + w.write("\n"); + } catch (Exception e) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Unable to process annotated elements in " + getClass().getSimpleName() + ": " + e.getMessage()); + dumpExceptionToErrorFile("camel-apt-error.log", "Error processing annotation in " + getClass().getSimpleName(), e); + } finally { + IOHelper.close(w); + } + } + public String createParameterJsonSchema(EipModel eipModel, Set<EipOption> options) { StringBuilder buffer = new StringBuilder("{"); // eip model diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/ModelAnnotationProcessor.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/ModelAnnotationProcessor.java index 211f42b..5d1e380 100644 --- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/ModelAnnotationProcessor.java +++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/ModelAnnotationProcessor.java @@ -16,8 +16,13 @@ */ package org.apache.camel.tools.apt; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; import java.util.Set; - +import java.util.TreeSet; +import java.util.function.Predicate; +import java.util.stream.Collectors; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.lang.model.element.Element; @@ -38,19 +43,48 @@ public class ModelAnnotationProcessor extends AbstractCamelAnnotationProcessor { @Override protected void doProcess(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) throws Exception { Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(XmlRootElement.class); - for (Element element : elements) { - if (element instanceof TypeElement) { - TypeElement classElement = (TypeElement) element; - - final String javaTypeName = canonicalClassName(classElement.getQualifiedName().toString()); - boolean core = javaTypeName.startsWith("org.apache.camel.model"); - boolean spring = javaTypeName.startsWith("org.apache.camel.spring") || javaTypeName.startsWith("org.apache.camel.core.xml"); - if (core) { - coreProcessor.processModelClass(processingEnv, roundEnv, classElement); - } else if (spring) { - springProcessor.processModelClass(processingEnv, roundEnv, classElement); - } - } + + Set<? extends Element> coreElements = elements.stream() + .filter(new Predicate<Element>() { + @Override + public boolean test(Element element) { + if (element instanceof TypeElement) { + TypeElement classElement = (TypeElement) element; + + final String javaTypeName = canonicalClassName(classElement.getQualifiedName().toString()); + return javaTypeName.startsWith("org.apache.camel.model"); + } + return false; + } + }).collect(Collectors.toSet()); + + Set<? extends Element> springElements = elements.stream() + .filter(new Predicate<Element>() { + @Override + public boolean test(Element element) { + if (element instanceof TypeElement) { + TypeElement classElement = (TypeElement) element; + + final String javaTypeName = canonicalClassName(classElement.getQualifiedName().toString()); + return javaTypeName.startsWith("org.apache.camel.spring") || javaTypeName.startsWith("org.apache.camel.core.xml"); + } + return false; + } + }).collect(Collectors.toSet()); + + // we want them to be sorted + Set<String> propertyPlaceholderDefinitions = new TreeSet<>(String::compareToIgnoreCase); + + Iterator it = coreElements.iterator(); + while (it.hasNext()) { + TypeElement classElement = (TypeElement) it.next(); + coreProcessor.processModelClass(processingEnv, roundEnv, classElement, propertyPlaceholderDefinitions, !it.hasNext()); + } + + it = springElements.iterator(); + while (it.hasNext()) { + TypeElement classElement = (TypeElement) it.next(); + springProcessor.processModelClass(processingEnv, roundEnv, classElement, !it.hasNext()); } } diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/SpringAnnotationProcessorHelper.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/SpringAnnotationProcessorHelper.java index 2300352..75f3110 100644 --- a/tooling/apt/src/main/java/org/apache/camel/tools/apt/SpringAnnotationProcessorHelper.java +++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/SpringAnnotationProcessorHelper.java @@ -56,7 +56,8 @@ import static org.apache.camel.tools.apt.helper.Strings.safeNull; */ public class SpringAnnotationProcessorHelper { - protected void processModelClass(final ProcessingEnvironment processingEnv, final RoundEnvironment roundEnv, final TypeElement classElement) { + protected void processModelClass(final ProcessingEnvironment processingEnv, final RoundEnvironment roundEnv, + final TypeElement classElement, final boolean last) { final String javaTypeName = canonicalClassName(classElement.getQualifiedName().toString()); String packageName = javaTypeName.substring(0, javaTypeName.lastIndexOf("."));