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; + } + +}
