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

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

commit 46d568f11e7018f856205316f84b769b054ad7bb
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Thu May 23 11:51:39 2019 +0200

    CAMEL-13557: Add property binding support to make it convenient to 
configure components and whatnot.
---
 .../org/apache/camel/PropertyBindingException.java |   6 ++
 .../java/org/apache/camel/main/MainSupport.java    |  58 +----------
 .../PropertyBindingSupportAutowireTest.java        | 107 +++++++++++++++++++++
 .../camel/support/PropertyBindingSupport.java      |  89 ++++++++++++++++-
 4 files changed, 203 insertions(+), 57 deletions(-)

diff --git 
a/core/camel-api/src/main/java/org/apache/camel/PropertyBindingException.java 
b/core/camel-api/src/main/java/org/apache/camel/PropertyBindingException.java
index ed6e61b..fdc9005 100644
--- 
a/core/camel-api/src/main/java/org/apache/camel/PropertyBindingException.java
+++ 
b/core/camel-api/src/main/java/org/apache/camel/PropertyBindingException.java
@@ -36,6 +36,12 @@ public class PropertyBindingException extends 
RuntimeCamelException {
         this.propertyName = propertyName;
     }
 
+    public PropertyBindingException(Object target, Exception e) {
+        super("Error binding properties on bean: " + target, e);
+        this.target = target;
+        this.propertyName = null;
+    }
+
     public Object getTarget() {
         return target;
     }
diff --git 
a/core/camel-core/src/main/java/org/apache/camel/main/MainSupport.java 
b/core/camel-core/src/main/java/org/apache/camel/main/MainSupport.java
index 4a249dc..a20623b 100644
--- a/core/camel-core/src/main/java/org/apache/camel/main/MainSupport.java
+++ b/core/camel-core/src/main/java/org/apache/camel/main/MainSupport.java
@@ -21,7 +21,6 @@ import java.io.FileInputStream;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
@@ -81,7 +80,6 @@ import org.apache.camel.spi.StreamCachingStrategy;
 import org.apache.camel.spi.ThreadPoolProfile;
 import org.apache.camel.spi.UnitOfWorkFactory;
 import org.apache.camel.spi.UuidGenerator;
-import org.apache.camel.support.IntrospectionSupport;
 import org.apache.camel.support.LifecycleStrategySupport;
 import org.apache.camel.support.PropertyBindingSupport;
 import org.apache.camel.support.jsse.GlobalSSLContextParametersSupplier;
