You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2019/08/14 07:52:58 UTC

[camel] 04/21: CAMEL-13850: Optimize model classes to provide changeable properties that support property placeholders to avoid reflection. Work in progress.

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 <cl...@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("."));