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 2021/05/04 13:45:22 UTC

[camel] 01/01: CAMEL-16575: Camel registry can now bind a bean that is supplied via a Supplier. This allows to bind beans that are lazy evaluated via lambda and assists for the local bean registry work that is needed for Kamelets and route templates.

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

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

commit 48469d3f73be880cc24f56d98a53ae836d277df6
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Tue May 4 15:44:30 2021 +0200

    CAMEL-16575: Camel registry can now bind a bean that is supplied via a Supplier. This allows to bind beans that are lazy evaluated via lambda and assists for the local bean registry work that is needed for Kamelets and route templates.
---
 .../main/java/org/apache/camel/spi/Registry.java   |  4 +
 .../apache/camel/support/DefaultRegistryTest.java  | 88 ++++++++++++++++++++++
 .../org/apache/camel/support/DefaultRegistry.java  | 63 ++++++++++++++--
 .../org/apache/camel/support/SimpleRegistry.java   |  7 ++
 .../org/apache/camel/support/SupplierRegistry.java | 68 +++++++++++++++++
 5 files changed, 223 insertions(+), 7 deletions(-)

diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/Registry.java b/core/camel-api/src/main/java/org/apache/camel/spi/Registry.java
index d8e596d..e350ee0 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/Registry.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/Registry.java
@@ -16,6 +16,8 @@
  */
 package org.apache.camel.spi;
 
+import java.util.function.Supplier;
+
 import org.apache.camel.CamelContextAware;
 import org.apache.camel.RuntimeCamelException;
 
