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 0216fa998960 CAMEL-25507: camel-lucene - Each endpoint keeps the
options of its own URI
0216fa998960 is described below
commit 0216fa9989604d9b688afab3d30a4ace8fa8fc4e
Author: allthingssecurity <[email protected]>
AuthorDate: Sat Oct 10 13:06:56 2026 +0530
CAMEL-25507: camel-lucene - Each endpoint keeps the options of its own URI
LuceneComponent parsed every endpoint URI into its single
LuceneConfiguration and gave that same object to every endpoint, so each
new lucene endpoint overwrote the host, operation, index directory,
analyzer and maxHits of the others. With several lucene endpoints in a
CamelContext, a query searched the index of the endpoint created last and
returned no hits or another index's documents, without an error.
Each URI is now parsed into its own copy of the component configuration.
Closes #27640
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
.../camel/component/lucene/LuceneComponent.java | 6 +-
.../component/lucene/LuceneConfiguration.java | 14 ++-
.../lucene/LuceneEndpointConfigurationTest.java | 113 +++++++++++++++++++++
3 files changed, 130 insertions(+), 3 deletions(-)
diff --git
a/components/camel-lucene/src/main/java/org/apache/camel/component/lucene/LuceneComponent.java
b/components/camel-lucene/src/main/java/org/apache/camel/component/lucene/LuceneComponent.java
index 72c18b7a0b10..6abe034a2192 100644
---
a/components/camel-lucene/src/main/java/org/apache/camel/component/lucene/LuceneComponent.java
+++
b/components/camel-lucene/src/main/java/org/apache/camel/component/lucene/LuceneComponent.java
@@ -43,8 +43,10 @@ public class LuceneComponent extends DefaultComponent {
@Override
protected Endpoint createEndpoint(String uri, String remaining,
Map<String, Object> parameters)
throws Exception {
- config.parseURI(new URI(uri), parameters, this);
- LuceneEndpoint luceneEndpoint = new LuceneEndpoint(uri, this, config);
+ // each endpoint parses its URI into its own copy, as the component
configuration is shared
+ LuceneConfiguration endpointConfig = config.copy();
+ endpointConfig.parseURI(new URI(uri), parameters, this);
+ LuceneEndpoint luceneEndpoint = new LuceneEndpoint(uri, this,
endpointConfig);
setProperties(luceneEndpoint, parameters);
return luceneEndpoint;
}
diff --git
a/components/camel-lucene/src/main/java/org/apache/camel/component/lucene/LuceneConfiguration.java
b/components/camel-lucene/src/main/java/org/apache/camel/component/lucene/LuceneConfiguration.java
index 74aec3338e0c..92bde35e9706 100644
---
a/components/camel-lucene/src/main/java/org/apache/camel/component/lucene/LuceneConfiguration.java
+++
b/components/camel-lucene/src/main/java/org/apache/camel/component/lucene/LuceneConfiguration.java
@@ -21,6 +21,7 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
+import org.apache.camel.RuntimeCamelException;
import org.apache.camel.spi.Metadata;
import org.apache.camel.spi.UriParam;
import org.apache.camel.spi.UriParams;
@@ -29,7 +30,7 @@ import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
@UriParams
-public class LuceneConfiguration {
+public class LuceneConfiguration implements Cloneable {
private transient URI uri;
private transient String authority;
@@ -55,6 +56,17 @@ public class LuceneConfiguration {
this.uri = uri;
}
+ /**
+ * Returns a copy of this configuration
+ */
+ public LuceneConfiguration copy() {
+ try {
+ return (LuceneConfiguration) clone();
+ } catch (CloneNotSupportedException e) {
+ throw new RuntimeCamelException(e);
+ }
+ }
+
public void parseURI(URI uri, Map<String, Object> parameters,
LuceneComponent component) throws Exception {
String protocol = uri.getScheme();
diff --git
a/components/camel-lucene/src/test/java/org/apache/camel/component/lucene/LuceneEndpointConfigurationTest.java
b/components/camel-lucene/src/test/java/org/apache/camel/component/lucene/LuceneEndpointConfigurationTest.java
new file mode 100644
index 000000000000..4e5acd0d45f1
--- /dev/null
+++
b/components/camel-lucene/src/test/java/org/apache/camel/component/lucene/LuceneEndpointConfigurationTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.lucene;
+
+import java.io.File;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.processor.lucene.support.Hits;
+import org.apache.camel.spi.Registry;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.TextField;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.IndexWriterConfig;
+import org.apache.lucene.store.FSDirectory;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+/**
+ * Each lucene endpoint keeps the options of its own URI, also when the
CamelContext has several lucene endpoints.
+ */
+class LuceneEndpointConfigurationTest extends CamelTestSupport {
+
+ private static final String QUERY_A =
"lucene:indexA:query?analyzer=#stdAnalyzer&indexDir=#dirA&maxHits=5";
+ private static final String QUERY_B =
"lucene:indexB:query?analyzer=#stdAnalyzer&indexDir=#dirB&maxHits=20";
+
+ @TempDir
+ static File dirA;
+ @TempDir
+ static File dirB;
+
+ @BeforeAll
+ static void createIndexes() throws Exception {
+ createIndex(dirA, "alpha");
+ createIndex(dirB, "beta");
+ }
+
+ private static void createIndex(File indexDir, String term) throws
Exception {
+ try (FSDirectory dir = FSDirectory.open(indexDir.toPath());
+ IndexWriter writer = new IndexWriter(dir, new
IndexWriterConfig(new StandardAnalyzer()))) {
+ for (int i = 0; i < 10; i++) {
+ Document doc = new Document();
+ doc.add(new TextField("contents", term + " document " + i,
Field.Store.YES));
+ writer.addDocument(doc);
+ }
+ writer.commit();
+ }
+ }
+
+ @Override
+ protected void bindToRegistry(Registry registry) {
+ registry.bind("dirA", dirA);
+ registry.bind("dirB", dirB);
+ registry.bind("stdAnalyzer", new StandardAnalyzer());
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("direct:a").to(QUERY_A);
+ from("direct:b").to(QUERY_B);
+ }
+ };
+ }
+
+ @Test
+ void endpointsKeepTheirOwnOptions() {
+ LuceneEndpoint a = context.getEndpoint(QUERY_A, LuceneEndpoint.class);
+ LuceneEndpoint b = context.getEndpoint(QUERY_B, LuceneEndpoint.class);
+ assertEquals(dirA, a.getConfig().getIndexDir(), "indexDir of " +
QUERY_A);
+ assertEquals(5, a.getConfig().getMaxHits(), "maxHits of " + QUERY_A);
+ assertEquals("indexA", a.getConfig().getHost(), "host of " + QUERY_A);
+ assertEquals(dirB, b.getConfig().getIndexDir(), "indexDir of " +
QUERY_B);
+ assertEquals(20, b.getConfig().getMaxHits(), "maxHits of " + QUERY_B);
+ assertEquals("indexB", b.getConfig().getHost(), "host of " + QUERY_B);
+ }
+
+ @Test
+ void eachQueryEndpointSearchesItsOwnIndex() {
+ Exchange a = template.send("direct:a", e ->
e.getIn().setHeader(LuceneConstants.HEADER_QUERY, "alpha"));
+ assertNull(a.getException());
+ assertEquals(5, a.getMessage().getBody(Hits.class).getNumberOfHits(),
+ QUERY_A + " must search its own index (10 alpha documents)
with its own maxHits (5)");
+
+ Exchange b = template.send("direct:b", e ->
e.getIn().setHeader(LuceneConstants.HEADER_QUERY, "beta"));
+ assertNull(b.getException());
+ assertEquals(10, b.getMessage().getBody(Hits.class).getNumberOfHits(),
+ QUERY_B + " must search its own index (10 beta documents)");
+ }
+}