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 ab9b2e2 CAMEL-12610: Bean component with cache=false will now also lookup beans that implements Processor on each invocation. ab9b2e2 is described below commit ab9b2e20a143f753e3781e00850b25b2905594f9 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Fri Aug 24 11:40:22 2018 +0200 CAMEL-12610: Bean component with cache=false will now also lookup beans that implements Processor on each invocation. --- camel-core/src/main/docs/bean-component.adoc | 2 +- camel-core/src/main/docs/class-component.adoc | 2 +- .../component/bean/AbstractBeanProcessor.java | 34 +++++-- .../apache/camel/component/bean/BeanEndpoint.java | 11 ++- .../apache/camel/component/bean/BeanProcessor.java | 8 ++ .../camel/processor/BeanCachedProcessorTest.java | 101 +++++++++++++++++++++ 6 files changed, 145 insertions(+), 13 deletions(-) diff --git a/camel-core/src/main/docs/bean-component.adoc b/camel-core/src/main/docs/bean-component.adoc index 2887822..9221e1c 100644 --- a/camel-core/src/main/docs/bean-component.adoc +++ b/camel-core/src/main/docs/bean-component.adoc @@ -50,7 +50,7 @@ with the following path and query parameters: |=== | Name | Description | Default | Type | *method* (producer) | Sets the name of the method to invoke on the bean | | String -| *cache* (advanced) | If enabled, Camel will cache the result of the first Registry look-up. Cache can be enabled if the bean in the Registry is defined as a singleton scope. | false | boolean +| *cache* (advanced) | If enabled, Camel will cache the result of the first Registry look-up. Cache can be enabled if the bean in the Registry is defined as a singleton scope. | | Boolean | *multiParameterArray* (advanced) | *Deprecated* How to treat the parameters which are passed from the message body; if it is true, the message body should be an array of parameters. Note: This option is used internally by Camel, and is not intended for end users to use. Deprecation note: This option is used internally by Camel, and is not intended for end users to use. | false | boolean | *parameters* (advanced) | Used for configuring additional properties on the bean | | Map | *synchronous* (advanced) | Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported). | false | boolean diff --git a/camel-core/src/main/docs/class-component.adoc b/camel-core/src/main/docs/class-component.adoc index 7249db4..e44fef7 100644 --- a/camel-core/src/main/docs/class-component.adoc +++ b/camel-core/src/main/docs/class-component.adoc @@ -53,7 +53,7 @@ with the following path and query parameters: |=== | Name | Description | Default | Type | *method* (producer) | Sets the name of the method to invoke on the bean | | String -| *cache* (advanced) | If enabled, Camel will cache the result of the first Registry look-up. Cache can be enabled if the bean in the Registry is defined as a singleton scope. | false | boolean +| *cache* (advanced) | If enabled, Camel will cache the result of the first Registry look-up. Cache can be enabled if the bean in the Registry is defined as a singleton scope. | | Boolean | *multiParameterArray* (advanced) | *Deprecated* How to treat the parameters which are passed from the message body; if it is true, the message body should be an array of parameters. Note: This option is used internally by Camel, and is not intended for end users to use. Deprecation note: This option is used internally by Camel, and is not intended for end users to use. | false | boolean | *parameters* (advanced) | Used for configuring additional properties on the bean | | Map | *synchronous* (advanced) | Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported). | false | boolean diff --git a/camel-core/src/main/java/org/apache/camel/component/bean/AbstractBeanProcessor.java b/camel-core/src/main/java/org/apache/camel/component/bean/AbstractBeanProcessor.java index fd4803a..2cc7b9d 100644 --- a/camel-core/src/main/java/org/apache/camel/component/bean/AbstractBeanProcessor.java +++ b/camel-core/src/main/java/org/apache/camel/component/bean/AbstractBeanProcessor.java @@ -42,6 +42,7 @@ public abstract class AbstractBeanProcessor implements AsyncProcessor { private transient boolean lookupProcessorDone; private final Object lock = new Object(); private boolean multiParameterArray; + private Boolean cache; private String method; private boolean shorthandMethod; @@ -94,19 +95,28 @@ public abstract class AbstractBeanProcessor implements AsyncProcessor { // but only do this if allowed // we need to check beanHolder is Processor is support, to avoid the bean cached issue if (allowProcessor(explicitMethodName, beanInfo)) { - processor = getProcessor(); - if (processor == null && !lookupProcessorDone) { + Processor target = getProcessor(); + if (target == null) { // only attempt to lookup the processor once or nearly once - synchronized (lock) { - lookupProcessorDone = true; + boolean allowCache = cache == null || cache; // allow cache by default + if (allowCache) { + if (!lookupProcessorDone) { + synchronized (lock) { + lookupProcessorDone = true; + // so if there is a custom type converter for the bean to processor + target = exchange.getContext().getTypeConverter().tryConvertTo(Processor.class, exchange, bean); + processor = target; + } + } + } else { // so if there is a custom type converter for the bean to processor - processor = exchange.getContext().getTypeConverter().tryConvertTo(Processor.class, exchange, bean); + target = exchange.getContext().getTypeConverter().tryConvertTo(Processor.class, exchange, bean); } } - if (processor != null) { - LOG.trace("Using a custom adapter as bean invocation: {}", processor); + if (target != null) { + LOG.trace("Using a custom adapter as bean invocation: {}", target); try { - processor.process(exchange); + target.process(exchange); } catch (Throwable e) { exchange.setException(e); } @@ -215,6 +225,14 @@ public abstract class AbstractBeanProcessor implements AsyncProcessor { multiParameterArray = mpArray; } + public Boolean getCache() { + return cache; + } + + public void setCache(Boolean cache) { + this.cache = cache; + } + /** * Sets the method name to use */ diff --git a/camel-core/src/main/java/org/apache/camel/component/bean/BeanEndpoint.java b/camel-core/src/main/java/org/apache/camel/component/bean/BeanEndpoint.java index bbaf39d..00e0c48 100644 --- a/camel-core/src/main/java/org/apache/camel/component/bean/BeanEndpoint.java +++ b/camel-core/src/main/java/org/apache/camel/component/bean/BeanEndpoint.java @@ -42,7 +42,7 @@ public class BeanEndpoint extends DefaultEndpoint { private String method; @UriParam(label = "advanced", description = "If enabled, Camel will cache the result of the first Registry look-up." + " Cache can be enabled if the bean in the Registry is defined as a singleton scope.") - private boolean cache; + private Boolean cache; @UriParam(label = "advanced", description = "How to treat the parameters which are passed from the message body." + "true means the message body should be an array of parameters.") @Deprecated @Metadata(deprecationNode = "This option is used internally by Camel, and is not intended for end users to use.") @@ -92,7 +92,7 @@ public class BeanEndpoint extends DefaultEndpoint { BeanHolder holder = getBeanHolder(); if (holder == null) { RegistryBean registryBean = new RegistryBean(getCamelContext(), beanName); - if (cache) { + if (isCache()) { holder = registryBean.createCacheHolder(); } else { holder = registryBean; @@ -103,6 +103,7 @@ public class BeanEndpoint extends DefaultEndpoint { processor.setMethod(method); } processor.setMultiParameterArray(isMultiParameterArray()); + processor.setCache(cache); if (parameters != null) { setProperties(processor, parameters); } @@ -147,6 +148,10 @@ public class BeanEndpoint extends DefaultEndpoint { } public boolean isCache() { + return cache != null ? cache : false; + } + + public Boolean getCache() { return cache; } @@ -154,7 +159,7 @@ public class BeanEndpoint extends DefaultEndpoint { * If enabled, Camel will cache the result of the first Registry look-up. * Cache can be enabled if the bean in the Registry is defined as a singleton scope. */ - public void setCache(boolean cache) { + public void setCache(Boolean cache) { this.cache = cache; } diff --git a/camel-core/src/main/java/org/apache/camel/component/bean/BeanProcessor.java b/camel-core/src/main/java/org/apache/camel/component/bean/BeanProcessor.java index 9e31582..cbf68c4 100644 --- a/camel-core/src/main/java/org/apache/camel/component/bean/BeanProcessor.java +++ b/camel-core/src/main/java/org/apache/camel/component/bean/BeanProcessor.java @@ -77,6 +77,14 @@ public class BeanProcessor extends ServiceSupport implements AsyncProcessor { delegate.setMultiParameterArray(mpArray); } + public Boolean getCache() { + return delegate.getCache(); + } + + public void setCache(Boolean cache) { + delegate.setCache(cache); + } + public void setMethod(String method) { delegate.setMethod(method); } diff --git a/camel-core/src/test/java/org/apache/camel/processor/BeanCachedProcessorTest.java b/camel-core/src/test/java/org/apache/camel/processor/BeanCachedProcessorTest.java new file mode 100644 index 0000000..f79fd20 --- /dev/null +++ b/camel-core/src/test/java/org/apache/camel/processor/BeanCachedProcessorTest.java @@ -0,0 +1,101 @@ +/** + * 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.processor; + +import javax.naming.Context; + +import org.apache.camel.CamelExecutionException; +import org.apache.camel.ContextTestSupport; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.impl.JndiRegistry; +import org.junit.Test; + +public class BeanCachedProcessorTest extends ContextTestSupport { + + private Context context; + + private JndiRegistry registry; + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + from("direct:noCache") + .to("bean:something?cache=false"); + from("direct:cached") + .to("bean:something?cache=true"); + + } + }; + } + + @Override + protected JndiRegistry createRegistry() throws Exception { + JndiRegistry registry = super.createRegistry(); + registry.bind("something", new MyBean()); + this.context = registry.getContext(); + this.registry = registry; + return registry; + } + + @Test + public void testFreshBeanInContext() throws Exception { + // Just make sure the bean processor doesn't work if the cached is false + MyBean originalInstance = registry.lookup("something", MyBean.class); + template.sendBody("direct:noCache", null); + context.unbind("something"); + context.bind("something", new MyBean()); + // Make sure we can get the object from the registry + assertNotSame(registry.lookup("something"), originalInstance); + template.sendBody("direct:noCache", null); + } + + @Test + public void testBeanWithCached() throws Exception { + // Just make sure the bean processor doesn't work if the cached is false + MyBean originalInstance = registry.lookup("something", MyBean.class); + template.sendBody("direct:cached", null); + context.unbind("something"); + context.bind("something", new MyBean()); + // Make sure we can get the object from the registry + assertNotSame(registry.lookup("something"), originalInstance); + try { + template.sendBody("direct:cached", null); + fail("The IllegalStateException is expected"); + } catch (CamelExecutionException ex) { + assertTrue("IllegalStateException is expected!", ex.getCause() instanceof IllegalStateException); + assertEquals("This bean is not supported to be invoked again!", ex.getCause().getMessage()); + } + } + + + public static class MyBean implements Processor { + private boolean invoked; + + public void process(Exchange exchange) throws Exception { + if (invoked) { + throw new IllegalStateException("This bean is not supported to be invoked again!"); + } else { + invoked = true; + } + } + } + +}