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 2022/03/12 06:18:35 UTC

[camel] branch CAMEL-17571 created (now ab841f6)

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a change to branch CAMEL-17571
in repository https://gitbox.apache.org/repos/asf/camel.git.


      at ab841f6  camel-kamelet-main - Cleanup code

This branch includes the following new commits:

     new 347d531  CAMEL-17571: camel-dsl - Allow to register custom annotation processors that can do custom logic after a DSL has compiled source into Java object.
     new edcbd22  CAMEL-17571: camel-jbang - Support for spring @Component/@Service annotations in custom beans
     new 1e2f796  CAMEL-17571: camel-dsl - Allow to register custom annotation processors that can do custom logic after a DSL has compiled source into Java object.
     new 8ba2dd8  CAMEL-17571: camel-dsl - Allow to register custom annotation processors that can do custom logic after a DSL has compiled source into Java object.
     new a46c8e7  CAMEL-17571: camel-jbang - Support for spring @Autowired/@Value annotations in custom beans
     new 5a5ef74  CAMEL-17571: camel-jbang - Support for spring @Autowired/@Value annotations in custom beans
     new f1c6b5d  CAMEL-17571: camel-jbang - Support for spring @Bean annotations in custom beans
     new 5334e55  CAMEL-17571: camel-jbang - Support for spring @Bean annotations in custom beans
     new a612b4b  CAMEL-17571: camel-dsl - Allow to register custom annotation processors that can do custom logic after a DSL has compiled source into Java object.
     new 9317e52  CAMEL-17571: camel-dsl - Allow to register custom annotation processors that can do custom logic after a DSL has compiled source into Java object.
     new ab841f6  camel-kamelet-main - Cleanup code

The 11 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[camel] 07/11: CAMEL-17571: camel-jbang - Support for spring @Bean annotations in custom beans

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-17571
in repository https://gitbox.apache.org/repos/asf/camel.git

commit f1c6b5dc7e6bffeb3e57e99871936ff86730af96
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Mar 11 18:34:17 2022 +0100

    CAMEL-17571: camel-jbang - Support for spring @Bean annotations in custom beans
---
 .../impl/engine/CamelPostProcessorHelper.java      | 89 ++++++++++++++++++++++
 .../impl/engine/DefaultCamelBeanPostProcessor.java | 85 +--------------------
 .../apache/camel/main/SpringAnnotationSupport.java | 22 +++++-
 3 files changed, 114 insertions(+), 82 deletions(-)

diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/CamelPostProcessorHelper.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/CamelPostProcessorHelper.java
index 04b4f95..a6a5654 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/CamelPostProcessorHelper.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/CamelPostProcessorHelper.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.impl.engine;
 
+import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 import java.util.LinkedHashMap;
 import java.util.Locale;
@@ -23,6 +24,8 @@ import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
 
+import org.apache.camel.BeanConfigInject;
+import org.apache.camel.BeanInject;
 import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
 import org.apache.camel.Consume;
@@ -38,12 +41,15 @@ import org.apache.camel.NoSuchBeanException;
 import org.apache.camel.PollingConsumer;
 import org.apache.camel.Producer;
 import org.apache.camel.ProducerTemplate;
+import org.apache.camel.PropertyInject;
 import org.apache.camel.ProxyInstantiationException;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.Service;
+import org.apache.camel.TypeConverter;
 import org.apache.camel.spi.BeanProxyFactory;
 import org.apache.camel.spi.PropertiesComponent;
 import org.apache.camel.spi.PropertyConfigurer;
+import org.apache.camel.spi.Registry;
 import org.apache.camel.support.CamelContextHelper;
 import org.apache.camel.support.PropertyBindingSupport;
 import org.apache.camel.support.service.ServiceHelper;
@@ -51,6 +57,9 @@ import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.apache.camel.support.ObjectHelper.invokeMethod;
+import static org.apache.camel.util.ObjectHelper.isEmpty;
+
 /**
  * A helper class for Camel based injector or bean post processing hooks.
  */
@@ -402,6 +411,86 @@ public class CamelPostProcessorHelper implements CamelContextAware {
         return bean;
     }
 
+    public Object getInjectionBeanMethodValue(
+            CamelContext context,
+            Method method, Object bean, String beanName) {
+        Class<?> returnType = method.getReturnType();
+        if (returnType == Void.TYPE) {
+            throw new IllegalArgumentException(
+                    "@BindToRegistry on class: " + method.getDeclaringClass()
+                                               + " method: " + method.getName() + " with void return type is not allowed");
+        }
+
+        Object value;
+        Object[] parameters = bindToRegistryParameterMapping(context, method);
+        if (parameters != null) {
+            value = invokeMethod(method, bean, parameters);
+        } else {
+            value = invokeMethod(method, bean);
+        }
+        return value;
+    }
+
+    private Object[] bindToRegistryParameterMapping(CamelContext context, Method method) {
+        if (method.getParameterCount() == 0) {
+            return null;
+        }
+
+        // map each parameter if possible
+        Object[] parameters = new Object[method.getParameterCount()];
+        for (int i = 0; i < method.getParameterCount(); i++) {
+            Class<?> type = method.getParameterTypes()[i];
+            if (type.isAssignableFrom(CamelContext.class)) {
+                parameters[i] = context;
+            } else if (type.isAssignableFrom(Registry.class)) {
+                parameters[i] = context.getRegistry();
+            } else if (type.isAssignableFrom(TypeConverter.class)) {
+                parameters[i] = context.getTypeConverter();
+            } else {
+                // we also support @BeanInject and @PropertyInject annotations
+                Annotation[] anns = method.getParameterAnnotations()[i];
+                if (anns.length == 1) {
+                    // we dont assume there are multiple annotations on the same parameter so grab first
+                    Annotation ann = anns[0];
+                    if (ann.annotationType() == PropertyInject.class) {
+                        PropertyInject pi = (PropertyInject) ann;
+                        Object result = getInjectionPropertyValue(type, pi.value(), pi.defaultValue(),
+                                null, null, null);
+                        parameters[i] = result;
+                    } else if (ann.annotationType() == BeanConfigInject.class) {
+                        BeanConfigInject pi = (BeanConfigInject) ann;
+                        Object result = getInjectionBeanConfigValue(type, pi.value());
+                        parameters[i] = result;
+                    } else if (ann.annotationType() == BeanInject.class) {
+                        BeanInject bi = (BeanInject) ann;
+                        Object result = getInjectionBeanValue(type, bi.value());
+                        parameters[i] = result;
+                    }
+                } else {
+                    // okay attempt to default to singleton instances from the registry
+                    Set<?> instances = context.getRegistry().findByType(type);
+                    if (instances.size() == 1) {
+                        parameters[i] = instances.iterator().next();
+                    } else if (instances.size() > 1) {
+                        // there are multiple instances of the same type, so barf
+                        throw new IllegalArgumentException(
+                                "Multiple beans of the same type: " + type
+                                                           + " exists in the Camel registry. Specify the bean name on @BeanInject to bind to a single bean, at the method: "
+                                                           + method);
+                    }
+                }
+            }
+
+            // each parameter must be mapped
+            if (parameters[i] == null) {
+                int pos = i + 1;
+                throw new IllegalArgumentException("@BindToProperty cannot bind parameter #" + pos + " on method: " + method);
+            }
+        }
+
+        return parameters;
+    }
+
     /**
      * Factory method to create a {@link org.apache.camel.ProducerTemplate} to be injected into a POJO
      */
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelBeanPostProcessor.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelBeanPostProcessor.java
index 15ad1af..6293b86 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelBeanPostProcessor.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelBeanPostProcessor.java
@@ -16,13 +16,11 @@
  */
 package org.apache.camel.impl.engine;
 
-import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.List;
-import java.util.Set;
 import java.util.function.Function;
 
 import org.apache.camel.BeanConfigInject;
@@ -35,10 +33,8 @@ import org.apache.camel.EndpointInject;
 import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.Produce;
 import org.apache.camel.PropertyInject;
-import org.apache.camel.TypeConverter;
 import org.apache.camel.spi.CamelBeanPostProcessor;
 import org.apache.camel.spi.CamelBeanPostProcessorInjector;
-import org.apache.camel.spi.Registry;
 import org.apache.camel.support.DefaultEndpoint;
 import org.apache.camel.util.ReflectionHelper;
 import org.slf4j.Logger;
@@ -515,12 +511,11 @@ public class DefaultCamelBeanPostProcessor implements CamelBeanPostProcessor, Ca
         }
         Object value = ReflectionHelper.getField(field, bean);
 
