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 f14ba3f1c4c61e31ac613b2afaee1dfef74b8707 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Tue Aug 13 18:11:40 2019 +0200 CAMEL-13850: Source code generate ExchangeConstantProvider so we can do fast lookup of its constant values without reflection --- core/camel-api/pom.xml | 18 +++ .../src/main/java/org/apache/camel/Exchange.java | 2 + .../camel/tools/apt/ConstantProviderProcessor.java | 130 +++++++++++++++++++++ .../services/javax.annotation.processing.Processor | 1 + .../camel/spi/annotations/ConstantProvider.java | 32 +++++ 5 files changed, 183 insertions(+) diff --git a/core/camel-api/pom.xml b/core/camel-api/pom.xml index 04a797b..54157b5 100644 --- a/core/camel-api/pom.xml +++ b/core/camel-api/pom.xml @@ -219,6 +219,24 @@ </build> </profile> + <profile> + <id>apt</id> + <activation> + <activeByDefault>true</activeByDefault> + </activation> + + <dependencies> + + <!-- enable the APT processor --> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>apt</artifactId> + <scope>provided</scope> + </dependency> + + </dependencies> + </profile> + <!-- skip management tests on AIX as it hangs CI servers --> <profile> <id>aix</id> diff --git a/core/camel-api/src/main/java/org/apache/camel/Exchange.java b/core/camel-api/src/main/java/org/apache/camel/Exchange.java index 1042154..90be5bf2 100644 --- a/core/camel-api/src/main/java/org/apache/camel/Exchange.java +++ b/core/camel-api/src/main/java/org/apache/camel/Exchange.java @@ -22,6 +22,7 @@ import java.util.Map; import org.apache.camel.spi.Synchronization; import org.apache.camel.spi.UnitOfWork; +import org.apache.camel.spi.annotations.ConstantProvider; /** * An Exchange is the message container holding the information during the entire routing of @@ -68,6 +69,7 @@ import org.apache.camel.spi.UnitOfWork; * See this <a href="http://camel.apache.org/using-getin-or-getout-methods-on-exchange.html">FAQ entry</a> * for more details. */ +@ConstantProvider("org.apache.camel.ExchangeConstantProvider") public interface Exchange { String AUTHENTICATION = "CamelAuthentication"; diff --git a/tooling/apt/src/main/java/org/apache/camel/tools/apt/ConstantProviderProcessor.java b/tooling/apt/src/main/java/org/apache/camel/tools/apt/ConstantProviderProcessor.java new file mode 100644 index 0000000..fa93112 --- /dev/null +++ b/tooling/apt/src/main/java/org/apache/camel/tools/apt/ConstantProviderProcessor.java @@ -0,0 +1,130 @@ +/* + * 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.tools.apt; + +import java.io.Writer; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; +import javax.tools.Diagnostic; +import javax.tools.JavaFileObject; + +import org.apache.camel.spi.annotations.ConstantProvider; +import org.apache.camel.tools.apt.helper.IOHelper; + +import static org.apache.camel.tools.apt.AnnotationProcessorHelper.dumpExceptionToErrorFile; +import static org.apache.camel.tools.apt.helper.Strings.canonicalClassName; + +@SupportedAnnotationTypes({"org.apache.camel.spi.annotations.ConstantProvider"}) +public class ConstantProviderProcessor extends AbstractCamelAnnotationProcessor { + + boolean acceptClass(Element element) { + return true; + } + + @Override + protected void doProcess(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) throws Exception { + TypeElement constantAnnotationType = this.processingEnv.getElementUtils().getTypeElement("org.apache.camel.spi.annotations.ConstantProvider"); + Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(constantAnnotationType); + + Map<String, Element> constantClasses = new TreeMap<>(); + for (Element element : elements) { + if (element instanceof TypeElement) { + TypeElement te = (TypeElement) element; + + // we only support top-level classes (not inner classes) + if (!te.getNestingKind().isNested() && acceptClass(te)) { + final String javaTypeName = canonicalClassName(te.getQualifiedName().toString()); + constantClasses.put(javaTypeName, element); + } + } + } + + // skip all converter classes from core as we just want to use the optimized TypeConverterLoader files + constantClasses.forEach((k, v) -> { + String fqn = v.getAnnotation(ConstantProvider.class).value(); + Map<String, String> fields = new TreeMap<>(String::compareToIgnoreCase); + + Set<Element> set = new HashSet<>(v.getEnclosedElements()); + for (VariableElement field : ElementFilter.fieldsIn(set)) { + TypeMirror fieldType = field.asType(); + String fullTypeClassName = fieldType.toString(); + if (String.class.getName().equals(fullTypeClassName)) { + String name = field.getSimpleName().toString(); + String text = (String) field.getConstantValue(); + fields.put(name, text); + dumpExceptionToErrorFile("camel-apt-error.log", "Name: " + field.getSimpleName().toString() + "=" + text, null); + } + } + + if (!fields.isEmpty()) { + generateConstantProviderClass(fqn, fields); + } + }); + } + + private void generateConstantProviderClass(String fqn, Map<String, String> fields) { + String pn = fqn.substring(0, fqn.lastIndexOf('.')); + String cn = fqn.substring(fqn.lastIndexOf('.') + 1); + + Writer w = null; + try { + JavaFileObject src = processingEnv.getFiler().createSourceFile(fqn); + w = src.openWriter(); + + w.write("/* Generated by org.apache.camel:apt */\n"); + w.write("package " + pn + ";\n"); + w.write("\n"); + w.write("import java.util.HashMap;\n"); + w.write("import java.util.Map;\n"); + w.write("\n"); + w.write("/**\n"); + w.write(" * Source code generated by org.apache.camel:apt\n"); + w.write(" */\n"); + w.write("public class " + cn + " {\n"); + w.write("\n"); + w.write(" private static final Map<String, String> MAP;\n"); + w.write(" static {\n"); + w.write(" Map<String, String> map = new HashMap<>(" + fields.size() + ");\n"); + for (Map.Entry<String, String> entry : fields.entrySet()) { + w.write(" map.put(\"" + entry.getKey() + "\", \"" + entry.getValue() + "\");\n"); + } + w.write(" MAP = map;\n"); + w.write(" }\n"); + w.write("\n"); + w.write(" public static String provider(String key) {\n"); + w.write(" return MAP.get(key);\n"); + w.write(" }\n"); + w.write("}\n"); + w.write("\n"); + } catch (Exception e) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Unable to generate source code file: " + fqn + ": " + e.getMessage()); + dumpExceptionToErrorFile("camel-apt-error.log", "Unable to generate source code file: " + fqn, e); + } finally { + IOHelper.close(w); + } + } + +} \ No newline at end of file diff --git a/tooling/apt/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/tooling/apt/src/main/resources/META-INF/services/javax.annotation.processing.Processor index 73db54b..fc74786 100644 --- a/tooling/apt/src/main/resources/META-INF/services/javax.annotation.processing.Processor +++ b/tooling/apt/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -19,6 +19,7 @@ org.apache.camel.tools.apt.ModelAnnotationProcessor org.apache.camel.tools.apt.EndpointAnnotationProcessor org.apache.camel.tools.apt.SpiProcessor +org.apache.camel.tools.apt.ConstantProviderProcessor org.apache.camel.tools.apt.TypeConverterProcessor org.apache.camel.tools.apt.TypeConverterLoaderGenerator diff --git a/tooling/spi-annotations/src/main/java/org/apache/camel/spi/annotations/ConstantProvider.java b/tooling/spi-annotations/src/main/java/org/apache/camel/spi/annotations/ConstantProvider.java new file mode 100644 index 0000000..1a93df6 --- /dev/null +++ b/tooling/spi-annotations/src/main/java/org/apache/camel/spi/annotations/ConstantProvider.java @@ -0,0 +1,32 @@ +/* + * 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.spi.annotations; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Target({ElementType.TYPE }) +public @interface ConstantProvider { + + String value(); + +}