@@ -1255,62 +1253,10 @@ public abstract class MainSupport extends 
ServiceSupport {
         camelContext.addLifecycleStrategy(new LifecycleStrategySupport() {
             @Override
             public void onComponentAdd(String name, Component component) {
-                // when adding a component then support auto-configuring 
complex types
-                // by looking up from registry, such as DataSource etc
-                Map<String, Object> properties = new LinkedHashMap<>();
-                IntrospectionSupport.getProperties(component, properties, 
null);
-
-                // TODO: Use PropertyBindingSupport to make it support this 
kind of use-case too
-                // TODO: Allow nested properties too
-                // TODO: Allow fluent builders
-
-                // lookup complex types
-                properties.forEach((k, v) -> {
-                    // if the property has not been set and its a complex type 
(not simple or string etc)
-                    Class type = getGetterType(component, k);
-                    if (isComplexType(type)) {
-                        Set lookup = findExplicitBindingByType(camelContext, 
type);
-                        if (lookup.size() == 1) {
-                            v = lookup.iterator().next();
-                            try {
-                                LOG.info("Auto configuring option: {} on 
component: {} as one instance of type: {} registered in the Camel Registry", k, 
name, type.getName());
-                                IntrospectionSupport.setProperty(camelContext, 
component, k, v);
-                            } catch (Exception e) {
-                                LOG.warn("Cannot auto configure option: " + k 
+ " on component: " + name + " due to " + e.getMessage());
-                            }
-                        }
-                    }
+                
PropertyBindingSupport.autowireSingletonPropertiesFromRegistry(camelContext, 
component, false, (obj, propertyName, type, value) -> {
+                    LOG.info("Auto configuring option: {} on component: {} as 
one instance of type: {} registered in the Camel Registry", propertyName, obj, 
type.getName());
                 });
             }
-
-            /**
-             * Finds any explicit bean bindings that has been added to the 
registry.
-             * This means that if there are any, then they have been added by 
the end user
-             * and we should favour using the bean if there is a single 
instance bound for the type.
-             */
-            private Set findExplicitBindingByType(CamelContext camelContext, 
Class type) {
-                if (camelContext.getRegistry() instanceof MainRegistry) {
-                    return ((MainRegistry) 
camelContext.getRegistry()).findBindingsByType(type);
-                }
-                return Collections.EMPTY_SET;
-            }
-
-            private boolean isComplexType(Class type) {
-                // lets consider all non java as complex types
-                return type != null && !type.isPrimitive() && 
!type.getName().startsWith("java");
-            }
-
-            private Class getGetterType(Component component, String key) {
-                try {
-                    Method getter = 
IntrospectionSupport.getPropertyGetter(component.getClass(), key);
-                    if (getter != null) {
-                        return getter.getReturnType();
-                    }
-                } catch (NoSuchMethodException e) {
-                    // ignore
-                }
-                return null;
-            }
         });
     }
 
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/support/PropertyBindingSupportAutowireTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/support/PropertyBindingSupportAutowireTest.java
new file mode 100644
index 0000000..5b33d61
--- /dev/null
+++ 
b/core/camel-core/src/test/java/org/apache/camel/support/PropertyBindingSupportAutowireTest.java
@@ -0,0 +1,107 @@
+/*
+ * 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.support;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ContextTestSupport;
+import org.junit.Test;
+
+/**
+ * Unit test for PropertyBindingSupport
+ */
+public class PropertyBindingSupportAutowireTest extends ContextTestSupport {
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext context = super.createCamelContext();
+
+        Bar bar = new Bar();
+        bar.setAge(33);
+        bar.setGoldCustomer(true);
+        bar.setRider(true);
+        context.getRegistry().bind("myBar", bar);
+
+        return context;
+    }
+
+    @Test
+    public void testAutowireProperties() throws Exception {
+        Foo foo = new Foo();
+
+        PropertyBindingSupport.bindProperty(context, foo, "name", "James");
+        
PropertyBindingSupport.autowireSingletonPropertiesFromRegistry(context, foo);
+
+        assertEquals("James", foo.getName());
+        // should be auto wired
+        assertEquals(33, foo.getBar().getAge());
+        assertTrue(foo.getBar().isRider());
+        assertTrue(foo.getBar().isGoldCustomer());
+    }
+
+    public static class Foo {
+        private String name;
+        private Bar bar;
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public Bar getBar() {
+            return bar;
+        }
+
+        public void setBar(Bar bar) {
+            this.bar = bar;
+        }
+    }
+
+    public static class Bar {
+        private int age;
+        private boolean rider;
+        private boolean goldCustomer;
+
+        public int getAge() {
+            return age;
+        }
+
+        public void setAge(int age) {
+            this.age = age;
+        }
+
+        public boolean isRider() {
+            return rider;
+        }
+
+        public void setRider(boolean rider) {
+            this.rider = rider;
+        }
+
+        public boolean isGoldCustomer() {
+            return goldCustomer;
+        }
+
+        public void setGoldCustomer(boolean goldCustomer) {
+            this.goldCustomer = goldCustomer;
+        }
+    }
+
+}
+
diff --git 
a/core/camel-support/src/main/java/org/apache/camel/support/PropertyBindingSupport.java
 
b/core/camel-support/src/main/java/org/apache/camel/support/PropertyBindingSupport.java
index d4a6980..f336d75 100644
--- 
a/core/camel-support/src/main/java/org/apache/camel/support/PropertyBindingSupport.java
+++ 
b/core/camel-support/src/main/java/org/apache/camel/support/PropertyBindingSupport.java
@@ -17,6 +17,7 @@
 package org.apache.camel.support;
 
 import java.lang.reflect.Method;
+import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
 
@@ -46,6 +47,20 @@ public final class PropertyBindingSupport {
     private PropertyBindingSupport() {
     }
 
+    @FunctionalInterface
+    public interface OnAutowiring {
+
+        /**
+         * Callback when a property was autowired on a bean
+         *
+         * @param target        the targeted bean
+         * @param propertyName  the name of the property
+         * @param propertyType  the type of the property
+         * @param value         the property value
+         */
+        void onAutowire(Object target, String propertyName, Class 
propertyType, Object value);
+
+    }
     /**
      * This will discover all the properties on the target, and automatic bind 
the properties that are null by
      * looking up in the registry to see if there is a single instance of the 
same type as the property.
@@ -57,10 +72,65 @@ public final class PropertyBindingSupport {
      * @return              true if one ore more properties was auto wired
      */
     public static boolean autowireSingletonPropertiesFromRegistry(CamelContext 
camelContext, Object target) {
-        // TODO: implement me
+        return autowireSingletonPropertiesFromRegistry(camelContext, target, 
false,null);
+    }
+
+    /**
+     * This will discover all the properties on the target, and automatic bind 
the properties by
+     * looking up in the registry to see if there is a single instance of the 
same type as the property.
+     * This is used for convention over configuration to automatic configure 
resources such as DataSource, Amazon Logins and
+     * so on.
+     *
+     * @param camelContext  the camel context
+     * @param target        the target object
+     * @param bindNullOnly  whether to only autowire if the property has no 
default value or has not been configured explicit
+     * @param callback      optional callback when a property was auto wired
+     * @return              true if one ore more properties was auto wired
+     */
+    public static boolean autowireSingletonPropertiesFromRegistry(CamelContext 
camelContext, Object target, boolean bindNullOnly, OnAutowiring callback) {
+        try {
+            if (target != null) {
+                return doAutowireSingletonPropertiesFromRegistry(camelContext, 
target, bindNullOnly, callback);
+            }
+        } catch (Exception e) {
+            throw new PropertyBindingException(target, e);
+        }
+
         return false;
     }
 
+    private static boolean 
doAutowireSingletonPropertiesFromRegistry(CamelContext camelContext, Object 
target, boolean bindNullOnly, OnAutowiring callback) throws Exception {
+        // when adding a component then support auto-configuring complex types
+        // by looking up from registry, such as DataSource etc
+        Map<String, Object> properties = new LinkedHashMap<>();
+        IntrospectionSupport.getProperties(target, properties, null);
+
+        boolean hit = false;
+
+        for (Map.Entry<String, Object> entry : properties.entrySet()) {
+            String key = entry.getKey();
+            Object value = entry.getValue();
+            Class<?> type = getGetterType(target, key);
+            if (isComplexUserType(type)) {
+                // if the property has not been set and its a complex type 
(not simple or string etc)
+                if (!bindNullOnly || value == null) {
+                    Set lookup = camelContext.getRegistry().findByType(type);
+                    if (lookup.size() == 1) {
+                        value = lookup.iterator().next();
+                        if (value != null) {
+                            hit |= 
IntrospectionSupport.setProperty(camelContext, target, key, value);
+                            if (hit && callback != null) {
+                                callback.onAutowire(target, key, type, value);
+                            }
+                        }
+                    }
+                }
+            }
+        };
+
+        return hit;
+    }
+
     /**
      * Binds the properties to the target object.
      *
@@ -222,4 +292,21 @@ public final class PropertyBindingSupport {
         return null;
     }
 
+    private static Class getGetterType(Object target, String name) {
+        try {
+            Method getter = 
IntrospectionSupport.getPropertyGetter(target.getClass(), name);
+            if (getter != null) {
+                return getter.getReturnType();
+            }
+        } catch (NoSuchMethodException e) {
+            // ignore
+        }
+        return null;
+    }
+
+    private static boolean isComplexUserType(Class type) {
+        // lets consider all non java, as complex types
+        return type != null && !type.isPrimitive() && 
!type.getName().startsWith("java");
+    }
+
 }

Reply via email to