-        // use dependency injection factory to perform the task of binding the bean to registry
         if (value != null) {
-
             if (unbindEnabled) {
                 getOrLookupCamelContext().getRegistry().unbind(name);
             }
+            // use dependency injection factory to perform the task of binding the bean to registry
             Runnable task = getOrLookupCamelContext().adapt(ExtendedCamelContext.class)
                     .getDependencyInjectionAnnotationFactory()
                     .createBindToRegistryFactory(name, value, beanName, beanPostProcess);
@@ -532,26 +527,14 @@ public class DefaultCamelBeanPostProcessor implements CamelBeanPostProcessor, Ca
         if (isEmpty(name)) {
             name = method.getName();
         }
-        Class<?> returnType = method.getReturnType();
-        if (returnType == null || returnType == Void.TYPE) {
-            throw new IllegalArgumentException(
-                    "@BindToRegistry on class: " + method.getDeclaringClass()
-                                               + " method: " + method.getName() + " with void return type is not allowed");
-        }
+        Object value = getPostProcessorHelper()
+                .getInjectionBeanMethodValue(getOrLookupCamelContext(), method, bean, beanName);
 
-        Object value;
-        Object[] parameters = bindToRegistryParameterMapping(method);
-        if (parameters != null) {
-            value = invokeMethod(method, bean, parameters);
-        } else {
-            value = invokeMethod(method, bean);
-        }
-        // use dependency injection factory to perform the task of binding the bean to registry
         if (value != null) {
-
             if (unbindEnabled) {
                 getOrLookupCamelContext().getRegistry().unbind(name);
             }
+            // use dependency injection factory to perform the task of binding the bean to registry
             Runnable task = getOrLookupCamelContext().adapt(ExtendedCamelContext.class)
                     .getDependencyInjectionAnnotationFactory()
                     .createBindToRegistryFactory(name, value, beanName, beanPostProcess);
@@ -559,66 +542,6 @@ public class DefaultCamelBeanPostProcessor implements CamelBeanPostProcessor, Ca
         }
     }
 
-    private Object[] bindToRegistryParameterMapping(Method method) {
-        if (method.getParameterCount() == 0) {
-            return null;
-        }
-
-        // map each parameter if possible
-        Object[] parameters = new Object[method.getParameterCount()];
-        for (int i = 0; i < method.getParameterCount(); i++) {
-            Class<?> type = method.getParameterTypes()[i];
-            if (type.isAssignableFrom(CamelContext.class)) {
-                parameters[i] = getOrLookupCamelContext();
-            } else if (type.isAssignableFrom(Registry.class)) {
-                parameters[i] = getOrLookupCamelContext().getRegistry();
-            } else if (type.isAssignableFrom(TypeConverter.class)) {
-                parameters[i] = getOrLookupCamelContext().getTypeConverter();
-            } else {
-                // we also support @BeanInject and @PropertyInject annotations
-                Annotation[] anns = method.getParameterAnnotations()[i];
-                if (anns.length == 1) {
-                    // we dont assume there are multiple annotations on the same parameter so grab first
-                    Annotation ann = anns[0];
-                    if (ann.annotationType() == PropertyInject.class) {
-                        PropertyInject pi = (PropertyInject) ann;
-                        Object result = getPostProcessorHelper().getInjectionPropertyValue(type, pi.value(), pi.defaultValue(),
-                                null, null, null);
-                        parameters[i] = result;
-                    } else if (ann.annotationType() == BeanConfigInject.class) {
-                        BeanConfigInject pi = (BeanConfigInject) ann;
-                        Object result = getPostProcessorHelper().getInjectionBeanConfigValue(type, pi.value());
-                        parameters[i] = result;
-                    } else if (ann.annotationType() == BeanInject.class) {
-                        BeanInject bi = (BeanInject) ann;
-                        Object result = getPostProcessorHelper().getInjectionBeanValue(type, bi.value());
-                        parameters[i] = result;
-                    }
-                } else {
-                    // okay attempt to default to singleton instances from the registry
-                    Set<?> instances = getOrLookupCamelContext().getRegistry().findByType(type);
-                    if (instances.size() == 1) {
-                        parameters[i] = instances.iterator().next();
-                    } else if (instances.size() > 1) {
-                        // there are multiple instances of the same type, so barf
-                        throw new IllegalArgumentException(
-                                "Multiple beans of the same type: " + type
-                                                           + " exists in the Camel registry. Specify the bean name on @BeanInject to bind to a single bean, at the method: "
-                                                           + method);
-                    }
-                }
-            }
-
-            // each parameter must be mapped
-            if (parameters[i] == null) {
-                int pos = i + 1;
-                throw new IllegalArgumentException("@BindToProperty cannot bind parameter #" + pos + " on method: " + method);
-            }
-        }
-
-        return parameters;
-    }
-
     private static boolean isComplexUserType(Class type) {
         // lets consider all non java, as complex types
         return type != null && !type.isPrimitive() && !type.getName().startsWith("java.");
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java
index 1186ccd..881e4b3 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java
@@ -31,6 +31,7 @@ import org.apache.camel.util.ReflectionHelper;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Service;
 
@@ -114,7 +115,26 @@ public final class SpringAnnotationSupport {
 
         @Override
         public void onMethodInject(Method method, Object bean, String beanName) {
-            // TODO; @Bean
+            Bean bi = method.getAnnotation(Bean.class);
+            if (bi != null) {
+                Object instance = helper.getInjectionBeanMethodValue(context, method, bean, beanName);
+                if (instance != null) {
+                    String name = method.getName();
+                    if (bi.name() != null && bi.name().length > 0) {
+                        name = bi.name()[0];
+                    }
+                    // to support hot reloading of beans then we need to enable unbind mode in bean post processor
+                    CamelBeanPostProcessor bpp = context.adapt(ExtendedCamelContext.class).getBeanPostProcessor();
+                    bpp.setUnbindEnabled(true);
+                    try {
+                        // re-bind the bean to the registry
+                        context.getRegistry().unbind(name);
+                        context.getRegistry().bind(name, instance);
+                    } finally {
+                        bpp.setUnbindEnabled(false);
+                    }
+                }
+            }
         }
     }
 }

[camel] 02/11: CAMEL-17571: camel-jbang - Support for spring @Component/@Service annotations in custom beans

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-17571
in repository https://gitbox.apache.org/repos/asf/camel.git

commit edcbd22a65371e753dc13710598287cc90439832
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Mar 11 10:51:31 2022 +0100

    CAMEL-17571: camel-jbang - Support for spring @Component/@Service annotations in custom beans
---
 dsl/camel-kamelet-main/pom.xml                     | 13 +++++
 .../java/org/apache/camel/main/KameletMain.java    |  2 +
 .../apache/camel/main/SpringAnnotationSupport.java | 65 +++++++++++++++++++++-
 3 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/dsl/camel-kamelet-main/pom.xml b/dsl/camel-kamelet-main/pom.xml
index c1b4f9f..0236a5f 100644
--- a/dsl/camel-kamelet-main/pom.xml
+++ b/dsl/camel-kamelet-main/pom.xml
@@ -105,6 +105,19 @@
             <artifactId>camel-catalog-console</artifactId>
         </dependency>
 
