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 2018/08/24 09:40:41 UTC

[camel] branch master updated: CAMEL-12610: Bean component with cache=false will now also lookup beans that implements Processor on each invocation.

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 <cl...@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;
+            }
+        }
+    }
+
+}