[camel] branch master updated: CAMEL-13557: Add property binding support to make it convenient to configure components and whatnot.

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[camel] branch master updated: CAMEL-13557: Add property binding support to make it convenient to configure components and whatnot.

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

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


The following commit(s) were added to refs/heads/master by this push:
     new a35e72f  CAMEL-13557: Add property binding support to make it convenient to configure components and whatnot.
a35e72f is described below

commit a35e72fdbce8d3546d1d285a39eb2cde831ac755
Author: Claus Ibsen <[hidden email]>
AuthorDate: Fri May 24 13:12:08 2019 +0200

    CAMEL-13557: Add property binding support to make it convenient to configure components and whatnot.
---
 .../camel/main/MainConfigurationProperties.java    |  15 +++
 .../java/org/apache/camel/main/MainSupport.java    |   6 +-
 .../PropertyBindingSupportAutowireNestedTest.java  | 135 +++++++++++++++++++++
 .../camel/support/PropertyBindingSupport.java      |  29 ++++-
 4 files changed, 179 insertions(+), 6 deletions(-)

diff --git a/core/camel-core/src/main/java/org/apache/camel/main/MainConfigurationProperties.java b/core/camel-core/src/main/java/org/apache/camel/main/MainConfigurationProperties.java
index 831dd97..9e7e418 100644
--- a/core/camel-core/src/main/java/org/apache/camel/main/MainConfigurationProperties.java
+++ b/core/camel-core/src/main/java/org/apache/camel/main/MainConfigurationProperties.java
@@ -25,6 +25,7 @@ import org.apache.camel.spi.ReloadStrategy;
 public class MainConfigurationProperties {
 
     private boolean autoConfigurationEnabled = true;
+    private boolean autowireComponentProperties = true;
     private String name;
     private int shutdownTimeout = 300;
     private boolean shutdownSuppressLoggingOnTimeout;
@@ -102,6 +103,20 @@ public class MainConfigurationProperties {
         this.autoConfigurationEnabled = autoConfigurationEnabled;
     }
 
+    public boolean isAutowireComponentProperties() {
+        return autowireComponentProperties;
+    }
+
+    /**
+     * Whether autowiring components with properties that are of same type, which has been added to the Camel registry, as a singleton instance.
+     * This is used for convention over configuration to inject DataSource, AmazonLogin instances to the components.
+     * <p/>
+     * This option is default enabled.
+     */
+    public void setAutowireComponentProperties(boolean autowireComponentProperties) {
+        this.autowireComponentProperties = autowireComponentProperties;
+    }
+
     public String getName() {
         return name;
     }
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 1866caf..c1a4a8a 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
@@ -852,8 +852,10 @@ public abstract class MainSupport extends ServiceSupport {
 
         // conventional configuration via properties to allow configuring options on
         // component, dataformat, and languages (like spring-boot auto-configuration)
-        if (mainConfigurationProperties.isAutoConfigurationEnabled()) {
+        if (mainConfigurationProperties.isAutowireComponentProperties()) {
             autoConfigurationFromRegistry(camelContext);
+        }
+        if (mainConfigurationProperties.isAutoConfigurationEnabled()) {
             autoConfigurationFromProperties(camelContext);
         }
 
@@ -1270,7 +1272,7 @@ public abstract class MainSupport extends ServiceSupport {
             @Override
             public void onComponentAdd(String name, Component component) {
                 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());
+                    LOG.info("Auto configuring option: {} on component: {} as one instance of type: {} registered in the Camel Registry", propertyName, component.getClass().getSimpleName(), type.getName());
                 });
             }
         });