@@ -51,6 +53,8 @@ public interface Registry extends BeanRepository {
      */
     void bind(String id, Class<?> type, Object bean) throws RuntimeCamelException;
 
+    void bind(String id, Class<?> type, Supplier<Object> bean) throws RuntimeCamelException;
+
     /**
      * Strategy to wrap the value to be stored in the registry.
      *
diff --git a/core/camel-core/src/test/java/org/apache/camel/support/DefaultRegistryTest.java b/core/camel-core/src/test/java/org/apache/camel/support/DefaultRegistryTest.java
index 98abf3a..bf32a4e 100644
--- a/core/camel-core/src/test/java/org/apache/camel/support/DefaultRegistryTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/support/DefaultRegistryTest.java
@@ -17,6 +17,9 @@
 package org.apache.camel.support;
 
 import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
@@ -33,6 +36,7 @@ public class DefaultRegistryTest {
     private final DefaultRegistry registry = new DefaultRegistry(br);
     private final Company myCompany = new Company();
     private final FooBar myFooBar = new FooBar();
+    private final AtomicInteger counter = new AtomicInteger();
 
     @BeforeEach
     protected void setUp() throws Exception {
@@ -41,6 +45,90 @@ public class DefaultRegistryTest {
     }
 
     @Test
+    public void testBindAsSupplierLookupByName() throws Exception {
+        counter.set(0);
+
+        registry.bind("myBar", FooBar.class, () -> {
+            FooBar bar = new FooBar();
+            bar.setGreeting("I am lazy " + counter.incrementAndGet());
+            return bar;
+        });
+
+        FooBar bar1 = (FooBar) registry.lookupByName("myBar");
+        FooBar bar2 = (FooBar) registry.lookupByName("myBar");
+        assertNotSame(bar1, bar2);
+        assertEquals("I am lazy 1 me", bar1.hello("me"));
+        assertEquals("I am lazy 2 me", bar2.hello("me"));
+    }
+
+    @Test
+    public void testBindAsSupplierLookupByNameAndType() throws Exception {
+        counter.set(0);
+
+        registry.bind("myBar", FooBar.class, () -> {
+            FooBar bar = new FooBar();
+            bar.setGreeting("I am lazy " + counter.incrementAndGet());
+            return bar;
+        });
+
+        FooBar bar1 = registry.lookupByNameAndType("myBar", FooBar.class);
+        FooBar bar2 = registry.lookupByNameAndType("myBar", FooBar.class);
+        assertNotSame(bar1, bar2);
+        assertEquals("I am lazy 1 me", bar1.hello("me"));
+        assertEquals("I am lazy 2 me", bar2.hello("me"));
+    }
+
+    @Test
+    public void testBindAsSupplierFindByType() throws Exception {
+        counter.set(0);
+
+        registry.bind("myBar", FooBar.class, () -> {
+            FooBar bar = new FooBar();
+            bar.setGreeting("I am lazy " + counter.incrementAndGet());
+            return bar;
+        });
+
+        // find first time which we find the supplier and then then from fallback
+        Set<FooBar> set = registry.findByType(FooBar.class);
+        assertEquals(2, set.size());
+        Iterator<FooBar> it = set.iterator();
+        assertEquals("I am lazy 1 me", it.next().hello("me"));
+        assertSame(myFooBar, it.next());
+
+        // find secoond time which we find the supplier and then then from fallback
+        set = registry.findByType(FooBar.class);
+        assertEquals(2, set.size());
+        it = set.iterator();
+        assertEquals("I am lazy 2 me", it.next().hello("me"));
+        assertSame(myFooBar, it.next());
+    }
+
+    @Test
+    public void testBindAsSupplierFindByTypeWithName() throws Exception {
+        counter.set(0);
+
+        registry.bind("myBar", FooBar.class, () -> {
+            FooBar bar = new FooBar();
+            bar.setGreeting("I am lazy " + counter.incrementAndGet());
+            return bar;
+        });
+
+        // find first time which we find the supplier and then then from fallback
+        Map<String, FooBar> map = registry.findByTypeWithName(FooBar.class);
+        assertEquals(2, map.size());
+        Iterator<FooBar> it = map.values().iterator();
+        assertEquals("I am lazy 1 me", it.next().hello("me"));
+        assertSame(myFooBar, it.next());
+
+        // find secoond time which we find the supplier and then then from fallback
+        map = registry.findByTypeWithName(FooBar.class);
+        assertEquals(2, map.size());
+        it = map.values().iterator();
+        assertEquals("I am lazy 2 me", it.next().hello("me"));
+        assertSame(myFooBar, it.next());
+    }
+
+    @Test
     public void testLookupByName() throws Exception {
         assertNull(registry.lookupByName("foo"));
         assertSame(myCompany, registry.lookupByName("myCompany"));
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/DefaultRegistry.java b/core/camel-support/src/main/java/org/apache/camel/support/DefaultRegistry.java
index 4e37dc3..86fd9ed 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/DefaultRegistry.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/DefaultRegistry.java
@@ -26,6 +26,7 @@ import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Supplier;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
@@ -49,6 +50,7 @@ public class DefaultRegistry extends ServiceSupport implements Registry, CamelCo
     protected CamelContext camelContext;
     protected List<BeanRepository> repositories;
     protected Registry fallbackRegistry = new SimpleRegistry();
+    protected Registry supplierRegistry = new SupplierRegistry();
 
     /**
      * Creates a default registry that uses {@link SimpleRegistry} as the fallback registry. The fallback registry can
@@ -98,6 +100,20 @@ public class DefaultRegistry extends ServiceSupport implements Registry, CamelCo
         this.fallbackRegistry = fallbackRegistry;
     }
 
+    /**
+     * Gets the supplier {@link Registry}
+     */
+    public Registry getSupplierRegistry() {
+        return supplierRegistry;
+    }
+
+    /**
+     * To use a custom {@link Registry} for suppliers.
+     */
+    public void setSupplierRegistry(Registry supplierRegistry) {
+        this.supplierRegistry = supplierRegistry;
+    }
+
     @Override
     public CamelContext getCamelContext() {
         return camelContext;
@@ -131,7 +147,13 @@ public class DefaultRegistry extends ServiceSupport implements Registry, CamelCo
     }
 
     @Override
+    public void bind(String id, Class<?> type, Supplier<Object> bean) throws RuntimeCamelException {
+        supplierRegistry.bind(id, type, bean);
+    }
+
+    @Override
     public Object lookupByName(String name) {
+        Object answer;
         try {
             // Must avoid attempting placeholder resolution when looking up
             // the properties component or else we end up in an infinite loop.
@@ -144,18 +166,26 @@ public class DefaultRegistry extends ServiceSupport implements Registry, CamelCo
 
         if (repositories != null) {
             for (BeanRepository r : repositories) {
-                Object answer = r.lookupByName(name);
+                answer = r.lookupByName(name);
                 if (answer != null) {
                     return unwrap(answer);
                 }
             }
         }
-        return fallbackRegistry.lookupByName(name);
+        answer = supplierRegistry.lookupByName(name);
+        if (answer == null) {
+            answer = fallbackRegistry.lookupByName(name);
+        }
+        if (answer != null) {
+            answer = unwrap(answer);
+        }
+        return answer;
     }
 
     @Override
     @SuppressWarnings("unchecked")
     public <T> T lookupByNameAndType(String name, Class<T> type) {
+        T answer;
         try {
             // Must avoid attempting placeholder resolution when looking up
             // the properties component or else we end up in an infinite loop.
@@ -168,13 +198,21 @@ public class DefaultRegistry extends ServiceSupport implements Registry, CamelCo
 
         if (repositories != null) {
             for (BeanRepository r : repositories) {
-                T answer = r.lookupByNameAndType(name, type);
+                answer = r.lookupByNameAndType(name, type);
                 if (answer != null) {
                     return (T) unwrap(answer);
                 }
             }
         }
-        return fallbackRegistry.lookupByNameAndType(name, type);
+
+        answer = supplierRegistry.lookupByNameAndType(name, type);
+        if (answer == null) {
+            answer = fallbackRegistry.lookupByNameAndType(name, type);
+        }
+        if (answer != null) {
+            answer = (T) unwrap(answer);
+        }
+        return answer;
     }
 
     @Override
@@ -190,7 +228,11 @@ public class DefaultRegistry extends ServiceSupport implements Registry, CamelCo
             }
         }
 
-        Map<String, T> found = fallbackRegistry.findByTypeWithName(type);
+        Map<String, T> found = supplierRegistry.findByTypeWithName(type);
+        if (found != null && !found.isEmpty()) {
+            answer.putAll(found);
+        }
+        found = fallbackRegistry.findByTypeWithName(type);
         if (found != null && !found.isEmpty()) {
             answer.putAll(found);
         }
@@ -211,7 +253,11 @@ public class DefaultRegistry extends ServiceSupport implements Registry, CamelCo
             }
         }
 
