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 8fbaf0869f61 CAMEL-26556: Allow configuring OpenSearch clients per
endpoint (#29117)
8fbaf0869f61 is described below
commit 8fbaf0869f61a29f1993d27c8db5229985d2115b
Author: Bartosz Popiela <[email protected]>
AuthorDate: Wed Nov 4 09:14:18 2026 +0100
CAMEL-26556: Allow configuring OpenSearch clients per endpoint (#29117)
---
.../camel/catalog/components/opensearch.json | 11 +-
.../camel/catalog/docs/opensearch-component.adoc | 25 ++++
.../opensearch/OpensearchEndpointConfigurer.java | 11 ++
.../opensearch/OpensearchEndpointUriFactory.java | 3 +-
.../camel/component/opensearch/opensearch.json | 11 +-
.../src/main/docs/opensearch-component.adoc | 25 ++++
.../component/opensearch/OpensearchEndpoint.java | 8 +
.../opensearch/OpensearchEndpointClientTest.java | 164 +++++++++++++++++++++
.../dsl/OpensearchEndpointBuilderFactory.java | 36 +++++
9 files changed, 283 insertions(+), 11 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/opensearch.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/opensearch.json
index 146664596a51..911d1cd63484 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/opensearch.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/opensearch.json
@@ -74,10 +74,11 @@
"documentClass": { "index": 14, "kind": "parameter", "displayName":
"Document Class", "group": "advanced", "label": "advanced", "required": false,
"type": "string", "javaType": "java.lang.Class<java.lang.Object>",
"deprecated": false, "autowired": false, "secret": false, "defaultValue":
"ObjectNode", "configurationClass":
"org.apache.camel.component.opensearch.OpensearchConfiguration",
"configurationField": "configuration", "description": "The class to use when
deserializing the docu [...]
"enableSniffer": { "index": 15, "kind": "parameter", "displayName":
"Enable Sniffer", "group": "advanced", "label": "advanced", "required": false,
"type": "boolean", "javaType": "boolean", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": false, "configurationClass":
"org.apache.camel.component.opensearch.OpensearchConfiguration",
"configurationField": "configuration", "description": "Enable automatically
discover nodes from a running OpenSearch cluster. If th [...]
"hostnameVerifier": { "index": 16, "kind": "parameter", "displayName":
"Hostname Verifier", "group": "advanced", "label": "advanced", "required":
false, "type": "object", "javaType": "javax.net.ssl.HostnameVerifier",
"deprecated": false, "autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.opensearch.OpensearchConfiguration",
"configurationField": "configuration", "description": "The class to use as
HostnameVerifier. By default there is no HostnameVe [...]
- "sniffAfterFailureDelay": { "index": 17, "kind": "parameter",
"displayName": "Sniff After Failure Delay", "group": "advanced", "label":
"advanced", "required": false, "type": "integer", "javaType": "int",
"deprecated": false, "autowired": false, "secret": false, "defaultValue":
60000, "configurationClass":
"org.apache.camel.component.opensearch.OpensearchConfiguration",
"configurationField": "configuration", "description": "The delay of a sniff
execution scheduled after a failure (in [...]
- "snifferInterval": { "index": 18, "kind": "parameter", "displayName":
"Sniffer Interval", "group": "advanced", "label": "advanced", "required":
false, "type": "integer", "javaType": "int", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": 300000, "configurationClass":
"org.apache.camel.component.opensearch.OpensearchConfiguration",
"configurationField": "configuration", "description": "The interval between
consecutive ordinary sniff executions in milliseconds. [...]
- "certificatePath": { "index": 19, "kind": "parameter", "displayName":
"Certificate Path", "group": "security", "label": "security", "required":
false, "type": "string", "javaType": "java.lang.String", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false,
"supportFileReference": true, "configurationClass":
"org.apache.camel.component.opensearch.OpensearchConfiguration",
"configurationField": "configuration", "description": "The certificate that can
be used t [...]
- "enableSSL": { "index": 20, "kind": "parameter", "displayName": "Enable
SSL", "group": "security", "label": "security", "required": false, "type":
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": false, "configurationClass":
"org.apache.camel.component.opensearch.OpensearchConfiguration",
"configurationField": "configuration", "description": "Enable SSL" },
- "sslContextParameters": { "index": 21, "kind": "parameter", "displayName":
"Ssl Context Parameters", "group": "security", "label": "security", "required":
false, "type": "object", "javaType":
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.opensearch.OpensearchConfiguration",
"configurationField": "configuration", "description": "To configure security
using SSLContextPara [...]
+ "openSearchClient": { "index": 17, "kind": "parameter", "displayName":
"Open Search Client", "group": "advanced", "label": "advanced", "required":
false, "type": "object", "javaType":
"org.opensearch.client.opensearch.OpenSearchClient", "deprecated": false,
"deprecationNote": "", "autowired": true, "secret": false, "description": "To
use a custom configured OpenSearchClient instance for this endpoint. This takes
precedence over the component's OpenSearchClient and RestClient options. [...]
+ "sniffAfterFailureDelay": { "index": 18, "kind": "parameter",
"displayName": "Sniff After Failure Delay", "group": "advanced", "label":
"advanced", "required": false, "type": "integer", "javaType": "int",
"deprecated": false, "autowired": false, "secret": false, "defaultValue":
60000, "configurationClass":
"org.apache.camel.component.opensearch.OpensearchConfiguration",
"configurationField": "configuration", "description": "The delay of a sniff
execution scheduled after a failure (in [...]
+ "snifferInterval": { "index": 19, "kind": "parameter", "displayName":
"Sniffer Interval", "group": "advanced", "label": "advanced", "required":
false, "type": "integer", "javaType": "int", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": 300000, "configurationClass":
"org.apache.camel.component.opensearch.OpensearchConfiguration",
"configurationField": "configuration", "description": "The interval between
consecutive ordinary sniff executions in milliseconds. [...]
+ "certificatePath": { "index": 20, "kind": "parameter", "displayName":
"Certificate Path", "group": "security", "label": "security", "required":
false, "type": "string", "javaType": "java.lang.String", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false,
"supportFileReference": true, "configurationClass":
"org.apache.camel.component.opensearch.OpensearchConfiguration",
"configurationField": "configuration", "description": "The certificate that can
be used t [...]
+ "enableSSL": { "index": 21, "kind": "parameter", "displayName": "Enable
SSL", "group": "security", "label": "security", "required": false, "type":
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": false, "configurationClass":
"org.apache.camel.component.opensearch.OpensearchConfiguration",
"configurationField": "configuration", "description": "Enable SSL" },
+ "sslContextParameters": { "index": 22, "kind": "parameter", "displayName":
"Ssl Context Parameters", "group": "security", "label": "security", "required":
false, "type": "object", "javaType":
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.opensearch.OpensearchConfiguration",
"configurationField": "configuration", "description": "To configure security
using SSLContextPara [...]
}
}
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/opensearch-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/opensearch-component.adoc
index 0059906dcada..de0f28e29688 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/opensearch-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/opensearch-component.adoc
@@ -131,6 +131,31 @@ camelContext.addComponent("opensearch",
opensearchComponent);
----
+=== Custom clients per endpoint
+
+Use the `openSearchClient` endpoint option to reference an
+`org.opensearch.client.opensearch.OpenSearchClient` in the Camel registry.
+Each endpoint can use a different client, allowing a single route to connect to
+different OpenSearch services with their own authentication and transport
settings.
+
+[source,java]
+----
+camelContext.getRegistry().bind("firstClient", firstClient);
+camelContext.getRegistry().bind("secondClient", secondClient);
+
+from("direct:ping")
+ .to("opensearch:first?operation=Ping&openSearchClient=#bean:firstClient")
+
.to("opensearch:second?operation=Ping&openSearchClient=#bean:secondClient");
+----
+
+The endpoint client takes precedence over the component's `openSearchClient`
and
+`client` options. Without an endpoint override, the component's client
configuration
+continues to apply. Configure connection and authentication settings on the
supplied
+client; `hostAddresses` is not required when supplying a client.
+
+The application owns supplied clients and must close them when they are no
longer
+needed. Camel does not close them when a route stops or when `disconnect=true`.
+
=== Document type
For all the search operations, it is possible to indicate the type of document
to retrieve to get the result already unmarshalled with the expected type.
diff --git
a/components/camel-opensearch/src/generated/java/org/apache/camel/component/opensearch/OpensearchEndpointConfigurer.java
b/components/camel-opensearch/src/generated/java/org/apache/camel/component/opensearch/OpensearchEndpointConfigurer.java
index 375574892d52..777bc2eb6b5d 100644
---
a/components/camel-opensearch/src/generated/java/org/apache/camel/component/opensearch/OpensearchEndpointConfigurer.java
+++
b/components/camel-opensearch/src/generated/java/org/apache/camel/component/opensearch/OpensearchEndpointConfigurer.java
@@ -46,6 +46,8 @@ public class OpensearchEndpointConfigurer extends
PropertyConfigurerSupport impl
case "lazyStartProducer":
target.setLazyStartProducer(property(camelContext, boolean.class, value));
return true;
case "maxretrytimeout":
case "maxRetryTimeout":
target.getConfiguration().setMaxRetryTimeout(property(camelContext, int.class,
value)); return true;
+ case "opensearchclient":
+ case "openSearchClient":
target.setOpenSearchClient(property(camelContext,
org.opensearch.client.opensearch.OpenSearchClient.class, value)); return true;
case "operation":
target.getConfiguration().setOperation(property(camelContext,
org.apache.camel.component.opensearch.OpensearchOperation.class, value));
return true;
case "scrollkeepalivems":
case "scrollKeepAliveMs":
target.getConfiguration().setScrollKeepAliveMs(property(camelContext,
int.class, value)); return true;
@@ -66,6 +68,11 @@ public class OpensearchEndpointConfigurer extends
PropertyConfigurerSupport impl
}
}
+ @Override
+ public String[] getAutowiredNames() {
+ return new String[]{"openSearchClient"};
+ }
+
@Override
public Class<?> getOptionType(String name, boolean ignoreCase) {
switch (ignoreCase ? name.toLowerCase(Locale.ROOT) : name) {
@@ -91,6 +98,8 @@ public class OpensearchEndpointConfigurer extends
PropertyConfigurerSupport impl
case "lazyStartProducer": return boolean.class;
case "maxretrytimeout":
case "maxRetryTimeout": return int.class;
+ case "opensearchclient":
+ case "openSearchClient": return
org.opensearch.client.opensearch.OpenSearchClient.class;
case "operation": return
org.apache.camel.component.opensearch.OpensearchOperation.class;
case "scrollkeepalivems":
case "scrollKeepAliveMs": return int.class;
@@ -137,6 +146,8 @@ public class OpensearchEndpointConfigurer extends
PropertyConfigurerSupport impl
case "lazyStartProducer": return target.isLazyStartProducer();
case "maxretrytimeout":
case "maxRetryTimeout": return
target.getConfiguration().getMaxRetryTimeout();
+ case "opensearchclient":
+ case "openSearchClient": return target.getOpenSearchClient();
case "operation": return target.getConfiguration().getOperation();
case "scrollkeepalivems":
case "scrollKeepAliveMs": return
target.getConfiguration().getScrollKeepAliveMs();
diff --git
a/components/camel-opensearch/src/generated/java/org/apache/camel/component/opensearch/OpensearchEndpointUriFactory.java
b/components/camel-opensearch/src/generated/java/org/apache/camel/component/opensearch/OpensearchEndpointUriFactory.java
index 0fa2f544082f..031e459a57c6 100644
---
a/components/camel-opensearch/src/generated/java/org/apache/camel/component/opensearch/OpensearchEndpointUriFactory.java
+++
b/components/camel-opensearch/src/generated/java/org/apache/camel/component/opensearch/OpensearchEndpointUriFactory.java
@@ -24,7 +24,7 @@ public class OpensearchEndpointUriFactory extends
org.apache.camel.support.compo
private static final Set<String> ENDPOINT_IDENTITY_PROPERTY_NAMES;
private static final Map<String, String> MULTI_VALUE_PREFIXES;
static {
- Set<String> props = new HashSet<>(22);
+ Set<String> props = new HashSet<>(23);
props.add("certificatePath");
props.add("clusterName");
props.add("connectionTimeout");
@@ -38,6 +38,7 @@ public class OpensearchEndpointUriFactory extends
org.apache.camel.support.compo
props.add("indexName");
props.add("lazyStartProducer");
props.add("maxRetryTimeout");
+ props.add("openSearchClient");
props.add("operation");
props.add("scrollKeepAliveMs");
props.add("size");
diff --git
a/components/camel-opensearch/src/generated/resources/META-INF/org/apache/camel/component/opensearch/opensearch.json
b/components/camel-opensearch/src/generated/resources/META-INF/org/apache/camel/component/opensearch/opensearch.json
index 146664596a51..911d1cd63484 100644
---
a/components/camel-opensearch/src/generated/resources/META-INF/org/apache/camel/component/opensearch/opensearch.json
+++
b/components/camel-opensearch/src/generated/resources/META-INF/org/apache/camel/component/opensearch/opensearch.json
@@ -74,10 +74,11 @@
"documentClass": { "index": 14, "kind": "parameter", "displayName":
"Document Class", "group": "advanced", "label": "advanced", "required": false,
"type": "string", "javaType": "java.lang.Class<java.lang.Object>",
"deprecated": false, "autowired": false, "secret": false, "defaultValue":
"ObjectNode", "configurationClass":
"org.apache.camel.component.opensearch.OpensearchConfiguration",
"configurationField": "configuration", "description": "The class to use when
deserializing the docu [...]
"enableSniffer": { "index": 15, "kind": "parameter", "displayName":
"Enable Sniffer", "group": "advanced", "label": "advanced", "required": false,
"type": "boolean", "javaType": "boolean", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": false, "configurationClass":
"org.apache.camel.component.opensearch.OpensearchConfiguration",
"configurationField": "configuration", "description": "Enable automatically
discover nodes from a running OpenSearch cluster. If th [...]
"hostnameVerifier": { "index": 16, "kind": "parameter", "displayName":
"Hostname Verifier", "group": "advanced", "label": "advanced", "required":
false, "type": "object", "javaType": "javax.net.ssl.HostnameVerifier",
"deprecated": false, "autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.opensearch.OpensearchConfiguration",
"configurationField": "configuration", "description": "The class to use as
HostnameVerifier. By default there is no HostnameVe [...]
- "sniffAfterFailureDelay": { "index": 17, "kind": "parameter",
"displayName": "Sniff After Failure Delay", "group": "advanced", "label":
"advanced", "required": false, "type": "integer", "javaType": "int",
"deprecated": false, "autowired": false, "secret": false, "defaultValue":
60000, "configurationClass":
"org.apache.camel.component.opensearch.OpensearchConfiguration",
"configurationField": "configuration", "description": "The delay of a sniff
execution scheduled after a failure (in [...]
- "snifferInterval": { "index": 18, "kind": "parameter", "displayName":
"Sniffer Interval", "group": "advanced", "label": "advanced", "required":
false, "type": "integer", "javaType": "int", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": 300000, "configurationClass":
"org.apache.camel.component.opensearch.OpensearchConfiguration",
"configurationField": "configuration", "description": "The interval between
consecutive ordinary sniff executions in milliseconds. [...]
- "certificatePath": { "index": 19, "kind": "parameter", "displayName":
"Certificate Path", "group": "security", "label": "security", "required":
false, "type": "string", "javaType": "java.lang.String", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false,
"supportFileReference": true, "configurationClass":
"org.apache.camel.component.opensearch.OpensearchConfiguration",
"configurationField": "configuration", "description": "The certificate that can
be used t [...]
- "enableSSL": { "index": 20, "kind": "parameter", "displayName": "Enable
SSL", "group": "security", "label": "security", "required": false, "type":
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": false, "configurationClass":
"org.apache.camel.component.opensearch.OpensearchConfiguration",
"configurationField": "configuration", "description": "Enable SSL" },
- "sslContextParameters": { "index": 21, "kind": "parameter", "displayName":
"Ssl Context Parameters", "group": "security", "label": "security", "required":
false, "type": "object", "javaType":
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.opensearch.OpensearchConfiguration",
"configurationField": "configuration", "description": "To configure security
using SSLContextPara [...]
+ "openSearchClient": { "index": 17, "kind": "parameter", "displayName":
"Open Search Client", "group": "advanced", "label": "advanced", "required":
false, "type": "object", "javaType":
"org.opensearch.client.opensearch.OpenSearchClient", "deprecated": false,
"deprecationNote": "", "autowired": true, "secret": false, "description": "To
use a custom configured OpenSearchClient instance for this endpoint. This takes
precedence over the component's OpenSearchClient and RestClient options. [...]
+ "sniffAfterFailureDelay": { "index": 18, "kind": "parameter",
"displayName": "Sniff After Failure Delay", "group": "advanced", "label":
"advanced", "required": false, "type": "integer", "javaType": "int",
"deprecated": false, "autowired": false, "secret": false, "defaultValue":
60000, "configurationClass":
"org.apache.camel.component.opensearch.OpensearchConfiguration",
"configurationField": "configuration", "description": "The delay of a sniff
execution scheduled after a failure (in [...]
+ "snifferInterval": { "index": 19, "kind": "parameter", "displayName":
"Sniffer Interval", "group": "advanced", "label": "advanced", "required":
false, "type": "integer", "javaType": "int", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": 300000, "configurationClass":
"org.apache.camel.component.opensearch.OpensearchConfiguration",
"configurationField": "configuration", "description": "The interval between
consecutive ordinary sniff executions in milliseconds. [...]
+ "certificatePath": { "index": 20, "kind": "parameter", "displayName":
"Certificate Path", "group": "security", "label": "security", "required":
false, "type": "string", "javaType": "java.lang.String", "deprecated": false,
"deprecationNote": "", "autowired": false, "secret": false,
"supportFileReference": true, "configurationClass":
"org.apache.camel.component.opensearch.OpensearchConfiguration",
"configurationField": "configuration", "description": "The certificate that can
be used t [...]
+ "enableSSL": { "index": 21, "kind": "parameter", "displayName": "Enable
SSL", "group": "security", "label": "security", "required": false, "type":
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": false, "configurationClass":
"org.apache.camel.component.opensearch.OpensearchConfiguration",
"configurationField": "configuration", "description": "Enable SSL" },
+ "sslContextParameters": { "index": 22, "kind": "parameter", "displayName":
"Ssl Context Parameters", "group": "security", "label": "security", "required":
false, "type": "object", "javaType":
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.opensearch.OpensearchConfiguration",
"configurationField": "configuration", "description": "To configure security
using SSLContextPara [...]
}
}
diff --git
a/components/camel-opensearch/src/main/docs/opensearch-component.adoc
b/components/camel-opensearch/src/main/docs/opensearch-component.adoc
index 0059906dcada..de0f28e29688 100644
--- a/components/camel-opensearch/src/main/docs/opensearch-component.adoc
+++ b/components/camel-opensearch/src/main/docs/opensearch-component.adoc
@@ -131,6 +131,31 @@ camelContext.addComponent("opensearch",
opensearchComponent);
----
+=== Custom clients per endpoint
+
+Use the `openSearchClient` endpoint option to reference an
+`org.opensearch.client.opensearch.OpenSearchClient` in the Camel registry.
+Each endpoint can use a different client, allowing a single route to connect to
+different OpenSearch services with their own authentication and transport
settings.
+
+[source,java]
+----
+camelContext.getRegistry().bind("firstClient", firstClient);
+camelContext.getRegistry().bind("secondClient", secondClient);
+
+from("direct:ping")
+ .to("opensearch:first?operation=Ping&openSearchClient=#bean:firstClient")
+
.to("opensearch:second?operation=Ping&openSearchClient=#bean:secondClient");
+----
+
+The endpoint client takes precedence over the component's `openSearchClient`
and
+`client` options. Without an endpoint override, the component's client
configuration
+continues to apply. Configure connection and authentication settings on the
supplied
+client; `hostAddresses` is not required when supplying a client.
+
+The application owns supplied clients and must close them when they are no
longer
+needed. Camel does not close them when a route stops or when `disconnect=true`.
+
=== Document type
For all the search operations, it is possible to indicate the type of document
to retrieve to get the result already unmarshalled with the expected type.
diff --git
a/components/camel-opensearch/src/main/java/org/apache/camel/component/opensearch/OpensearchEndpoint.java
b/components/camel-opensearch/src/main/java/org/apache/camel/component/opensearch/OpensearchEndpoint.java
index 568d53dfae55..4649944f99da 100644
---
a/components/camel-opensearch/src/main/java/org/apache/camel/component/opensearch/OpensearchEndpoint.java
+++
b/components/camel-opensearch/src/main/java/org/apache/camel/component/opensearch/OpensearchEndpoint.java
@@ -24,6 +24,7 @@ import org.apache.camel.spi.BodyType;
import org.apache.camel.spi.BodyType.Carrier;
import org.apache.camel.spi.BodyTypes;
import org.apache.camel.spi.EndpointServiceLocation;
+import org.apache.camel.spi.Metadata;
import org.apache.camel.spi.UriEndpoint;
import org.apache.camel.spi.UriParam;
import org.apache.camel.support.DefaultEndpoint;
@@ -111,6 +112,9 @@ public class OpensearchEndpoint extends DefaultEndpoint
implements EndpointServi
private final OpensearchConfiguration configuration;
private final RestClient client;
+
+ @UriParam(label = "advanced")
+ @Metadata(autowired = true)
private OpenSearchClient openSearchClient;
public OpensearchEndpoint(String uri, OpensearchComponent component,
OpensearchConfiguration config,
@@ -143,6 +147,10 @@ public class OpensearchEndpoint extends DefaultEndpoint
implements EndpointServi
return openSearchClient;
}
+ /**
+ * To use a custom configured OpenSearchClient instance for this endpoint.
This takes precedence over the
+ * component's OpenSearchClient and RestClient options. The application is
responsible for closing the client.
+ */
public void setOpenSearchClient(OpenSearchClient openSearchClient) {
this.openSearchClient = openSearchClient;
}
diff --git
a/components/camel-opensearch/src/test/java/org/apache/camel/component/opensearch/OpensearchEndpointClientTest.java
b/components/camel-opensearch/src/test/java/org/apache/camel/component/opensearch/OpensearchEndpointClientTest.java
new file mode 100644
index 000000000000..1921ca6a7f11
--- /dev/null
+++
b/components/camel-opensearch/src/test/java/org/apache/camel/component/opensearch/OpensearchEndpointClientTest.java
@@ -0,0 +1,164 @@
+/*
+ * 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.opensearch;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import com.sun.net.httpserver.HttpServer;
+import org.apache.camel.CamelContext;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.message.BasicHeader;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.opensearch.client.RestClient;
+import org.opensearch.client.json.jackson.JacksonJsonpMapper;
+import org.opensearch.client.opensearch.OpenSearchClient;
+import org.opensearch.client.transport.rest_client.RestClientTransport;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class OpensearchEndpointClientTest {
+
+ private static final String BASIC_AUTH = "Basic dXNlcjpwYXNz";
+ private static final String BEARER_AUTH = "Bearer test-token";
+
+ private final AtomicInteger firstRequests = new AtomicInteger();
+ private final AtomicInteger secondRequests = new AtomicInteger();
+ private HttpServer firstServer;
+ private HttpServer secondServer;
+
+ @BeforeEach
+ void startServers() throws IOException {
+ firstServer = startServer(BASIC_AUTH, firstRequests);
+ secondServer = startServer(BEARER_AUTH, secondRequests);
+ }
+
+ @AfterEach
+ void stopServers() {
+ firstServer.stop(0);
+ secondServer.stop(0);
+ }
+
+ @Test
+ void endpointClientOverridesComponentClient() throws Exception {
+ try (RestClient firstRestClient = createClient(firstServer,
BASIC_AUTH);
+ RestClient secondRestClient = createClient(secondServer,
BEARER_AUTH);
+ CamelContext context = new DefaultCamelContext()) {
+ OpenSearchClient firstClient = openSearchClient(firstRestClient);
+ OpenSearchClient secondClient = openSearchClient(secondRestClient);
+ context.getRegistry().bind("firstClient", firstClient);
+ context.getRegistry().bind("secondClient", secondClient);
+ OpensearchComponent component = new OpensearchComponent();
+ component.setOpenSearchClient(firstClient);
+ context.addComponent("opensearch", component);
+
+ String firstUri =
"opensearch:first?operation=Ping&openSearchClient=#bean:firstClient";
+ String secondUri =
"opensearch:second?operation=Ping&openSearchClient=#bean:secondClient";
+ context.addRoutes(new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("direct:both").to(firstUri).to(secondUri);
+
from("direct:default").to("opensearch:default?operation=Ping");
+ }
+ });
+ context.start();
+ try (ProducerTemplate template = context.createProducerTemplate())
{
+ assertSame(firstClient, context.getEndpoint(firstUri,
OpensearchEndpoint.class).getOpenSearchClient());
+ assertSame(secondClient, context.getEndpoint(secondUri,
OpensearchEndpoint.class).getOpenSearchClient());
+ assertEquals(Boolean.TRUE, template.requestBody("direct:both",
"", Boolean.class));
+ assertEquals(1, firstRequests.get());
+ assertEquals(1, secondRequests.get());
+
+ assertEquals(Boolean.TRUE,
template.requestBody("direct:default", "", Boolean.class));
+ assertEquals(2, firstRequests.get());
+ }
+ }
+ }
+
+ @ParameterizedTest
+ @ValueSource(booleans = { false, true })
+ void camelCloseNotTheClientOnShutDown(boolean disconnect) throws Exception
{
+ try (RestClient restClient = createClient(firstServer, BASIC_AUTH);
+ CamelContext context = new DefaultCamelContext()) {
+ OpenSearchClient client = openSearchClient(restClient);
+ context.getRegistry().bind("customClient", client);
+ OpensearchComponent component = new OpensearchComponent();
+ component.setClient(restClient);
+ context.addComponent("opensearch", component);
+ String uri =
"opensearch:custom?operation=Ping&openSearchClient=#bean:customClient&disconnect="
+ disconnect;
+ context.addRoutes(new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("direct:ping").to(uri);
+ }
+ });
+ context.start();
+ assertTrue(restClient.isRunning());
+
+ context.stop();
+ assertTrue(restClient.isRunning());
+ }
+ }
+
+ @Test
+ void componentClientIsStillAutowiredWithoutEndpointOverride() throws
Exception {
+ try (RestClient restClient = createClient(firstServer, BASIC_AUTH);
+ CamelContext context = new DefaultCamelContext()) {
+ OpenSearchClient client = openSearchClient(restClient);
+ context.getRegistry().bind("customClient", client);
+ context.start();
+ OpensearchEndpoint endpoint =
context.getEndpoint("opensearch:default", OpensearchEndpoint.class);
+
+ assertSame(client, context.getComponent("opensearch",
OpensearchComponent.class).getOpenSearchClient());
+ assertSame(client, endpoint.getOpenSearchClient());
+ }
+ }
+
+ private static HttpServer startServer(String authorization, AtomicInteger
requests) throws IOException {
+ HttpServer server = HttpServer.create(new
InetSocketAddress("127.0.0.1", 0), 0);
+ server.createContext("/", exchange -> {
+ boolean authorized =
authorization.equals(exchange.getRequestHeaders().getFirst("Authorization"));
+ if (authorized) {
+ requests.incrementAndGet();
+ }
+ exchange.sendResponseHeaders(authorized ? 200 : 401, -1);
+ exchange.close();
+ });
+ server.start();
+ return server;
+ }
+
+ private static RestClient createClient(HttpServer server, String
authorization) {
+ return RestClient.builder(new HttpHost("http", "127.0.0.1",
server.getAddress().getPort()))
+ .setDefaultHeaders(new BasicHeader[] { new
BasicHeader("Authorization", authorization) })
+ .build();
+ }
+
+ private static OpenSearchClient openSearchClient(RestClient client) {
+ return new OpenSearchClient(new RestClientTransport(client, new
JacksonJsonpMapper()));
+ }
+}
diff --git
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OpensearchEndpointBuilderFactory.java
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OpensearchEndpointBuilderFactory.java
index df3035d84f54..99907993fd8e 100644
---
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OpensearchEndpointBuilderFactory.java
+++
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OpensearchEndpointBuilderFactory.java
@@ -619,6 +619,42 @@ public interface OpensearchEndpointBuilderFactory {
doSetProperty("hostnameVerifier", hostnameVerifier);
return this;
}
+ /**
+ * To use a custom configured OpenSearchClient instance for this
+ * endpoint. This takes precedence over the component's
OpenSearchClient
+ * and RestClient options. The application is responsible for closing
+ * the client.
+ *
+ * The option is a:
+ * <code>org.opensearch.client.opensearch.OpenSearchClient</code> type.
+ *
+ * Group: advanced
+ *
+ * @param openSearchClient the value to set
+ * @return the dsl builder
+ */
+ default AdvancedOpensearchEndpointBuilder
openSearchClient(org.opensearch.client.opensearch.OpenSearchClient
openSearchClient) {
+ doSetProperty("openSearchClient", openSearchClient);
+ return this;
+ }
+ /**
+ * To use a custom configured OpenSearchClient instance for this
+ * endpoint. This takes precedence over the component's
OpenSearchClient
+ * and RestClient options. The application is responsible for closing
+ * the client.
+ *
+ * The option will be converted to a
+ * <code>org.opensearch.client.opensearch.OpenSearchClient</code> type.
+ *
+ * Group: advanced
+ *
+ * @param openSearchClient the value to set
+ * @return the dsl builder
+ */
+ default AdvancedOpensearchEndpointBuilder openSearchClient(String
openSearchClient) {
+ doSetProperty("openSearchClient", openSearchClient);
+ return this;
+ }
/**
* The delay of a sniff execution scheduled after a failure (in
* milliseconds).