+        <!-- optional spring annotation support -->
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context</artifactId>
+            <version>${spring-version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework</groupId>
+                    <artifactId>*</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
         <dependency>
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-timer</artifactId>
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
index 665c872..8279f1b 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
@@ -163,6 +163,8 @@ public class KameletMain extends MainCommandLineSupport {
         answer.setRegistry(registry);
         // load camel component and custom health-checks
         answer.setLoadHealthChecks(true);
+        // optional spring annotation support
+        SpringAnnotationSupport.registerSpringSupport(answer);
 
         // embed HTTP server if port is specified
         Object port = getInitialProperties().get("camel.jbang.platform-http.port");
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java
index 1682402..22a185b 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java
@@ -1,2 +1,65 @@
-package org.apache.camel.main;public class SpringAnnotationSupport {
+/*
+ * 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.main;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.dsl.support.AnnotationPreProcessor;
+import org.apache.camel.spi.CamelBeanPostProcessor;
+import org.apache.camel.util.ObjectHelper;
+import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Service;
+
+public final class SpringAnnotationSupport {
+
+    private SpringAnnotationSupport() {
+    }
+
+    public static void registerSpringSupport(CamelContext context) {
+        context.getRegistry().bind("SpringAnnotationPreProcessor", new SpringAnnotationPreProcessor());
+    }
+
+    private static class SpringAnnotationPreProcessor implements AnnotationPreProcessor {
+
+        @Override
+        public void handleAnnotation(CamelContext camelContext, String name, Class<?> clazz, Object instance) throws Exception {
+            // @Component and @Service are the same
+            Component comp = clazz.getAnnotation(Component.class);
+            Service service = clazz.getAnnotation(Service.class);
+            if (comp != null || service != null) {
+                CamelBeanPostProcessor bpp = camelContext.adapt(ExtendedCamelContext.class).getBeanPostProcessor();
+                if (comp != null && ObjectHelper.isNotEmpty(comp.value())) {
+                    name = comp.value();
+                } else if (service != null && ObjectHelper.isNotEmpty(service.value())) {
+                    name = service.value();
+                }
+                // to support hot reloading of beans then we need to enable unbind mode in bean post processor
+                bpp.setUnbindEnabled(true);
+                try {
+                    // re-bind the bean to the registry
+                    camelContext.getRegistry().unbind(name);
+                    camelContext.getRegistry().bind(name, instance);
+                    // this class is a bean service which needs to be post processed
+                    bpp.postProcessBeforeInitialization(instance, name);
+                    bpp.postProcessAfterInitialization(instance, name);
+                } finally {
+                    bpp.setUnbindEnabled(false);
+                }
+            }
+        }
+    }
 }

[camel] 10/11: CAMEL-17571: camel-dsl - Allow to register custom annotation processors that can do custom logic after a DSL has compiled source into Java object.

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-17571
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 9317e52ecf66701bf16d0777ad69331612ca7a39
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Mar 11 22:30:43 2022 +0100

    CAMEL-17571: camel-dsl - Allow to register custom annotation processors that can do custom logic after a DSL has compiled source into Java object.
---
 .../org/apache/camel/impl/CamelBeanPostProcessorInjectorTest.java   | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/core/camel-core/src/test/java/org/apache/camel/impl/CamelBeanPostProcessorInjectorTest.java b/core/camel-core/src/test/java/org/apache/camel/impl/CamelBeanPostProcessorInjectorTest.java
index a244b3b..dc9793a 100644
--- a/core/camel-core/src/test/java/org/apache/camel/impl/CamelBeanPostProcessorInjectorTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/impl/CamelBeanPostProcessorInjectorTest.java
@@ -16,6 +16,9 @@
  */
 package org.apache.camel.impl;
 
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
 import org.apache.camel.ContextTestSupport;
 import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.PropertyInject;
@@ -29,9 +32,6 @@ import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-
 public class CamelBeanPostProcessorInjectorTest extends ContextTestSupport {
 
     private CamelBeanPostProcessor postProcessor;

[camel] 04/11: CAMEL-17571: camel-dsl - Allow to register custom annotation processors that can do custom logic after a DSL has compiled source into Java object.

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-17571
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 8ba2dd851a553108d7acb8f898936fee9068a37a
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Mar 11 11:11:54 2022 +0100

    CAMEL-17571: camel-dsl - Allow to register custom annotation processors that can do custom logic after a DSL has compiled source into Java object.
---
 .../BindToRegistryCompilePostProcessor.java        | 56 ++++++++++++++++++
 .../dsl/support/RouteBuilderLoaderSupport.java     |  7 ++-
 .../support/TypeConverterCompilePostProcessor.java | 45 +++++++++++++++
 .../dsl/java/joor/JavaRoutesBuilderLoader.java     | 66 ----------------------
 4 files changed, 106 insertions(+), 68 deletions(-)

diff --git a/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/BindToRegistryCompilePostProcessor.java b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/BindToRegistryCompilePostProcessor.java
new file mode 100644
index 0000000..cd1271a
--- /dev/null
+++ b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/BindToRegistryCompilePostProcessor.java
@@ -0,0 +1,56 @@
+/*
+ * 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.dsl.support;
+
+import org.apache.camel.BindToRegistry;
+import org.apache.camel.CamelConfiguration;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Configuration;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.spi.CamelBeanPostProcessor;
+import org.apache.camel.util.ObjectHelper;
+
+public class BindToRegistryCompilePostProcessor implements CompilePostProcessor {
+
+    @Override
+    public void postCompile(CamelContext camelContext, String name, Class<?> clazz, Object instance) throws Exception {
+        BindToRegistry bir = instance.getClass().getAnnotation(BindToRegistry.class);
+        Configuration cfg = instance.getClass().getAnnotation(Configuration.class);
+        if (bir != null || cfg != null || instance instanceof CamelConfiguration) {
+            CamelBeanPostProcessor bpp = camelContext.adapt(ExtendedCamelContext.class).getBeanPostProcessor();
+            if (bir != null && ObjectHelper.isNotEmpty(bir.value())) {
+                name = bir.value();
+            } else if (cfg != null && ObjectHelper.isNotEmpty(cfg.value())) {
+                name = cfg.value();
+            }
+            // to support hot reloading of beans then we need to enable unbind mode in bean post processor
+            bpp.setUnbindEnabled(true);
+            try {
+                // this class is a bean service which needs to be post processed and registered which happens
+                // automatic by the bean post processor
+                bpp.postProcessBeforeInitialization(instance, name);
+                bpp.postProcessAfterInitialization(instance, name);
+            } finally {
+                bpp.setUnbindEnabled(false);
+            }
+            if (instance instanceof CamelConfiguration) {
+                ((CamelConfiguration) instance).configure(camelContext);
+            }
+        }
+    }
+
+}
diff --git a/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java
index 0b3dae8..eb0024b 100644
--- a/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java
+++ b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java
@@ -37,12 +37,15 @@ import org.apache.camel.support.RoutesBuilderLoaderSupport;
  */
 public abstract class RouteBuilderLoaderSupport extends RoutesBuilderLoaderSupport {
     private final String extension;
-
-    private StartupStepRecorder recorder;
     private final List<CompilePostProcessor> compilePostProcessors = new ArrayList<>();
+    private StartupStepRecorder recorder;
 
     protected RouteBuilderLoaderSupport(String extension) {
         this.extension = extension;
+
+        // out of the box camel based compile post processors
+        addCompilePostProcessor(new TypeConverterCompilePostProcessor());
+        addCompilePostProcessor(new BindToRegistryCompilePostProcessor());
     }
 
     @ManagedAttribute(description = "Supported file extension")
diff --git a/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/TypeConverterCompilePostProcessor.java b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/TypeConverterCompilePostProcessor.java
new file mode 100644
index 0000000..ba3de3b
--- /dev/null
+++ b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/TypeConverterCompilePostProcessor.java
@@ -0,0 +1,45 @@
+/*
+ * 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.dsl.support;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Converter;
+import org.apache.camel.LoggingLevel;
+import org.apache.camel.TypeConverterExists;
+import org.apache.camel.spi.TypeConverterRegistry;
+
+public class TypeConverterCompilePostProcessor implements CompilePostProcessor {
+
+    @Override
+    public void postCompile(CamelContext camelContext, String name, Class<?> clazz, Object instance) throws Exception {
+        if (clazz.getAnnotation(Converter.class) != null) {
+            TypeConverterRegistry tcr = camelContext.getTypeConverterRegistry();
+            TypeConverterExists exists = tcr.getTypeConverterExists();
+            LoggingLevel level = tcr.getTypeConverterExistsLoggingLevel();
+            // force type converter to override as we could be re-loading
+            tcr.setTypeConverterExists(TypeConverterExists.Override);
+            tcr.setTypeConverterExistsLoggingLevel(LoggingLevel.OFF);
+            try {
+                tcr.addTypeConverters(clazz);
+            } finally {
+                tcr.setTypeConverterExists(exists);
+                tcr.setTypeConverterExistsLoggingLevel(level);
+            }
+        }
+    }
+
+}
diff --git a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
index a407559..b5d2815 100644
--- a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
+++ b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
@@ -21,26 +21,15 @@ import java.io.InputStream;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import org.apache.camel.BindToRegistry;
-import org.apache.camel.CamelConfiguration;
-import org.apache.camel.CamelContext;
-import org.apache.camel.Configuration;
-import org.apache.camel.Converter;
-import org.apache.camel.ExtendedCamelContext;
-import org.apache.camel.LoggingLevel;
-import org.apache.camel.TypeConverterExists;
 import org.apache.camel.api.management.ManagedResource;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.dsl.support.CompilePostProcessor;
 import org.apache.camel.dsl.support.RouteBuilderLoaderSupport;
-import org.apache.camel.spi.CamelBeanPostProcessor;
 import org.apache.camel.spi.Resource;
-import org.apache.camel.spi.TypeConverterRegistry;
 import org.apache.camel.spi.annotations.RoutesLoader;
 import org.apache.camel.support.ResourceHelper;
 import org.apache.camel.util.FileUtil;
 import org.apache.camel.util.IOHelper;
-import org.apache.camel.util.ObjectHelper;
 import org.joor.Reflect;
 
 @ManagedResource(description = "Managed JavaRoutesBuilderLoader")
@@ -52,9 +41,6 @@ public class JavaRoutesBuilderLoader extends RouteBuilderLoaderSupport {
 
     public JavaRoutesBuilderLoader() {
         super(EXTENSION);
-
-        addCompilePostProcessor(new ConverterCompilePostProcessor());
-        addCompilePostProcessor(new BindToRegistryCompilePostProcessor());
     }
 
     @Override
@@ -98,56 +84,4 @@ public class JavaRoutesBuilderLoader extends RouteBuilderLoaderSupport {
                 : name;
     }
 
-    private static class ConverterCompilePostProcessor implements CompilePostProcessor {
-
-        @Override
-        public void postCompile(CamelContext camelContext, String name, Class<?> clazz, Object instance) throws Exception {
-            if (clazz.getAnnotation(Converter.class) != null) {
-                TypeConverterRegistry tcr = camelContext.getTypeConverterRegistry();
-                TypeConverterExists exists = tcr.getTypeConverterExists();
-                LoggingLevel level = tcr.getTypeConverterExistsLoggingLevel();
-                // force type converter to override as we could be re-loading
-                tcr.setTypeConverterExists(TypeConverterExists.Override);
-                tcr.setTypeConverterExistsLoggingLevel(LoggingLevel.OFF);
-                try {
-                    tcr.addTypeConverters(clazz);
-                } finally {
-                    tcr.setTypeConverterExists(exists);
-                    tcr.setTypeConverterExistsLoggingLevel(level);
-                }
-            }
-        }
-    }
-
-    private static class BindToRegistryCompilePostProcessor implements CompilePostProcessor {
-
-        @Override
-        public void postCompile(CamelContext camelContext, String name, Class<?> clazz, Object instance) throws Exception {
-            BindToRegistry bir = instance.getClass().getAnnotation(BindToRegistry.class);
-            Configuration cfg = instance.getClass().getAnnotation(Configuration.class);
-            if (bir != null || cfg != null || instance instanceof CamelConfiguration) {
-                CamelBeanPostProcessor bpp = camelContext.adapt(ExtendedCamelContext.class).getBeanPostProcessor();
-                if (bir != null && ObjectHelper.isNotEmpty(bir.value())) {
-                    name = bir.value();
-                } else if (cfg != null && ObjectHelper.isNotEmpty(cfg.value())) {
-                    name = cfg.value();
-                }
-                // to support hot reloading of beans then we need to enable unbind mode in bean post processor
-                bpp.setUnbindEnabled(true);
-                try {
-                    // this class is a bean service which needs to be post processed and registered which happens
-                    // automatic by the bean post processor
-                    bpp.postProcessBeforeInitialization(instance, name);
-                    bpp.postProcessAfterInitialization(instance, name);
-                } finally {
-                    bpp.setUnbindEnabled(false);
-                }
-                if (instance instanceof CamelConfiguration) {
-                    ((CamelConfiguration) instance).configure(camelContext);
-                }
-            }
-        }
-
-    }
-
 }

[camel] 09/11: CAMEL-17571: camel-dsl - Allow to register custom annotation processors that can do custom logic after a DSL has compiled source into Java object.

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-17571
in repository https://gitbox.apache.org/repos/asf/camel.git

commit a612b4bdf5cfb3802b8dd3053ee410eaac9dda47
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Mar 11 22:20:04 2022 +0100

    CAMEL-17571: camel-dsl - Allow to register custom annotation processors that can do custom logic after a DSL has compiled source into Java object.
---
 .../impl/engine/CamelPostProcessorHelper.java      |   3 +-
 .../impl/CamelBeanPostProcessorInjectorTest.java   | 101 +++++++++++++++++++++
 2 files changed, 102 insertions(+), 2 deletions(-)

diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/CamelPostProcessorHelper.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/CamelPostProcessorHelper.java
index a6a5654..533fb49 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/CamelPostProcessorHelper.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/CamelPostProcessorHelper.java
@@ -58,10 +58,9 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import static org.apache.camel.support.ObjectHelper.invokeMethod;
-import static org.apache.camel.util.ObjectHelper.isEmpty;
 
 /**
- * A helper class for Camel based injector or bean post processing hooks.
+ * A helper class for Camel based injector or bean post-processing hooks.
  */
 public class CamelPostProcessorHelper implements CamelContextAware {
 
diff --git a/core/camel-core/src/test/java/org/apache/camel/impl/CamelBeanPostProcessorInjectorTest.java b/core/camel-core/src/test/java/org/apache/camel/impl/CamelBeanPostProcessorInjectorTest.java
new file mode 100644
index 0000000..a244b3b
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/impl/CamelBeanPostProcessorInjectorTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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.impl;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.PropertyInject;
+import org.apache.camel.impl.engine.CamelPostProcessorHelper;
+import org.apache.camel.spi.CamelBeanPostProcessor;
+import org.apache.camel.spi.CamelBeanPostProcessorInjector;
+import org.apache.camel.spi.CamelLogger;
+import org.apache.camel.support.ObjectHelper;
+import org.apache.camel.util.ReflectionHelper;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+public class CamelBeanPostProcessorInjectorTest extends ContextTestSupport {
+
+    private CamelBeanPostProcessor postProcessor;
+    private CamelPostProcessorHelper helper;
+
+    @Override
+    @BeforeEach
+    public void setUp() throws Exception {
+        super.setUp();
+        postProcessor = context.adapt(ExtendedCamelContext.class).getBeanPostProcessor();
+        postProcessor.addCamelBeanPostProjectInjector(new MyInjector());
+        helper = new CamelPostProcessorHelper(context);
+    }
+
+    private class MyInjector implements CamelBeanPostProcessorInjector {
+
+        @Override
+        public void onFieldInject(Field field, Object bean, String beanName) {
+            if (field.getName().equals("foo")) {
+                ReflectionHelper.setField(field, bean, "changed-foo");
+            }
+        }
+
+        @Override
+        public void onMethodInject(Method method, Object bean, String beanName) {
+            if (method.getName().equals("createLogger")) {
+                Object out = ObjectHelper.invokeMethod(method, bean, "changed-bar");
+                context.getRegistry().bind(method.getName(), out);
+            }
+        }
+    }
+
+    public class MyService {
+
+        @PropertyInject(value = "myName", defaultValue = "Donald Duck")
+        private String name;
+        @PropertyInject(value = "myFoo", defaultValue = "myDefault")
+        private String foo;
+
+        public String getName() {
+            return name;
+        }
+
+        public String getFoo() {
+            return foo;
+        }
+
+        public CamelLogger createLogger(String name) {
+            return new CamelLogger(name);
+        }
+    }
+
+    @Test
+    public void testBeanPostInjector() throws Exception {
+        MyService service = new MyService();
+
+        postProcessor.postProcessBeforeInitialization(service, "service");
+        postProcessor.postProcessAfterInitialization(service, "service");
+
+        Assertions.assertEquals("Donald Duck", service.getName());
+        Assertions.assertEquals("changed-foo", service.getFoo());
+
+        CamelLogger logger = (CamelLogger) context.getRegistry().lookupByName("createLogger");
+        Assertions.assertNotNull(logger);
+    }
+
+}

[camel] 11/11: camel-kamelet-main - Cleanup code

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-17571
in repository https://gitbox.apache.org/repos/asf/camel.git

commit ab841f64175f782bf60e556f459a17fbb9ededa1
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Mar 11 22:38:30 2022 +0100

    camel-kamelet-main - Cleanup code
---
 .../camel/main/DependencyDownloaderKamelet.java    | 111 +++++++++++++++++-
 .../org/apache/camel/main/KameletYamlRoutes.java   | 130 ---------------------
 2 files changed, 110 insertions(+), 131 deletions(-)

diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/DependencyDownloaderKamelet.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/DependencyDownloaderKamelet.java
index f4155e3..269088b 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/DependencyDownloaderKamelet.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/DependencyDownloaderKamelet.java
@@ -16,21 +16,36 @@
  */
 package org.apache.camel.main;
 
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
 import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
 import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.kamelet.KameletComponent;
+import org.apache.camel.dsl.yaml.YamlRoutesBuilderLoaderSupport;
 import org.apache.camel.spi.Resource;
 import org.apache.camel.spi.RouteTemplateLoaderListener;
 import org.apache.camel.support.service.ServiceHelper;
 import org.apache.camel.support.service.ServiceSupport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.snakeyaml.engine.v2.nodes.Node;
+import org.snakeyaml.engine.v2.nodes.NodeType;
+import org.snakeyaml.engine.v2.nodes.ScalarNode;
+import org.snakeyaml.engine.v2.nodes.SequenceNode;
+
+import static org.apache.camel.dsl.yaml.common.YamlDeserializerSupport.nodeAt;
 
 /**
  * To automatic downloaded dependencies that Kamelets requires.
  */
 final class DependencyDownloaderKamelet extends ServiceSupport implements CamelContextAware, RouteTemplateLoaderListener {
 
-    private final KameletYamlRoutes downloader = new KameletYamlRoutes("yaml");
+    private final KameletDependencyDownloader downloader = new KameletDependencyDownloader("yaml");
     private CamelContext camelContext;
 
     @Override
@@ -77,4 +92,98 @@ final class DependencyDownloaderKamelet extends ServiceSupport implements CamelC
             }
         }
     }
+
+    /**
+     * To automatic downloaded dependencies that Kamelets requires.
+     */
+    private static class KameletDependencyDownloader extends YamlRoutesBuilderLoaderSupport implements CamelContextAware {
+
+        private static final Logger LOG = LoggerFactory.getLogger(KameletDependencyDownloader.class);
+        private CamelContext camelContext;
+        private final Set<String> downloaded = new HashSet<>();
+
+        public KameletDependencyDownloader(String extension) {
+            super(extension);
+        }
+
+        @Override
+        public CamelContext getCamelContext() {
+            return camelContext;
+        }
+
+        @Override
+        public void setCamelContext(CamelContext camelContext) {
+            this.camelContext = camelContext;
+        }
+
+        @Override
+        protected RouteBuilder builder(Node node, Resource resource) {
+            final List<String> dependencies = new ArrayList<>();
+
+            Node deps = nodeAt(node, "/spec/dependencies");
+            if (deps != null && deps.getNodeType() == NodeType.SEQUENCE) {
+                SequenceNode sn = (SequenceNode) deps;
+                for (Node child : sn.getValue()) {
+                    if (child.getNodeType() == NodeType.SCALAR) {
+                        ScalarNode scn = (ScalarNode) child;
+                        String dep = scn.getValue();
+                        if (dep != null) {
+                            LOG.trace("Kamelet dependency: {}", dep);
+                            dependencies.add(dep);
+                        }
+                    }
+                }
+            }
+
+            downloadDependencies(dependencies);
+
+            // need to fool and return an empty route builder
+            return new RouteBuilder() {
+                @Override
+                public void configure() throws Exception {
+                    // noop
+                }
+            };
+        }
+
+        private void downloadDependencies(List<String> dependencies) {
+            final List<String> gavs = new ArrayList<>();
+            for (String dep : dependencies) {
+                String gav = dep;
+                if (dep.startsWith("camel:")) {
+                    // it's a known camel component
+                    gav = "org.apache.camel:camel-" + dep.substring(6) + ":" + camelContext.getVersion();
+                }
+                if (isValidGav(gav)) {
+                    gavs.add(gav);
+                }
+            }
+
+            if (!gavs.isEmpty()) {
+                for (String gav : gavs) {
+                    MavenGav mg = MavenGav.parseGav(camelContext, gav);
+                    DownloaderHelper.downloadDependency(camelContext, mg.getGroupId(), mg.getArtifactId(), mg.getVersion());
+                    downloaded.add(gav);
+                }
+            }
+        }
+
+        private boolean isValidGav(String gav) {
+            if (downloaded.contains(gav)) {
+                // already downloaded
+                return false;
+            }
+
+            // skip camel-core and camel-kamelet as they are already included
+            if (gav.contains("org.apache.camel:camel-core") || gav.contains("org.apache.camel:camel-kamelet:")) {
+                return false;
+            }
+
+            MavenGav mg = MavenGav.parseGav(camelContext, gav);
+            boolean exists = DownloaderHelper.alreadyOnClasspath(camelContext, mg.getArtifactId(), mg.getVersion());
+            // valid if not already on classpath
+            return !exists;
+        }
+
+    }
 }
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletYamlRoutes.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletYamlRoutes.java
deleted file mode 100644
index a57422c..0000000
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletYamlRoutes.java
+++ /dev/null
@@ -1,130 +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
- *
- *      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.main;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import org.apache.camel.CamelContext;
-import org.apache.camel.CamelContextAware;
-import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.dsl.yaml.YamlRoutesBuilderLoaderSupport;
-import org.apache.camel.spi.Resource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.snakeyaml.engine.v2.nodes.Node;
-import org.snakeyaml.engine.v2.nodes.NodeType;
-import org.snakeyaml.engine.v2.nodes.ScalarNode;
-import org.snakeyaml.engine.v2.nodes.SequenceNode;
-
-import static org.apache.camel.dsl.yaml.common.YamlDeserializerSupport.nodeAt;
-
-/**
- * Reuse the YAML DSL support for parsing Kamelets
- */
-class KameletYamlRoutes extends YamlRoutesBuilderLoaderSupport implements CamelContextAware {
-
-    private static final Logger LOG = LoggerFactory.getLogger(KameletYamlRoutes.class);
-    private CamelContext camelContext;
-    private final Set<String> downloaded = new HashSet<>();
-
-    public KameletYamlRoutes(String extension) {
-        super(extension);
-    }
-
-    @Override
-    public CamelContext getCamelContext() {
-        return camelContext;
-    }
-
-    @Override
-    public void setCamelContext(CamelContext camelContext) {
-        this.camelContext = camelContext;
-    }
-
-    @Override
-    protected RouteBuilder builder(Node node, Resource resource) {
-        final List<String> dependencies = new ArrayList<>();
-
-        Node deps = nodeAt(node, "/spec/dependencies");
-        if (deps != null && deps.getNodeType() == NodeType.SEQUENCE) {
-            SequenceNode sn = (SequenceNode) deps;
-            for (Node child : sn.getValue()) {
-                if (child.getNodeType() == NodeType.SCALAR) {
-                    ScalarNode scn = (ScalarNode) child;
-                    String dep = scn.getValue();
-                    if (dep != null) {
-                        LOG.trace("Kamelet dependency: {}", dep);
-                        dependencies.add(dep);
-                    }
-                }
-            }
-        }
-
-        downloadDependencies(dependencies);
-
-        // need to fool and return an empty route builder
-        return new RouteBuilder() {
-            @Override
-            public void configure() throws Exception {
-                // noop
-            }
-        };
-    }
-
-    private void downloadDependencies(List<String> dependencies) {
-        final List<String> gavs = new ArrayList<>();
-        for (String dep : dependencies) {
-            String gav = dep;
-            if (dep.startsWith("camel:")) {
-                // it's a known camel component
-                gav = "org.apache.camel:camel-" + dep.substring(6) + ":" + camelContext.getVersion();
-            }
-            if (isValidGav(gav)) {
-                gavs.add(gav);
-            }
-        }
-
-        if (!gavs.isEmpty()) {
-            for (String gav : gavs) {
-                MavenGav mg = MavenGav.parseGav(camelContext, gav);
-                DownloaderHelper.downloadDependency(camelContext, mg.getGroupId(), mg.getArtifactId(), mg.getVersion());
-                downloaded.add(gav);
-            }
-        }
-    }
-
-    private boolean isValidGav(String gav) {
-        if (downloaded.contains(gav)) {
-            // already downloaded
-            return false;
-        }
-
-        // skip camel-core and camel-kamelet as they are already included
-        if (gav.contains("org.apache.camel:camel-core") || gav.contains("org.apache.camel:camel-kamelet:")) {
-            return false;
-        }
-
-        MavenGav mg = MavenGav.parseGav(camelContext, gav);
-        boolean exists = DownloaderHelper.alreadyOnClasspath(camelContext, mg.getArtifactId(), mg.getVersion());
-        // valid if not already on classpath
-        return !exists;
-    }
-
-}

[camel] 05/11: CAMEL-17571: camel-jbang - Support for spring @Autowired/@Value annotations in custom beans

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-17571
in repository https://gitbox.apache.org/repos/asf/camel.git

commit a46c8e7c5bcba5f7fb834d48cb9f42b94e8244fd
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Mar 11 13:03:30 2022 +0100

    CAMEL-17571: camel-jbang - Support for spring @Autowired/@Value annotations in custom beans
---
 .../apache/camel/spi/CamelBeanPostProcessor.java   |  9 +++++
 .../camel/spi/CamelBeanPostProcessorInjector.java  | 32 +++++++++++++++
 .../impl/engine/DefaultCamelBeanPostProcessor.java | 17 ++++++++
 dsl/camel-kamelet-main/pom.xml                     | 10 ++++-
 .../apache/camel/main/SpringAnnotationSupport.java | 46 ++++++++++++++++++++++
 5 files changed, 113 insertions(+), 1 deletion(-)

diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/CamelBeanPostProcessor.java b/core/camel-api/src/main/java/org/apache/camel/spi/CamelBeanPostProcessor.java
index 0308f54..1fff611 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/CamelBeanPostProcessor.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/CamelBeanPostProcessor.java
@@ -83,4 +83,13 @@ public interface CamelBeanPostProcessor {
         return false;
     }
 
+    /**
+     * Adds a custom bean post injector
+     *
+     * @param injector the custom injector
+     */
+    default void addCamelBeanPostProjectInjector(CamelBeanPostProcessorInjector injector) {
+        // noop
+    }
+
 }
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/CamelBeanPostProcessorInjector.java b/core/camel-api/src/main/java/org/apache/camel/spi/CamelBeanPostProcessorInjector.java
new file mode 100644
index 0000000..51febcf
--- /dev/null
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/CamelBeanPostProcessorInjector.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;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * Used for custom injection when doing {@link CamelBeanPostProcessor} bean post-processing. Can be used to support
+ * 3rd-party annotations for dependenct injections.
+ */
+public interface CamelBeanPostProcessorInjector {
+
+    void onFieldInject(Field field, Object bean, String beanName);
+
+    void onFieldMethod(Method method, Object bean, String beanName);
+
+}
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelBeanPostProcessor.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelBeanPostProcessor.java
index 3a74646..53fab39 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelBeanPostProcessor.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelBeanPostProcessor.java
@@ -37,6 +37,7 @@ import org.apache.camel.Produce;
 import org.apache.camel.PropertyInject;
 import org.apache.camel.TypeConverter;
 import org.apache.camel.spi.CamelBeanPostProcessor;
+import org.apache.camel.spi.CamelBeanPostProcessorInjector;
 import org.apache.camel.spi.Registry;
 import org.apache.camel.support.DefaultEndpoint;
 import org.apache.camel.util.ReflectionHelper;
@@ -65,6 +66,7 @@ import static org.apache.camel.util.ObjectHelper.isEmpty;
 public class DefaultCamelBeanPostProcessor implements CamelBeanPostProcessor, CamelContextAware {
 
     protected static final Logger LOG = LoggerFactory.getLogger(DefaultCamelBeanPostProcessor.class);
+    protected final List<CamelBeanPostProcessorInjector> beanPostProcessorInjectors = new ArrayList<>();
     protected CamelPostProcessorHelper camelPostProcessorHelper;
     protected CamelContext camelContext;
     protected boolean enabled = true;
@@ -106,6 +108,11 @@ public class DefaultCamelBeanPostProcessor implements CamelBeanPostProcessor, Ca
     }
 
     @Override
+    public void addCamelBeanPostProjectInjector(CamelBeanPostProcessorInjector injector) {
+        this.beanPostProcessorInjectors.add(injector);
+    }
+
+    @Override
     public Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception {
         LOG.trace("Camel bean processing before initialization for bean: {}", beanName);
 
@@ -268,6 +275,11 @@ public class DefaultCamelBeanPostProcessor implements CamelBeanPostProcessor, Ca
                 String uri = produce.value().isEmpty() ? produce.uri() : produce.value();
                 injectField(field, uri, produce.property(), bean, beanName, produce.binding());
             }
+
+            // custom bean injector on the field
+            for (CamelBeanPostProcessorInjector injector : beanPostProcessorInjectors) {
+                injector.onFieldInject(field, bean, beanName);
+            }
         });
     }
 