-        Set<T> found = fallbackRegistry.findByType(type);
+        Set<T> found = supplierRegistry.findByType(type);
+        if (found != null && !found.isEmpty()) {
+            answer.addAll(found);
+        }
+        found = fallbackRegistry.findByType(type);
         if (found != null && !found.isEmpty()) {
             answer.addAll(found);
         }
@@ -222,9 +268,12 @@ public class DefaultRegistry extends ServiceSupport implements Registry, CamelCo
     @Override
     protected void doStop() throws Exception {
         super.doStop();
+        if (supplierRegistry instanceof Closeable) {
+            IOHelper.close((Closeable) supplierRegistry);
+        }
         if (fallbackRegistry instanceof Closeable) {
             IOHelper.close((Closeable) fallbackRegistry);
         }
-        ServiceHelper.stopAndShutdownService(fallbackRegistry);
+        ServiceHelper.stopAndShutdownServices(supplierRegistry, fallbackRegistry);
     }
 }
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/SimpleRegistry.java b/core/camel-support/src/main/java/org/apache/camel/support/SimpleRegistry.java
index 4d443b0..e697f9e 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/SimpleRegistry.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/SimpleRegistry.java
@@ -22,8 +22,10 @@ import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Supplier;
 
 import org.apache.camel.NoSuchBeanException;
+import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.spi.Registry;
 
 /**
@@ -104,6 +106,11 @@ public class SimpleRegistry extends LinkedHashMap<String, Map<Class<?>, Object>>
     }
 
     @Override
+    public void bind(String id, Class<?> type, Supplier<Object> bean) throws RuntimeCamelException {
+        computeIfAbsent(id, k -> new LinkedHashMap<>()).put(type, wrap(bean));
+    }
+
+    @Override
     public void close() throws IOException {
         clear();
     }
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/SupplierRegistry.java b/core/camel-support/src/main/java/org/apache/camel/support/SupplierRegistry.java
new file mode 100644
index 0000000..572007c
--- /dev/null
+++ b/core/camel-support/src/main/java/org/apache/camel/support/SupplierRegistry.java
@@ -0,0 +1,68 @@
+/*
+ * 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 java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Supplier;
+
+/**
+ * Used for storing beans that are lazy supplied via a {@link Supplier}.
+ *
+ * To bind a bean as a supplier, then use the {@link org.apache.camel.spi.Registry#bind(String, Class, Supplier)} method.
+ */
+public class SupplierRegistry extends SimpleRegistry {
+
+    @Override
+    public <T> Set<T> findByType(Class<T> type) {
+        Set<T> result = new LinkedHashSet<>();
+        for (Map.Entry<String, Map<Class<?>, Object>> entry : entrySet()) {
+            for (Map.Entry<Class<?>, Object> subEntry : entry.getValue().entrySet()) {
+                if (type.isAssignableFrom(subEntry.getKey())) {
+                    Object value = unwrap(subEntry.getValue());
+                    result.add(type.cast(value));
+                }
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public <T> Map<String, T> findByTypeWithName(Class<T> type) {
+        Map<String, T> result = new LinkedHashMap<>();
+        for (Map.Entry<String, Map<Class<?>, Object>> entry : entrySet()) {
+            for (Map.Entry<Class<?>, Object> subEntry : entry.getValue().entrySet()) {
+                if (type.isAssignableFrom(subEntry.getKey())) {
+                    Object value = unwrap(subEntry.getValue());
+                    result.put(entry.getKey(), type.cast(value));
+                }
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public Object unwrap(Object value) {
+        if (value instanceof Supplier) {
+            value = ((Supplier<?>) value).get();
+        }
+        return value;
+    }
+
+}