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 2026/09/05 11:35:40 UTC

(camel) branch camel-4.22.x updated: CAMEL-24623: camel-infinispan - report a QUERY that has no query builder (backport to camel-4.22.x) (#26116)

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch camel-4.22.x
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/camel-4.22.x by this push:
     new 47394a298fbb CAMEL-24623: camel-infinispan - report a QUERY that has no query builder (backport to camel-4.22.x) (#26116)
47394a298fbb is described below

commit 47394a298fbbb460c29ccbf9730dcc7acfb101b4
Author: Andrea Cosentino <an...@gmail.com>
AuthorDate: Sat Sep 5 13:35:34 2026 +0200

    CAMEL-24623: camel-infinispan - report a QUERY that has no query builder (backport to camel-4.22.x) (#26116)
    
    CAMEL-24623: camel-infinispan - report a QUERY that has no query builder
    
    Both producers ran the QUERY operation through an "if (query != null)" with no
    else branch, and buildQuery returns null when neither the queryBuilder option
    nor the CamelInfinispanQueryBuilder header is set. A misconfigured route got its
    own message back with no result, no exception and no log line, which is
    indistinguishable from a query that matched nothing.
    
    The pass-through is kept - it has been asserted by
    producerQueryOperationWithoutQueryBuilder since the operation was contributed in
    CAMEL-9624 - but it is now logged at WARN, naming the cache, the queryBuilder
    option and the header. The builder is also resolved before the cache is looked
    up, so a misconfigured remote route no longer pays a Hot Rod round trip to do
    nothing.
    
    The embedded producer carried the same defect and is fixed the same way.
    
    Backport of fe55a9a454f1 (#26111).
    
    
    Claude-Session: https://claude.ai/code/session_01JpshGTyfSmdq7hC8tuEwrZ
    
    Co-authored-by: Claude Opus 5 (1M context) <no...@anthropic.com>
---
 .../embedded/InfinispanEmbeddedProducer.java       |  30 +++++-
 .../embedded/InfinispanEmbeddedUtil.java           |  10 +-
 .../remote/InfinispanRemoteProducer.java           |  30 +++++-
 .../infinispan/remote/InfinispanRemoteUtil.java    |  10 +-
 .../remote/InfinispanRemoteProducerQueryTest.java  | 106 +++++++++++++++++++++
 5 files changed, 176 insertions(+), 10 deletions(-)

diff --git a/components/camel-infinispan/camel-infinispan-embedded/src/main/java/org/apache/camel/component/infinispan/embedded/InfinispanEmbeddedProducer.java b/components/camel-infinispan/camel-infinispan-embedded/src/main/java/org/apache/camel/component/infinispan/embedded/InfinispanEmbeddedProducer.java
index fc2af696866a..fd95169a6a42 100644
--- a/components/camel-infinispan/camel-infinispan-embedded/src/main/java/org/apache/camel/component/infinispan/embedded/InfinispanEmbeddedProducer.java
+++ b/components/camel-infinispan/camel-infinispan-embedded/src/main/java/org/apache/camel/component/infinispan/embedded/InfinispanEmbeddedProducer.java
@@ -17,13 +17,20 @@
 package org.apache.camel.component.infinispan.embedded;
 
 import org.apache.camel.Message;
+import org.apache.camel.component.infinispan.InfinispanConstants;
+import org.apache.camel.component.infinispan.InfinispanOperation;
 import org.apache.camel.component.infinispan.InfinispanProducer;
+import org.apache.camel.component.infinispan.InfinispanQueryBuilder;
 import org.apache.camel.spi.InvokeOnHeader;
 import org.infinispan.Cache;
 import org.infinispan.commons.api.query.Query;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class InfinispanEmbeddedProducer extends InfinispanProducer<InfinispanEmbeddedManager, InfinispanEmbeddedConfiguration> {
 
+    private static final Logger LOG = LoggerFactory.getLogger(InfinispanEmbeddedProducer.class);
+
     public InfinispanEmbeddedProducer(InfinispanEmbeddedEndpoint endpoint,
                                       String cacheName,
                                       InfinispanEmbeddedManager manager,
@@ -47,11 +54,26 @@ public class InfinispanEmbeddedProducer extends InfinispanProducer<InfinispanEmb
     @SuppressWarnings("unchecked")
     @InvokeOnHeader("QUERY")
     public void onQuery(Message message) {
-        final Cache<Object, Object> cache = getManager().getCache(message, getCacheName(), Cache.class);
-        final Query<?> query = InfinispanEmbeddedUtil.buildQuery(getConfiguration(), cache, message);
+        // resolved before the cache is looked up, so a misconfigured route is reported the same way everywhere
+        final InfinispanQueryBuilder builder = InfinispanEmbeddedUtil.resolveQueryBuilder(getConfiguration(), message);
+        if (builder == null) {
+            warnNoQueryBuilder();
+            return;
+        }
 
-        if (query != null) {
-            setResult(message, query.execute().list());
+        final Cache<Object, Object> cache = getManager().getCache(message, getCacheName(), Cache.class);
+        final Query<?> query = InfinispanEmbeddedUtil.buildQuery(builder, cache);
+        if (query == null) {
+            warnNoQueryBuilder();
+            return;
         }
+
+        setResult(message, query.execute().list());
+    }
+
+    private void warnNoQueryBuilder() {
+        LOG.warn("No query to run for the {} operation on cache {}, the message is passed through unchanged."
+                 + " Set a query builder on the endpoint with the queryBuilder option, or per message with the {} header.",
+                InfinispanOperation.QUERY, getCacheName(), InfinispanConstants.QUERY_BUILDER);
     }
 }
diff --git a/components/camel-infinispan/camel-infinispan-embedded/src/main/java/org/apache/camel/component/infinispan/embedded/InfinispanEmbeddedUtil.java b/components/camel-infinispan/camel-infinispan-embedded/src/main/java/org/apache/camel/component/infinispan/embedded/InfinispanEmbeddedUtil.java
index c8585986a04a..0e15acdcf06a 100644
--- a/components/camel-infinispan/camel-infinispan-embedded/src/main/java/org/apache/camel/component/infinispan/embedded/InfinispanEmbeddedUtil.java
+++ b/components/camel-infinispan/camel-infinispan-embedded/src/main/java/org/apache/camel/component/infinispan/embedded/InfinispanEmbeddedUtil.java
@@ -40,12 +40,20 @@ public final class InfinispanEmbeddedUtil extends InfinispanUtil {
     public static Query<?> buildQuery(
             InfinispanConfiguration configuration, Cache<Object, Object> cache, Message message) {
 
+        return buildQuery(resolveQueryBuilder(configuration, message), cache);
+    }
+
+    /**
+     * The query builder to use for a message: the one carried by the {@link InfinispanConstants#QUERY_BUILDER} header
+     * if there is one, the one configured on the endpoint otherwise. Returns {@code null} when neither is set.
+     */
+    public static InfinispanQueryBuilder resolveQueryBuilder(InfinispanConfiguration configuration, Message message) {
         InfinispanQueryBuilder builder = message.getHeader(InfinispanConstants.QUERY_BUILDER, InfinispanQueryBuilder.class);
         if (builder == null) {
             builder = configuration.getQueryBuilder();
         }
 
-        return buildQuery(builder, cache);
+        return builder;
     }
 
     public static Query<?> buildQuery(InfinispanConfiguration configuration, Cache<Object, Object> cache) {
diff --git a/components/camel-infinispan/camel-infinispan/src/main/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteProducer.java b/components/camel-infinispan/camel-infinispan/src/main/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteProducer.java
index 925988e478dc..850b41aa3d65 100644
--- a/components/camel-infinispan/camel-infinispan/src/main/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteProducer.java
+++ b/components/camel-infinispan/camel-infinispan/src/main/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteProducer.java
@@ -17,14 +17,21 @@
 package org.apache.camel.component.infinispan.remote;
 
 import org.apache.camel.Message;
+import org.apache.camel.component.infinispan.InfinispanConstants;
 import org.apache.camel.component.infinispan.InfinispanEndpoint;
+import org.apache.camel.component.infinispan.InfinispanOperation;
 import org.apache.camel.component.infinispan.InfinispanProducer;
+import org.apache.camel.component.infinispan.InfinispanQueryBuilder;
 import org.apache.camel.spi.InvokeOnHeader;
 import org.infinispan.client.hotrod.RemoteCache;
 import org.infinispan.commons.api.query.Query;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class InfinispanRemoteProducer extends InfinispanProducer<InfinispanRemoteManager, InfinispanRemoteConfiguration> {
 
+    private static final Logger LOG = LoggerFactory.getLogger(InfinispanRemoteProducer.class);
+
     public InfinispanRemoteProducer(InfinispanEndpoint endpoint,
                                     String cacheName,
                                     InfinispanRemoteManager manager,
@@ -49,11 +56,26 @@ public class InfinispanRemoteProducer extends InfinispanProducer<InfinispanRemot
     @SuppressWarnings("unchecked")
     @InvokeOnHeader("QUERY")
     public void onQuery(Message message) {
-        final RemoteCache<Object, Object> cache = getManager().getCache(message, getCacheName(), RemoteCache.class);
-        final Query<?> query = InfinispanRemoteUtil.buildQuery(getConfiguration(), cache, message);
+        // resolved before the cache is opened, so a misconfigured route does not pay a remote call
+        final InfinispanQueryBuilder builder = InfinispanRemoteUtil.resolveQueryBuilder(getConfiguration(), message);
+        if (builder == null) {
+            warnNoQueryBuilder();
+            return;
+        }
 
-        if (query != null) {
-            setResult(message, query.execute().list());
+        final RemoteCache<Object, Object> cache = getManager().getCache(message, getCacheName(), RemoteCache.class);
+        final Query<?> query = InfinispanRemoteUtil.buildQuery(builder, cache);
+        if (query == null) {
+            warnNoQueryBuilder();
+            return;
         }
+
+        setResult(message, query.execute().list());
+    }
+
+    private void warnNoQueryBuilder() {
+        LOG.warn("No query to run for the {} operation on cache {}, the message is passed through unchanged."
+                 + " Set a query builder on the endpoint with the queryBuilder option, or per message with the {} header.",
+                InfinispanOperation.QUERY, getCacheName(), InfinispanConstants.QUERY_BUILDER);
     }
 }
diff --git a/components/camel-infinispan/camel-infinispan/src/main/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteUtil.java b/components/camel-infinispan/camel-infinispan/src/main/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteUtil.java
index e4a32f7fa772..b4ee2028ba0f 100644
--- a/components/camel-infinispan/camel-infinispan/src/main/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteUtil.java
+++ b/components/camel-infinispan/camel-infinispan/src/main/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteUtil.java
@@ -42,6 +42,14 @@ public final class InfinispanRemoteUtil extends InfinispanUtil {
     public static Query<?> buildQuery(
             InfinispanRemoteConfiguration configuration, RemoteCache<Object, Object> cache, Message message) {
 
+        return buildQuery(resolveQueryBuilder(configuration, message), cache);
+    }
+
+    /**
+     * The query builder to use for a message: the one carried by the {@link InfinispanConstants#QUERY_BUILDER} header
+     * if there is one, the one configured on the endpoint otherwise. Returns {@code null} when neither is set.
+     */
+    public static InfinispanQueryBuilder resolveQueryBuilder(InfinispanRemoteConfiguration configuration, Message message) {
         InfinispanQueryBuilder builder = message.getHeader(InfinispanConstants.QUERY_BUILDER, InfinispanQueryBuilder.class);
         if (builder == null) {
             builder = configuration.getQueryBuilder();
@@ -52,7 +60,7 @@ public final class InfinispanRemoteUtil extends InfinispanUtil {
             vectorQueryBuilder.setTypeName(EmbeddingStoreUtil.getTypeName(configuration));
         }
 
-        return buildQuery(builder, cache);
+        return builder;
     }
 
     public static Query<?> buildQuery(InfinispanConfiguration configuration, RemoteCache<Object, Object> cache) {
diff --git a/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteProducerQueryTest.java b/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteProducerQueryTest.java
new file mode 100644
index 000000000000..63d434c0c119
--- /dev/null
+++ b/components/camel-infinispan/camel-infinispan/src/test/java/org/apache/camel/component/infinispan/remote/InfinispanRemoteProducerQueryTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.component.infinispan.remote;
+
+import org.apache.camel.Message;
+import org.apache.camel.Producer;
+import org.apache.camel.component.infinispan.InfinispanConstants;
+import org.apache.camel.component.infinispan.InfinispanQueryBuilder;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.support.DefaultExchange;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
+
+/**
+ * Verifies how the QUERY operation resolves its query builder. Builds the endpoint directly so that nothing tries to
+ * reach an Infinispan server.
+ */
+class InfinispanRemoteProducerQueryTest {
+
+    private DefaultCamelContext context;
+
+    @AfterEach
+    void tearDown() {
+        if (context != null) {
+            context.stop();
+        }
+    }
+
+    private InfinispanRemoteProducer producer(InfinispanRemoteConfiguration configuration) throws Exception {
+        context = new DefaultCamelContext();
+
+        InfinispanRemoteComponent component = new InfinispanRemoteComponent(context);
+        InfinispanRemoteEndpoint endpoint
+                = new InfinispanRemoteEndpoint("infinispan:misc", "misc", component, configuration);
+
+        Producer producer = endpoint.createProducer();
+        return (InfinispanRemoteProducer) producer;
+    }
+
+    private Message message() {
+        return new DefaultExchange(context).getMessage();
+    }
+
+    @Test
+    void aQueryWithoutABuilderTouchesNoCache() throws Exception {
+        InfinispanRemoteProducer producer = producer(new InfinispanRemoteConfiguration());
+
+        Message message = message();
+        message.setBody("unchanged");
+
+        // the message is still passed through (CAMEL-9624 behaviour), but without reaching for a cache first:
+        // the manager here was never started, so any remote call would fail
+        assertThatCode(() -> producer.onQuery(message)).doesNotThrowAnyException();
+        assertThat(message.getBody()).isEqualTo("unchanged");
+    }
+
+    @Test
+    void theBuilderComesFromTheConfiguration() {
+        context = new DefaultCamelContext();
+
+        InfinispanQueryBuilder configured = cache -> null;
+        InfinispanRemoteConfiguration configuration = new InfinispanRemoteConfiguration();
+        configuration.setQueryBuilder(configured);
+
+        assertThat(InfinispanRemoteUtil.resolveQueryBuilder(configuration, message())).isSameAs(configured);
+    }
+
+    @Test
+    void theHeaderWinsOverTheConfiguration() {
+        context = new DefaultCamelContext();
+
+        InfinispanQueryBuilder configured = cache -> null;
+        InfinispanQueryBuilder fromHeader = cache -> null;
+        InfinispanRemoteConfiguration configuration = new InfinispanRemoteConfiguration();
+        configuration.setQueryBuilder(configured);
+
+        Message message = message();
+        message.setHeader(InfinispanConstants.QUERY_BUILDER, fromHeader);
+
+        assertThat(InfinispanRemoteUtil.resolveQueryBuilder(configuration, message)).isSameAs(fromHeader);
+    }
+
+    @Test
+    void noBuilderAnywhereResolvesToNull() {
+        context = new DefaultCamelContext();
+
+        assertThat(InfinispanRemoteUtil.resolveQueryBuilder(new InfinispanRemoteConfiguration(), message())).isNull();
+    }
+}