@@ -323,6 +335,11 @@ public class DefaultCamelBeanPostProcessor implements CamelBeanPostProcessor, Ca
 
             setterInjection(method, bean, beanName);
             getPostProcessorHelper().consumerInjection(method, bean, beanName);
+
+            // custom bean injector on the method
+            for (CamelBeanPostProcessorInjector injector : beanPostProcessorInjectors) {
+                injector.onFieldMethod(method, bean, beanName);
+            }
         });
     }
 
diff --git a/dsl/camel-kamelet-main/pom.xml b/dsl/camel-kamelet-main/pom.xml
index 0236a5f..899e154 100644
--- a/dsl/camel-kamelet-main/pom.xml
+++ b/dsl/camel-kamelet-main/pom.xml
@@ -113,7 +113,15 @@
             <exclusions>
                 <exclusion>
                     <groupId>org.springframework</groupId>
-                    <artifactId>*</artifactId>
+                    <artifactId>spring-aop</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.springframework</groupId>
+                    <artifactId>spring-core</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.springframework</groupId>
+                    <artifactId>spring-expression</artifactId>
                 </exclusion>
             </exclusions>
         </dependency>
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java
index 26392b0..0f0e8a9 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java
@@ -16,11 +16,20 @@
  */
 package org.apache.camel.main;
 
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
 import org.apache.camel.CamelContext;
 import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.dsl.support.CompilePostProcessor;
