This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push: new e7cbc864f98 Bypass (#10808) e7cbc864f98 is described below commit e7cbc864f98c265cdd336f927f9071f33e7e928e Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Tue Jul 25 08:50:23 2023 +0200 Bypass (#10808) * CAMEL-14467: camel-jcache - Dynamically bypass the cache for lookups. Thanks to Jens Kleine-Herzbruch for the patch. --- .../src/main/docs/jcache-component.adoc | 6 +++ .../component/jcache/policy/JCachePolicy.java | 11 ++++- .../jcache/policy/JCachePolicyProcessor.java | 40 ++++++++++++----- .../jcache/policy/JCachePolicyProcessorTest.java | 52 ++++++++++++++++++++++ 4 files changed, 96 insertions(+), 13 deletions(-) diff --git a/components/camel-jcache/src/main/docs/jcache-component.adoc b/components/camel-jcache/src/main/docs/jcache-component.adoc index 0a33957fca7..8f879fbbc63 100644 --- a/components/camel-jcache/src/main/docs/jcache-component.adoc +++ b/components/camel-jcache/src/main/docs/jcache-component.adoc @@ -177,6 +177,12 @@ from("direct:get-orders") .bean(OrderService.class,"findOrderById(${header.orderId})"); ---------------------------- +== BypassExpression + +The `JCachePolicy` can be configured with an `Expression` that can per `Exchange` determine whether +to look up the value from the cache or bypass. If the expression is evaluated to `false` then the route +is executed as normal, and the returned value is inserted into the cache for future lookup. + == Camel XML DSL examples == Use JCachePolicy in an XML route diff --git a/components/camel-jcache/src/main/java/org/apache/camel/component/jcache/policy/JCachePolicy.java b/components/camel-jcache/src/main/java/org/apache/camel/component/jcache/policy/JCachePolicy.java index 87d82d8626c..e764e13862e 100644 --- a/components/camel-jcache/src/main/java/org/apache/camel/component/jcache/policy/JCachePolicy.java +++ b/components/camel-jcache/src/main/java/org/apache/camel/component/jcache/policy/JCachePolicy.java @@ -53,6 +53,7 @@ public class JCachePolicy implements Policy { private String cacheName; private Configuration cacheConfiguration; private Expression keyExpression; + private Expression bypassExpression; private boolean enabled = true; @Override @@ -105,7 +106,7 @@ public class JCachePolicy implements Policy { } - return new JCachePolicyProcessor(route.getCamelContext(), cache, keyExpression, processor); + return new JCachePolicyProcessor(route.getCamelContext(), cache, keyExpression, bypassExpression, processor); } public Cache getCache() { @@ -148,6 +149,14 @@ public class JCachePolicy implements Policy { this.keyExpression = keyExpression; } + public Expression getBypassExpression() { + return bypassExpression; + } + + public void setBypassExpression(Expression bypassExpression) { + this.bypassExpression = bypassExpression; + } + public boolean isEnabled() { return enabled; } diff --git a/components/camel-jcache/src/main/java/org/apache/camel/component/jcache/policy/JCachePolicyProcessor.java b/components/camel-jcache/src/main/java/org/apache/camel/component/jcache/policy/JCachePolicyProcessor.java index d561d8518ab..08d8bc22a5b 100644 --- a/components/camel-jcache/src/main/java/org/apache/camel/component/jcache/policy/JCachePolicyProcessor.java +++ b/components/camel-jcache/src/main/java/org/apache/camel/component/jcache/policy/JCachePolicyProcessor.java @@ -33,12 +33,15 @@ public class JCachePolicyProcessor extends DelegateAsyncProcessor { private final CamelContext camelContext; private Cache cache; private Expression keyExpression; + private Expression bypassExpression; - public JCachePolicyProcessor(CamelContext camelContext, Cache cache, Expression keyExpression, Processor processor) { + public JCachePolicyProcessor(CamelContext camelContext, Cache cache, Expression keyExpression, Expression bypassExpression, + Processor processor) { super(processor); this.camelContext = camelContext; this.cache = cache; this.keyExpression = keyExpression; + this.bypassExpression = bypassExpression; } @Override @@ -59,21 +62,26 @@ public class JCachePolicyProcessor extends DelegateAsyncProcessor { return super.process(exchange, callback); } - //Check if cache contains the key - Object value = cache.get(key); - if (value != null) { - // use the cached object in the Exchange without calling the rest of the route - LOG.debug("Cached object is found, skipping the route - key:{}, exchange:{}", key, exchange.getExchangeId()); + Boolean bypass = bypassExpression != null ? bypassExpression.evaluate(exchange, Boolean.class) : Boolean.FALSE; + if (!Boolean.TRUE.equals(bypass)) { + //Check if cache contains the key + Object value = cache.get(key); + if (value != null) { + // use the cached object in the Exchange without calling the rest of the route + LOG.debug("Cached object is found, skipping the route - key:{}, exchange:{}", key, + exchange.getExchangeId()); - exchange.getMessage().setBody(value); + exchange.getMessage().setBody(value); - callback.done(true); - return true; + callback.done(true); + return true; + } + //Not found in cache. Continue route. + LOG.debug("No cached object is found, continue route - key:{}, exchange:{}", key, exchange.getExchangeId()); + } else { + LOG.debug("Bypassing cache - key:{}, exchange:{}", key, exchange.getExchangeId()); } - //Not found in cache. Continue route. - LOG.debug("No cached object is found, continue route - key:{}, exchange:{}", key, exchange.getExchangeId()); - return super.process(exchange, new AsyncCallback() { @Override public void done(boolean doneSync) { @@ -136,4 +144,12 @@ public class JCachePolicyProcessor extends DelegateAsyncProcessor { public void setKeyExpression(Expression keyExpression) { this.keyExpression = keyExpression; } + + public Expression getBypassExpression() { + return bypassExpression; + } + + public void setBypassExpression(Expression bypassExpression) { + this.bypassExpression = bypassExpression; + } } diff --git a/components/camel-jcache/src/test/java/org/apache/camel/component/jcache/policy/JCachePolicyProcessorTest.java b/components/camel-jcache/src/test/java/org/apache/camel/component/jcache/policy/JCachePolicyProcessorTest.java index 1a3cfca32ff..24f1e8b91e3 100644 --- a/components/camel-jcache/src/test/java/org/apache/camel/component/jcache/policy/JCachePolicyProcessorTest.java +++ b/components/camel-jcache/src/test/java/org/apache/camel/component/jcache/policy/JCachePolicyProcessorTest.java @@ -16,6 +16,9 @@ */ package org.apache.camel.component.jcache.policy; +import java.util.HashMap; +import java.util.Map; + import javax.cache.Cache; import javax.cache.CacheManager; import javax.cache.Caching; @@ -245,6 +248,45 @@ public class JCachePolicyProcessorTest extends JCachePolicyTestBase { } + //Use a bypass expression ${header.mybypass} + @Test + public void testBypassExpression() throws Exception { + final String key = randomString(); + final String body = randomString(); + MockEndpoint mock = getMockEndpoint("mock:value"); + Cache cache = lookupCache("simple"); + + Map<String, Object> headers = new HashMap<>(); + headers.put("mykey", key); + headers.put("mybypass", Boolean.TRUE); + + //Send first, key is not in cache + Object responseBody = this.template().requestBodyAndHeaders("direct:cached-bypass", body, headers); + + //We got back the value, mock was called once, value got cached. + assertEquals(generateValue(body), cache.get(key)); + assertEquals(generateValue(body), responseBody); + assertEquals(1, mock.getExchanges().size()); + + //Send again, use another body, but the same key + final String body2 = randomString(); + responseBody = this.template().requestBodyAndHeaders("direct:cached-bypass", body2, headers); + + //We got back the value, the mock was called again, value got cached + assertEquals(generateValue(body2), cache.get(key)); + assertEquals(generateValue(body2), responseBody); + assertEquals(2, mock.getExchanges().size()); + + //Send again, use another body, but the same key; disable bypass + headers.put("mybypass", Boolean.FALSE); + responseBody = this.template().requestBodyAndHeaders("direct:cached-bypass", body, headers); + + //We got back the cached value, the mock was not called again + assertEquals(generateValue(body2), cache.get(key)); + assertEquals(generateValue(body2), responseBody); + assertEquals(2, mock.getExchanges().size()); + } + @Override protected RouteBuilder createRouteBuilder() { return new RouteBuilder() { @@ -299,6 +341,16 @@ public class JCachePolicyProcessorTest extends JCachePolicyTestBase { from("direct:cached-byheader") .policy(jcachePolicy) .to("mock:value"); + + //Use ${header.mykey} as the key, ${header.mybypass} as bypass + jcachePolicy = new JCachePolicy(); + jcachePolicy.setCache(cacheManager.getCache("simple")); + jcachePolicy.setKeyExpression(simple("${header.mykey}")); + jcachePolicy.setBypassExpression(simple("${header.mybypass}")); + + from("direct:cached-bypass") + .policy(jcachePolicy) + .to("mock:value"); } }; }