diff --git a/core/camel-core/src/test/java/org/apache/camel/support/PropertyBindingSupportAutowireNestedTest.java b/core/camel-core/src/test/java/org/apache/camel/support/PropertyBindingSupportAutowireNestedTest.java
new file mode 100644
index 0000000..84ab322
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/support/PropertyBindingSupportAutowireNestedTest.java
@@ -0,0 +1,135 @@
+/*
+ * 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 PropertyBindingSupportAutowireNestedTest extends ContextTestSupport {
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext context = super.createCamelContext();
+
+        Company work = new Company();
+        work.setId(456);
+        work.setName("Acme");
+        context.getRegistry().bind("myWork", work);
+
+        return context;
+    }
+
+    @Test
+    public void testAutowireProperties() throws Exception {
+        Foo foo = new Foo();
+
+        PropertyBindingSupport.bindProperty(context, foo, "name", "James");
+        PropertyBindingSupport.bindProperty(context, foo, "bar.age", "33");
+        PropertyBindingSupport.bindProperty(context, foo, "bar.rider", "true");
+        PropertyBindingSupport.bindProperty(context, foo, "bar.gold-customer", "true");
+        PropertyBindingSupport.autowireSingletonPropertiesFromRegistry(context, foo);
+
+        assertEquals("James", foo.getName());
+        assertEquals(33, foo.getBar().getAge());
+        assertTrue(foo.getBar().isRider());
+        assertTrue(foo.getBar().isGoldCustomer());
+        // should be auto wired
+        assertNotNull(foo.getBar().getWork());
+        assertEquals(456, foo.getBar().getWork().getId());
+        assertEquals("Acme", foo.getBar().getWork().getName());
+    }
+
+    public static class Foo {
+        private String name;
+        private Bar bar = new Bar(this);
+
+        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 Foo parent;
+        private int age;
+        private boolean rider;
+        private Company work;
+        private boolean goldCustomer;
+
+        public Bar(Foo parent) {
+            this.parent = parent;
+        }
+
+        public Foo getParent() {
+            // circular dependency foo -> bar && bar -> foo
+            return parent;
+        }
+
+        public void setParent(Foo parent) {
+            this.parent = parent;
+        }
+
+        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 Company getWork() {
+            return work;
+        }
+
+        public void setWork(Company work) {
+            this.work = work;
+        }
+
+        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 cddf4fe..7a21929 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,13 +17,17 @@
 package org.apache.camel.support;
 
 import java.lang.reflect.Method;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
 
 import org.apache.camel.CamelContext;
+import org.apache.camel.Component;
+import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.PropertyBindingException;
+import org.apache.camel.runtimecatalog.RuntimeCamelCatalog;
 
 import static org.apache.camel.support.IntrospectionSupport.findSetterMethods;
 import static org.apache.camel.support.IntrospectionSupport.getOrElseProperty;
@@ -165,7 +169,8 @@ public final class PropertyBindingSupport {
     public static boolean autowireSingletonPropertiesFromRegistry(CamelContext camelContext, Object target, boolean bindNullOnly, OnAutowiring callback) {
         try {
             if (target != null) {
-                return doAutowireSingletonPropertiesFromRegistry(camelContext, target, bindNullOnly, callback);
+                Set<Object> parents = new HashSet<>();
+                return doAutowireSingletonPropertiesFromRegistry(camelContext, target, parents, bindNullOnly, callback);
             }
         } catch (Exception e) {
             throw new PropertyBindingException(target, e);
@@ -174,7 +179,8 @@ public final class PropertyBindingSupport {
         return false;
     }
 
-    private static boolean doAutowireSingletonPropertiesFromRegistry(CamelContext camelContext, Object target, boolean bindNullOnly, OnAutowiring callback) throws Exception {
+    private static boolean doAutowireSingletonPropertiesFromRegistry(CamelContext camelContext, Object target, Set<Object> parents,
+                                                                     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<>();
@@ -182,12 +188,18 @@ public final class PropertyBindingSupport {
 
         boolean hit = false;
 
-        // TODO: add support for nesting but not for inherited properties from base classes (eg CamelContext etc)
-
         for (Map.Entry<String, Object> entry : properties.entrySet()) {
             String key = entry.getKey();
             Object value = entry.getValue();
             Class<?> type = getGetterType(target, key);
+
+            boolean skip = parents.contains(value) || value instanceof CamelContext;
+            if (skip) {
+                // we have already covered this as parent of parents so dont walk down this as we want to avoid
+                // circular dependencies when walking the OGNL graph, also we dont want to walk down CamelContext
+                continue;
+            }
+
             if (isComplexUserType(type)) {
                 // if the property has not been set and its a complex type (not simple or string etc)
                 if (!bindNullOnly || value == null) {
@@ -202,6 +214,15 @@ public final class PropertyBindingSupport {
                         }
                     }
                 }
+
+                // TODO: Support creating new instances to walk down the tree if its null
+
+                // remember this as parent and also autowire nested properties
+                // do not walk down if it point to our-selves (circular reference)
+                if (value != null) {
+                    parents.add(target);
+                    hit |= doAutowireSingletonPropertiesFromRegistry(camelContext, value, parents, bindNullOnly, callback);
+                }
             }
         };