+import org.apache.camel.impl.engine.CamelPostProcessorHelper;
 import org.apache.camel.spi.CamelBeanPostProcessor;
+import org.apache.camel.spi.CamelBeanPostProcessorInjector;
 import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.ReflectionHelper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Service;
 
@@ -31,6 +40,8 @@ public final class SpringAnnotationSupport {
 
     public static void registerSpringSupport(CamelContext context) {
         context.getRegistry().bind("SpringAnnotationCompilePostProcessor", new SpringAnnotationCompilePostProcessor());
+        context.adapt(ExtendedCamelContext.class).getBeanPostProcessor()
+                .addCamelBeanPostProjectInjector(new SpringBeanPostProcessorInjector(context));
     }
 
     private static class SpringAnnotationCompilePostProcessor implements CompilePostProcessor {
@@ -62,4 +73,39 @@ public final class SpringAnnotationSupport {
             }
         }
     }
+
+    private static class SpringBeanPostProcessorInjector implements CamelBeanPostProcessorInjector {
+
+        private final CamelContext context;
+        private final CamelPostProcessorHelper helper;
+
+        public SpringBeanPostProcessorInjector(CamelContext context) {
+            this.context = context;
+            this.helper = new CamelPostProcessorHelper(context);
+        }
+
+        @Override
+        public void onFieldInject(Field field, Object bean, String beanName) {
+            Autowired autowired = field.getAnnotation(Autowired.class);
+            if (autowired != null) {
+                String name = null;
+                Qualifier qualifier = field.getAnnotation(Qualifier.class);
+                if (qualifier != null) {
+                    name = qualifier.value();
+                }
+                ReflectionHelper.setField(field, bean,
+                        helper.getInjectionBeanValue(field.getType(), name));
+            }
+            Value value = field.getAnnotation(Value.class);
+            if (value != null) {
+                ReflectionHelper.setField(field, bean,
+                        helper.getInjectionPropertyValue(field.getType(), value.value(), null, null, bean, beanName));
+            }
+        }
+
+        @Override
+        public void onFieldMethod(Method method, Object bean, String beanName) {
+
+        }
+    }
 }

