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 <[email protected]>
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;
+    }
+
+}

Reply via email to