You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2019/05/24 10:12:46 UTC

[camel] 06/27: CAMEL-13557: Add property binding support to make it convenient to configure components and whatnot.

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

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

commit 9af09b9676e3c6364f048b71ce2597df09d028ce
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Thu May 23 06:38:33 2019 +0200

    CAMEL-13557: Add property binding support to make it convenient to configure components and whatnot.
---
 .../java/org/apache/camel/main/MainSupport.java    |  2 +
 .../camel/support/PropertyBindingSupportTest.java  | 37 +++++++++++--
 .../camel/support/PropertyBindingSupport.java      | 61 +++++++++++++++-------
 3 files changed, 78 insertions(+), 22 deletions(-)

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 fedb2cd..4a249dc 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
@@ -1261,6 +1261,8 @@ public abstract class MainSupport extends ServiceSupport {
                 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) -> {
diff --git a/core/camel-core/src/test/java/org/apache/camel/support/PropertyBindingSupportTest.java b/core/camel-core/src/test/java/org/apache/camel/support/PropertyBindingSupportTest.java
index 86118be..3f28037 100644
--- a/core/camel-core/src/test/java/org/apache/camel/support/PropertyBindingSupportTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/support/PropertyBindingSupportTest.java
@@ -16,12 +16,16 @@
  */
 package org.apache.camel.support;
 
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
 import org.apache.camel.CamelContext;
 import org.apache.camel.ContextTestSupport;
 import org.junit.Test;
 
 /**
- * Unit test for PropertyBindingSupport with nested properties
+ * Unit test for PropertyBindingSupport
  */
 public class PropertyBindingSupportTest extends ContextTestSupport {
 
@@ -34,19 +38,46 @@ public class PropertyBindingSupportTest extends ContextTestSupport {
         work.setName("Acme");
         context.getRegistry().bind("myWork", work);
 
+        Properties placeholders = new Properties();
+        placeholders.put("companyName", "Acme");
+        placeholders.put("committer", "rider");
+        context.getPropertiesComponent().setInitialProperties(placeholders);
+
         return context;
     }
 
     @Test
+    public void testProperties() throws Exception {
+        Foo foo = new Foo();
+
+        Map<String, Object> prop = new HashMap<>();
+        prop.put("name", "James");
+        prop.put("bar.age", "33");
+        prop.put("bar.{{committer}}", "true");
+        prop.put("bar.gold-customer", "true");
+        prop.put("bar.work.id", "123");
+        prop.put("bar.work.name", "{{companyName}}");
+
+        PropertyBindingSupport.bindProperties(context, foo, prop);
+
+        assertEquals("James", foo.getName());
+        assertEquals(33, foo.getBar().getAge());
+        assertTrue(foo.getBar().isRider());
+        assertTrue(foo.getBar().isGoldCustomer());
+        assertEquals(123, foo.getBar().getWork().getId());
+        assertEquals("Acme", foo.getBar().getWork().getName());
+    }
+
+    @Test
     public void testNested() 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.{{committer}}", "true");
         PropertyBindingSupport.bindProperty(context, foo, "bar.gold-customer", "true");
         PropertyBindingSupport.bindProperty(context, foo, "bar.work.id", "123");
-        PropertyBindingSupport.bindProperty(context, foo, "bar.work.name", "Acme");
+        PropertyBindingSupport.bindProperty(context, foo, "bar.work.name", "{{companyName}}");
 
         assertEquals("James", foo.getName());
         assertEquals(33, foo.getBar().getAge());
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 66bb0b4..d9bfb03 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
@@ -21,6 +21,7 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.camel.CamelContext;
+import org.apache.camel.RuntimeCamelException;
 
 import static org.apache.camel.support.IntrospectionSupport.findSetterMethods;
 import static org.apache.camel.support.IntrospectionSupport.getOrElseProperty;
@@ -29,6 +30,7 @@ import static org.apache.camel.support.IntrospectionSupport.getOrElseProperty;
  * A convenient support class for binding String valued properties to an instance which
  * uses a set of conventions:
  * <ul>
+ *     <li>property placeholders - Keys and values using Camels property placeholder will be resolved</li>
  *     <li>nested - Properties can be nested using the dot syntax (OGNL and builder pattern using with as prefix), eg foo.bar=123</li>
  *     <li>reference by id - Values can refer to other beans in the registry by prefixing with # syntax, eg #myBean</li>
  * </ul>
@@ -41,34 +43,52 @@ public final class PropertyBindingSupport {
     private PropertyBindingSupport() {
     }
 
+    /**
+     * Binds the properties to the target object.
+     *
+     * @param camelContext  the camel context
+     * @param target        the target object
+     * @param properties    the properties
+     * @return              true if one or more properties was bound, false otherwise
+     */
     public static boolean bindProperties(CamelContext camelContext, Object target, Map<String, Object> properties) throws Exception {
-        boolean answer = true;
+        boolean answer = false;
         for (Map.Entry<String, Object> entry : properties.entrySet()) {
-            answer &= bindProperty(camelContext, target, entry.getKey(), entry.getValue());
+            answer |= bindProperty(camelContext, target, entry.getKey(), entry.getValue());
         }
         return answer;
     }
 
-    public static boolean bindProperty(CamelContext camelContext, Object target, String name, Object value) throws Exception {
-        return setProperty(camelContext, target, name, value, null, true, true);
-    }
-
     /**
-     * This method supports two modes to set a property:
-     *
-     * 1. Setting a property that has already been resolved, this is the case when {@code context} and {@code refName} are
-     * NULL and {@code value} is non-NULL.
+     * Binds the property to the target object.
      *
-     * 2. Setting a property that has not yet been resolved, the property will be resolved based on the suitable methods
-     * found matching the property name on the {@code target} bean. For this mode to be triggered the parameters
-     * {@code context} and {@code refName} must NOT be NULL, and {@code value} MUST be NULL.
+     * @param camelContext  the camel context
+     * @param target        the target object
+     * @param name          name of property
+     * @param value         value of property
+     * @return              true if property was bound, false otherwise
      */
-    private static boolean setProperty(CamelContext context, Object target, String name, Object value, String refName,
-                                      boolean allowBuilderPattern, boolean allowNestedProperties) throws Exception {
+    public static boolean bindProperty(CamelContext camelContext, Object target, String name, Object value) throws Exception {
+        if (target != null && name != null) {
+            return setProperty(camelContext, target, name, value);
+        } else {
+            return false;
+        }
+    }
+
+    private static boolean setProperty(CamelContext context, Object target, String name, Object value) {
         Class<?> clazz = target.getClass();
+        String refName = null;
+
+        // resolve property placeholders
+        name = context.resolvePropertyPlaceholders(name);
+        if (value instanceof String) {
+            // resolve property placeholders
+            value = context.resolvePropertyPlaceholders(value.toString());
+        }
 
         // if name has dot then we need to OGNL walk it
-        if (allowNestedProperties && name.indexOf('.') > 0) {
+        if (name.indexOf('.') > 0) {
             String[] parts = name.split("\\.");
             Object newTarget = target;
             Class<?> newClass = clazz;
@@ -78,7 +98,7 @@ public final class PropertyBindingSupport {
                 Object prop = getOrElseProperty(newTarget, part, null);
                 if (prop == null) {
                     // okay is there a setter so we can create a new instance and set it automatic
-                    Set<Method> newSetters = findSetterMethods(newClass, part, allowBuilderPattern);
+                    Set<Method> newSetters = findSetterMethods(newClass, part, true);
                     if (newSetters.size() == 1) {
                         Method method = newSetters.iterator().next();
                         Class<?> parameterType = method.getParameterTypes()[0];
@@ -98,7 +118,6 @@ public final class PropertyBindingSupport {
             }
             // okay we found a nested property, then lets change to use that
             target = newTarget;
-            clazz = newTarget.getClass();
             name = parts[parts.length - 1];
             if (value instanceof String) {
                 if (EndpointHelper.isReferenceParameter(value.toString())) {
@@ -109,7 +128,11 @@ public final class PropertyBindingSupport {
             }
         }
 
-        return IntrospectionSupport.setProperty(context, context.getTypeConverter(), target, name, value, refName, allowBuilderPattern);
+        try {
+            return IntrospectionSupport.setProperty(context, context.getTypeConverter(), target, name, value, refName, true);
+        } catch (Exception e) {
+            throw RuntimeCamelException.wrapRuntimeException(e);
+        }
     }
 
 }