[camel] 01/11: CAMEL-17571: camel-dsl - Allow to register custom annotation processors that can do custom logic after a DSL has compiled source into Java object.

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-17571
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 347d531a6a8532beb24fa5f2e1143b44885656b1
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Mar 11 10:24:38 2022 +0100

    CAMEL-17571: camel-dsl - Allow to register custom annotation processors that can do custom logic after a DSL has compiled source into Java object.
---
 .../camel/dsl/support/AnnotationPreProcessor.java  |  35 +++++++
 .../dsl/support/RouteBuilderLoaderSupport.java     |  35 +++++++
 .../dsl/java/joor/JavaRoutesBuilderLoader.java     | 106 +++++++++++++--------
 .../apache/camel/main/SpringAnnotationSupport.java |   2 +
 4 files changed, 137 insertions(+), 41 deletions(-)

diff --git a/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/AnnotationPreProcessor.java b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/AnnotationPreProcessor.java
new file mode 100644
index 0000000..2c0499a
--- /dev/null
+++ b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/AnnotationPreProcessor.java
@@ -0,0 +1,35 @@
+/*
+ * 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.dsl.support;
+
+import org.apache.camel.CamelContext;
+
+/**
+ * Allows to plugin custom annotation pre-processors that are processed after the DSL has loaded the source and compiled
+ * into a Java object.
+ * <p/>
+ * This is used to detect and handle {@link org.apache.camel.BindToRegistry} and {@link org.apache.camel.TypeConverter}
+ * classes.
+ */
+public interface AnnotationPreProcessor {
+
+    void handleAnnotation(
+            CamelContext camelContext, String name,
+            Class<?> clazz, Object instance)
+            throws Exception;
+
+}
diff --git a/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java
index 11fbc8f..5e93d15 100644
--- a/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java
+++ b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java
@@ -16,6 +16,10 @@
  */
 package org.apache.camel.dsl.support;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
 import org.apache.camel.CamelContextAware;
 import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.RoutesBuilder;
@@ -35,6 +39,7 @@ public abstract class RouteBuilderLoaderSupport extends RoutesBuilderLoaderSuppo
     private final String extension;
 
     private StartupStepRecorder recorder;
+    private final List<AnnotationPreProcessor> annotationPreProcessors = new ArrayList<>();
 
     protected RouteBuilderLoaderSupport(String extension) {
         this.extension = extension;
@@ -46,6 +51,21 @@ public abstract class RouteBuilderLoaderSupport extends RoutesBuilderLoaderSuppo
         return extension;
     }
 
+    /**
+     * Gets the registered {@link AnnotationPreProcessor}.
+     */
+    public List<AnnotationPreProcessor> getAnnotationPreProcessors() {
+        return annotationPreProcessors;
+    }
+
+    /**
+     * Add a custom {@link AnnotationPreProcessor} to handle specific annotations after compiling the source into a Java
+     * object.
+     */
+    public void addAnnotationPreProcessor(AnnotationPreProcessor preProcessor) {
+        this.annotationPreProcessors.add(preProcessor);
+    }
+
     @Override
     protected void doBuild() throws Exception {
         super.doBuild();
@@ -56,6 +76,21 @@ public abstract class RouteBuilderLoaderSupport extends RoutesBuilderLoaderSuppo
     }
 
     @Override
+    protected void doStart() throws Exception {
+        super.doStart();
+
+        if (getCamelContext() != null) {
+            // discover optional pre-processors to be used
+            Set<AnnotationPreProcessor> pres = getCamelContext().getRegistry().findByType(AnnotationPreProcessor.class);
+            if (pres != null && !pres.isEmpty()) {
+                for (AnnotationPreProcessor pre : pres) {
+                    addAnnotationPreProcessor(pre);
+                }
+            }
+        }
+    }
+
+    @Override
     public RoutesBuilder loadRoutesBuilder(Resource resource) throws Exception {
         final RouteBuilder builder = doLoadRouteBuilder(resource);
         if (builder != null) {
diff --git a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
index dd149db..baad4ee 100644
--- a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
+++ b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
@@ -23,6 +23,7 @@ import java.util.regex.Pattern;
 
 import org.apache.camel.BindToRegistry;
 import org.apache.camel.CamelConfiguration;
+import org.apache.camel.CamelContext;
 import org.apache.camel.Configuration;
 import org.apache.camel.Converter;
 import org.apache.camel.ExtendedCamelContext;
@@ -30,6 +31,7 @@ import org.apache.camel.LoggingLevel;
 import org.apache.camel.TypeConverterExists;
 import org.apache.camel.api.management.ManagedResource;
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.dsl.support.AnnotationPreProcessor;
 import org.apache.camel.dsl.support.RouteBuilderLoaderSupport;
 import org.apache.camel.spi.CamelBeanPostProcessor;
 import org.apache.camel.spi.Resource;
@@ -50,6 +52,9 @@ public class JavaRoutesBuilderLoader extends RouteBuilderLoaderSupport {
 
     public JavaRoutesBuilderLoader() {
         super(EXTENSION);
+
+        addAnnotationPreProcessor(new ConverterAnnotationPreProcessor());
+        addAnnotationPreProcessor(new BindToRegistryAnnotationPreProcessor());
     }
 
     @Override
@@ -64,51 +69,16 @@ public class JavaRoutesBuilderLoader extends RouteBuilderLoaderSupport {
             Reflect ref = Reflect.compile(name, content).create();
             Class<?> clazz = ref.type();
 
-            if (clazz.getAnnotation(Converter.class) != null) {
-                TypeConverterRegistry tcr = getCamelContext().getTypeConverterRegistry();
-                TypeConverterExists exists = tcr.getTypeConverterExists();
-                LoggingLevel level = tcr.getTypeConverterExistsLoggingLevel();
-                // force type converter to override as we could be re-loading
-                tcr.setTypeConverterExists(TypeConverterExists.Override);
-                tcr.setTypeConverterExistsLoggingLevel(LoggingLevel.OFF);
-                try {
-                    tcr.addTypeConverters(clazz);
-                } finally {
-                    tcr.setTypeConverterExists(exists);
-                    tcr.setTypeConverterExistsLoggingLevel(level);
-                }
-                return null;
-            }
-
             Object obj = ref.get();
             if (obj instanceof RouteBuilder) {
                 return (RouteBuilder) obj;
-            } else if (obj != null) {
-                BindToRegistry bir = obj.getClass().getAnnotation(BindToRegistry.class);
-                Configuration cfg = obj.getClass().getAnnotation(Configuration.class);
-                if (bir != null || cfg != null || obj instanceof CamelConfiguration) {
-                    CamelBeanPostProcessor bpp = getCamelContext().adapt(ExtendedCamelContext.class).getBeanPostProcessor();
-                    if (bir != null && ObjectHelper.isNotEmpty(bir.value())) {
-                        name = bir.value();
-                    } else if (cfg != null && ObjectHelper.isNotEmpty(cfg.value())) {
-                        name = cfg.value();
-                    }
-                    // to support hot reloading of beans then we need to enable unbind mode in bean post processor
-                    bpp.setUnbindEnabled(true);
-                    try {
-                        // this class is a bean service which needs to be post processed and registered which happens
-                        // automatic by the bean post processor
-                        bpp.postProcessBeforeInitialization(obj, name);
-                        bpp.postProcessAfterInitialization(obj, name);
-                    } finally {
-                        bpp.setUnbindEnabled(false);
-                    }
-                    if (obj instanceof CamelConfiguration) {
-                        ((CamelConfiguration) obj).configure(getCamelContext());
-                    }
-                    return null;
-                }
             }
+
+            // not a route builder but we support annotation scan to register custom beans, type converters, etc.
+            for (AnnotationPreProcessor pre : getAnnotationPreProcessors()) {
+                pre.handleAnnotation(getCamelContext(), name, clazz, obj);
+            }
+
             return null;
         }
     }
@@ -127,4 +97,58 @@ public class JavaRoutesBuilderLoader extends RouteBuilderLoaderSupport {
                 ? matcher.group(1) + "." + name
                 : name;
     }
+
+    private static class ConverterAnnotationPreProcessor implements AnnotationPreProcessor {
+
+        @Override
+        public void handleAnnotation(CamelContext camelContext, String name, Class<?> clazz, Object instance) {
+            if (clazz.getAnnotation(Converter.class) != null) {
+                TypeConverterRegistry tcr = camelContext.getTypeConverterRegistry();
+                TypeConverterExists exists = tcr.getTypeConverterExists();
+                LoggingLevel level = tcr.getTypeConverterExistsLoggingLevel();
+                // force type converter to override as we could be re-loading
+                tcr.setTypeConverterExists(TypeConverterExists.Override);
+                tcr.setTypeConverterExistsLoggingLevel(LoggingLevel.OFF);
+                try {
+                    tcr.addTypeConverters(clazz);
+                } finally {
+                    tcr.setTypeConverterExists(exists);
+                    tcr.setTypeConverterExistsLoggingLevel(level);
+                }
+            }
+        }
+    }
+
+    private static class BindToRegistryAnnotationPreProcessor implements AnnotationPreProcessor {
+
+        @Override
+        public void handleAnnotation(CamelContext camelContext, String name, Class<?> clazz, Object instance)
+                throws Exception {
+            BindToRegistry bir = instance.getClass().getAnnotation(BindToRegistry.class);
+            Configuration cfg = instance.getClass().getAnnotation(Configuration.class);
+            if (bir != null || cfg != null || instance instanceof CamelConfiguration) {
+                CamelBeanPostProcessor bpp = camelContext.adapt(ExtendedCamelContext.class).getBeanPostProcessor();
+                if (bir != null && ObjectHelper.isNotEmpty(bir.value())) {
+                    name = bir.value();
+                } else if (cfg != null && ObjectHelper.isNotEmpty(cfg.value())) {
+                    name = cfg.value();
+                }
+                // to support hot reloading of beans then we need to enable unbind mode in bean post processor
+                bpp.setUnbindEnabled(true);
+                try {
+                    // this class is a bean service which needs to be post processed and registered which happens
+                    // automatic by the bean post processor
+                    bpp.postProcessBeforeInitialization(instance, name);
+                    bpp.postProcessAfterInitialization(instance, name);
+                } finally {
+                    bpp.setUnbindEnabled(false);
+                }
+                if (instance instanceof CamelConfiguration) {
+                    ((CamelConfiguration) instance).configure(camelContext);
+                }
+            }
+        }
+
+    }
+
 }
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java
new file mode 100644
index 0000000..1682402
--- /dev/null
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java
@@ -0,0 +1,2 @@
+package org.apache.camel.main;public class SpringAnnotationSupport {
+}

[camel] 03/11: CAMEL-17571: camel-dsl - Allow to register custom annotation processors that can do custom logic after a DSL has compiled source into Java object.

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-17571
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 1e2f796c5eba327aa6e03afb20e0752e278c856e
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Mar 11 11:01:16 2022 +0100

    CAMEL-17571: camel-dsl - Allow to register custom annotation processors that can do custom logic after a DSL has compiled source into Java object.
---
 ...PreProcessor.java => CompilePostProcessor.java} | 19 ++++++++++++++-----
 .../dsl/support/RouteBuilderLoaderSupport.java     | 22 +++++++++++-----------
 .../dsl/java/joor/JavaRoutesBuilderLoader.java     | 19 +++++++++----------
 .../apache/camel/main/SpringAnnotationSupport.java |  8 ++++----
 4 files changed, 38 insertions(+), 30 deletions(-)

diff --git a/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/AnnotationPreProcessor.java b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/CompilePostProcessor.java
similarity index 64%
rename from dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/AnnotationPreProcessor.java
rename to dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/CompilePostProcessor.java
index 2c0499a..021a97f 100644
--- a/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/AnnotationPreProcessor.java
+++ b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/CompilePostProcessor.java
@@ -19,15 +19,24 @@ package org.apache.camel.dsl.support;
 import org.apache.camel.CamelContext;
 
 /**
- * Allows to plugin custom annotation pre-processors that are processed after the DSL has loaded the source and compiled
- * into a Java object.
+ * Allows to plugin custom post processors that are processed after the DSL has loaded the source and compiled into a
+ * Java object.
  * <p/>
- * This is used to detect and handle {@link org.apache.camel.BindToRegistry} and {@link org.apache.camel.TypeConverter}
+ * This is used to detect and handle {@link org.apache.camel.BindToRegistry} and {@link org.apache.camel.Converter}
  * classes.
  */
-public interface AnnotationPreProcessor {
+public interface CompilePostProcessor {
 
-    void handleAnnotation(
+    /**
+     * Invoked after the class has been compiled
+     *
+     * @param  camelContext the camel context
+     * @param  name         the name of the resource/class
+     * @param  clazz        the class
+     * @param  instance     the object created as instance of the class (if any)
+     * @throws Exception    is thrown if error during post-processing
+     */
+    void postCompile(
             CamelContext camelContext, String name,
             Class<?> clazz, Object instance)
             throws Exception;
diff --git a/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java
index 5e93d15..0b3dae8 100644
--- a/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java
+++ b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java
@@ -39,7 +39,7 @@ public abstract class RouteBuilderLoaderSupport extends RoutesBuilderLoaderSuppo
     private final String extension;
 
     private StartupStepRecorder recorder;
-    private final List<AnnotationPreProcessor> annotationPreProcessors = new ArrayList<>();
+    private final List<CompilePostProcessor> compilePostProcessors = new ArrayList<>();
 
     protected RouteBuilderLoaderSupport(String extension) {
         this.extension = extension;
@@ -52,18 +52,18 @@ public abstract class RouteBuilderLoaderSupport extends RoutesBuilderLoaderSuppo
     }
 
     /**
-     * Gets the registered {@link AnnotationPreProcessor}.
+     * Gets the registered {@link CompilePostProcessor}.
      */
-    public List<AnnotationPreProcessor> getAnnotationPreProcessors() {
-        return annotationPreProcessors;
+    public List<CompilePostProcessor> getCompilePostProcessors() {
+        return compilePostProcessors;
     }
 
     /**
-     * Add a custom {@link AnnotationPreProcessor} to handle specific annotations after compiling the source into a Java
-     * object.
+     * Add a custom {@link CompilePostProcessor} to handle specific post-processing after compiling the source into a
+     * Java object.
      */
-    public void addAnnotationPreProcessor(AnnotationPreProcessor preProcessor) {
-        this.annotationPreProcessors.add(preProcessor);
+    public void addCompilePostProcessor(CompilePostProcessor preProcessor) {
+        this.compilePostProcessors.add(preProcessor);
     }
 
     @Override
@@ -81,10 +81,10 @@ public abstract class RouteBuilderLoaderSupport extends RoutesBuilderLoaderSuppo
 
         if (getCamelContext() != null) {
             // discover optional pre-processors to be used
-            Set<AnnotationPreProcessor> pres = getCamelContext().getRegistry().findByType(AnnotationPreProcessor.class);
+            Set<CompilePostProcessor> pres = getCamelContext().getRegistry().findByType(CompilePostProcessor.class);
             if (pres != null && !pres.isEmpty()) {
-                for (AnnotationPreProcessor pre : pres) {
-                    addAnnotationPreProcessor(pre);
+                for (CompilePostProcessor pre : pres) {
+                    addCompilePostProcessor(pre);
                 }
             }
         }
diff --git a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
index baad4ee..a407559 100644
--- a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
+++ b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
@@ -31,7 +31,7 @@ import org.apache.camel.LoggingLevel;
 import org.apache.camel.TypeConverterExists;
 import org.apache.camel.api.management.ManagedResource;
 import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.dsl.support.AnnotationPreProcessor;
+import org.apache.camel.dsl.support.CompilePostProcessor;
 import org.apache.camel.dsl.support.RouteBuilderLoaderSupport;
 import org.apache.camel.spi.CamelBeanPostProcessor;
 import org.apache.camel.spi.Resource;
@@ -53,8 +53,8 @@ public class JavaRoutesBuilderLoader extends RouteBuilderLoaderSupport {
     public JavaRoutesBuilderLoader() {
         super(EXTENSION);
 
-        addAnnotationPreProcessor(new ConverterAnnotationPreProcessor());
-        addAnnotationPreProcessor(new BindToRegistryAnnotationPreProcessor());
+        addCompilePostProcessor(new ConverterCompilePostProcessor());
+        addCompilePostProcessor(new BindToRegistryCompilePostProcessor());
     }
 
     @Override
@@ -75,8 +75,8 @@ public class JavaRoutesBuilderLoader extends RouteBuilderLoaderSupport {
             }
 
             // not a route builder but we support annotation scan to register custom beans, type converters, etc.
-            for (AnnotationPreProcessor pre : getAnnotationPreProcessors()) {
-                pre.handleAnnotation(getCamelContext(), name, clazz, obj);
+            for (CompilePostProcessor pre : getCompilePostProcessors()) {
+                pre.postCompile(getCamelContext(), name, clazz, obj);
             }
 
             return null;
@@ -98,10 +98,10 @@ public class JavaRoutesBuilderLoader extends RouteBuilderLoaderSupport {
                 : name;
     }
 
-    private static class ConverterAnnotationPreProcessor implements AnnotationPreProcessor {
+    private static class ConverterCompilePostProcessor implements CompilePostProcessor {
 
         @Override
-        public void handleAnnotation(CamelContext camelContext, String name, Class<?> clazz, Object instance) {
+        public void postCompile(CamelContext camelContext, String name, Class<?> clazz, Object instance) throws Exception {
             if (clazz.getAnnotation(Converter.class) != null) {
                 TypeConverterRegistry tcr = camelContext.getTypeConverterRegistry();
                 TypeConverterExists exists = tcr.getTypeConverterExists();
@@ -119,11 +119,10 @@ public class JavaRoutesBuilderLoader extends RouteBuilderLoaderSupport {
         }
     }
 
-    private static class BindToRegistryAnnotationPreProcessor implements AnnotationPreProcessor {
+    private static class BindToRegistryCompilePostProcessor implements CompilePostProcessor {
 
         @Override
-        public void handleAnnotation(CamelContext camelContext, String name, Class<?> clazz, Object instance)
-                throws Exception {
+        public void postCompile(CamelContext camelContext, String name, Class<?> clazz, Object instance) throws Exception {
             BindToRegistry bir = instance.getClass().getAnnotation(BindToRegistry.class);
             Configuration cfg = instance.getClass().getAnnotation(Configuration.class);
             if (bir != null || cfg != null || instance instanceof CamelConfiguration) {
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java
index 22a185b..26392b0 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java
@@ -18,7 +18,7 @@ package org.apache.camel.main;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.ExtendedCamelContext;
-import org.apache.camel.dsl.support.AnnotationPreProcessor;
+import org.apache.camel.dsl.support.CompilePostProcessor;
 import org.apache.camel.spi.CamelBeanPostProcessor;
 import org.apache.camel.util.ObjectHelper;
 import org.springframework.stereotype.Component;
@@ -30,13 +30,13 @@ public final class SpringAnnotationSupport {
     }
 
     public static void registerSpringSupport(CamelContext context) {
-        context.getRegistry().bind("SpringAnnotationPreProcessor", new SpringAnnotationPreProcessor());
+        context.getRegistry().bind("SpringAnnotationCompilePostProcessor", new SpringAnnotationCompilePostProcessor());
     }
 
-    private static class SpringAnnotationPreProcessor implements AnnotationPreProcessor {
+    private static class SpringAnnotationCompilePostProcessor implements CompilePostProcessor {
 
         @Override
-        public void handleAnnotation(CamelContext camelContext, String name, Class<?> clazz, Object instance) throws Exception {
+        public void postCompile(CamelContext camelContext, String name, Class<?> clazz, Object instance) throws Exception {
             // @Component and @Service are the same
             Component comp = clazz.getAnnotation(Component.class);
             Service service = clazz.getAnnotation(Service.class);

[camel] 06/11: CAMEL-17571: camel-jbang - Support for spring @Autowired/@Value annotations in custom beans

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-17571
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 5a5ef74b7beabcf67968d3f556bda5079da53b4d
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Mar 11 13:08:15 2022 +0100

    CAMEL-17571: camel-jbang - Support for spring @Autowired/@Value annotations in custom beans
---
 .../camel/spi/CamelBeanPostProcessorInjector.java      | 18 ++++++++++++++++--
 .../impl/engine/DefaultCamelBeanPostProcessor.java     |  2 +-
 .../org/apache/camel/main/SpringAnnotationSupport.java | 17 +++++++++++++----
 3 files changed, 30 insertions(+), 7 deletions(-)

diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/CamelBeanPostProcessorInjector.java b/core/camel-api/src/main/java/org/apache/camel/spi/CamelBeanPostProcessorInjector.java
index 51febcf..6c70ab2 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/CamelBeanPostProcessorInjector.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/CamelBeanPostProcessorInjector.java
@@ -21,12 +21,26 @@ import java.lang.reflect.Method;
 
 /**
  * Used for custom injection when doing {@link CamelBeanPostProcessor} bean post-processing. Can be used to support
- * 3rd-party annotations for dependenct injections.
+ * 3rd-party annotations for dependency injections.
  */
 public interface CamelBeanPostProcessorInjector {
 
+    /**
+     * Field injection
+     *
+     * @param field    the field
+     * @param bean     the bean instance where the field is present
+     * @param beanName optional bean id of the bean
+     */
     void onFieldInject(Field field, Object bean, String beanName);
 
-    void onFieldMethod(Method method, Object bean, String beanName);
+    /**
+     * Method injection
+     *
+     * @param method   the method
+     * @param bean     the bean instance where the method is present
+     * @param beanName optional bean id of the bean
+     */
+    void onMethodInject(Method method, Object bean, String beanName);
 
 }
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelBeanPostProcessor.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelBeanPostProcessor.java
index 53fab39..15ad1af 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelBeanPostProcessor.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelBeanPostProcessor.java
@@ -338,7 +338,7 @@ public class DefaultCamelBeanPostProcessor implements CamelBeanPostProcessor, Ca
 
             // custom bean injector on the method
             for (CamelBeanPostProcessorInjector injector : beanPostProcessorInjectors) {
-                injector.onFieldMethod(method, bean, beanName);
+                injector.onMethodInject(method, bean, beanName);
             }
         });
     }
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java
index 0f0e8a9..1186ccd 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java
@@ -21,6 +21,7 @@ import java.lang.reflect.Method;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.NoSuchBeanException;
 import org.apache.camel.dsl.support.CompilePostProcessor;
 import org.apache.camel.impl.engine.CamelPostProcessorHelper;
 import org.apache.camel.spi.CamelBeanPostProcessor;
@@ -93,8 +94,16 @@ public final class SpringAnnotationSupport {
                 if (qualifier != null) {
                     name = qualifier.value();
                 }
-                ReflectionHelper.setField(field, bean,
-                        helper.getInjectionBeanValue(field.getType(), name));
+
+                try {
+                    ReflectionHelper.setField(field, bean,
+                            helper.getInjectionBeanValue(field.getType(), name));
+                } catch (NoSuchBeanException e) {
+                    if (autowired.required()) {
+                        throw e;
+                    }
+                    // not required so ignore
+                }
             }
             Value value = field.getAnnotation(Value.class);
             if (value != null) {
@@ -104,8 +113,8 @@ public final class SpringAnnotationSupport {
         }
 
         @Override
-        public void onFieldMethod(Method method, Object bean, String beanName) {
-
+        public void onMethodInject(Method method, Object bean, String beanName) {
+            // TODO; @Bean
         }
     }
 }

[camel] 08/11: CAMEL-17571: camel-jbang - Support for spring @Bean annotations in custom beans

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-17571
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 5334e55938022b8da6bbc8dc9e576255c1ea137a
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Mar 11 22:04:00 2022 +0100

    CAMEL-17571: camel-jbang - Support for spring @Bean annotations in custom beans
---
 .../src/main/java/org/apache/camel/main/SpringAnnotationSupport.java   | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java
index 881e4b3..120d963 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/SpringAnnotationSupport.java
@@ -35,6 +35,9 @@ import org.springframework.context.annotation.Bean;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Service;
 
+/**
+ * To support spring based annotations such as @Component/@Service, @Autowired/@Qualifier, @Value, and @Bean.
+ */
 public final class SpringAnnotationSupport {
 
     private SpringAnnotationSupport() {