port;
+
+ /**
+ * The OpenSearch container image to use.
+ * Defaults to the opensearch image provided by OpenSearch.
+ */
+ @ConfigItem(defaultValue = "docker.io/opensearchproject/opensearch:2.4.1")
+ public String imageName;
+
+ /**
+ * The value for the ES_JAVA_OPTS env variable.
+ * Defaults to setting the heap to 512MB min - 1GB max.
+ */
+ @ConfigItem(defaultValue = "-Xms512m -Xmx1g")
+ public String javaOpts;
+
+ /**
+ * Indicates if the OpenSearch server managed by Quarkus Dev Services is shared.
+ * When shared, Quarkus looks for running containers using label-based service discovery.
+ * If a matching container is found, it is used, and so a second one is not started.
+ * Otherwise, Dev Services for OpenSearch starts a new container.
+ *
+ * The discovery uses the {@code quarkus-dev-service-opensearch} label.
+ * The value is configured using the {@code service-name} property.
+ *
+ * Container sharing is only used in dev mode.
+ */
+ @ConfigItem(defaultValue = "true")
+ public boolean shared;
+
+ /**
+ * The value of the {@code quarkus-dev-service-opensearch} label attached to the started container.
+ * This property is used when {@code shared} is set to {@code true}.
+ * In this case, before starting a container, Dev Services for OpenSearch looks for a container with the
+ * {@code quarkus-dev-service-opensearch} label
+ * set to the configured value. If found, it will use this container instead of starting a new one. Otherwise it
+ * starts a new container with the {@code quarkus-dev-service-opensearch} label set to the specified value.
+ *
+ * This property is used when you need multiple shared OpenSearch servers.
+ */
+ @ConfigItem(defaultValue = "opensearch")
+ public String serviceName;
+}
diff --git a/opensearch-rest-client-common/deployment/src/main/java/io/quarkiverse/opensearch/restclient/common/deployment/OpenSearchRestClientProcessor.java b/opensearch-rest-client-common/deployment/src/main/java/io/quarkiverse/opensearch/restclient/common/deployment/OpenSearchRestClientProcessor.java
new file mode 100644
index 0000000..fc53ce6
--- /dev/null
+++ b/opensearch-rest-client-common/deployment/src/main/java/io/quarkiverse/opensearch/restclient/common/deployment/OpenSearchRestClientProcessor.java
@@ -0,0 +1,23 @@
+package io.quarkiverse.opensearch.restclient.common.deployment;
+
+import io.quarkus.deployment.Feature;
+import io.quarkus.deployment.annotations.BuildProducer;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.builditem.ExtensionSslNativeSupportBuildItem;
+import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
+
+class OpenSearchRestClientProcessor {
+
+ @BuildStep
+ public void build(BuildProducer extensionSslNativeSupport) {
+ // Indicates that this extension would like the SSL support to be enabled
+ extensionSslNativeSupport.produce(new ExtensionSslNativeSupportBuildItem(Feature.ELASTICSEARCH_REST_CLIENT_COMMON));
+ }
+
+ @BuildStep
+ public ReflectiveClassBuildItem registerForReflection() {
+ return new ReflectiveClassBuildItem(true, true,
+ "org.apache.logging.log4j.message.ReusableMessageFactory",
+ "org.apache.logging.log4j.message.DefaultFlowMessageFactory");
+ }
+}
diff --git a/opensearch-rest-client-common/pom.xml b/opensearch-rest-client-common/pom.xml
new file mode 100644
index 0000000..aea44bc
--- /dev/null
+++ b/opensearch-rest-client-common/pom.xml
@@ -0,0 +1,20 @@
+
+
+
+ io.quarkiverse.opensearch
+ quarkus-opensearch-parent
+ 0.1.0-SNAPSHOT
+ ../pom.xml
+
+ 4.0.0
+
+ quarkus-opensearch-rest-client-common-parent
+ Quarkus - OpenSearch client common
+ pom
+
+ deployment
+ runtime
+
+
diff --git a/opensearch-rest-client-common/runtime/pom.xml b/opensearch-rest-client-common/runtime/pom.xml
new file mode 100644
index 0000000..e05d32d
--- /dev/null
+++ b/opensearch-rest-client-common/runtime/pom.xml
@@ -0,0 +1,75 @@
+
+
+
+ io.quarkiverse.opensearch
+ quarkus-opensearch-rest-client-common-parent
+ 0.1.0-SNAPSHOT
+
+ 4.0.0
+
+ quarkus-opensearch-rest-client-common
+ Quarkus - OpenSearch REST client common - Runtime
+ OpenSearch REST client common - Runtime
+
+
+ io.quarkus
+ quarkus-core
+
+
+ org.opensearch.client
+ opensearch-rest-client
+
+
+ commons-logging
+ commons-logging
+
+
+
+
+ io.quarkus
+ quarkus-apache-httpclient
+
+
+ org.jboss.logging
+ commons-logging-jboss-logging
+
+
+ org.opensearch.client
+ opensearch-rest-client-sniffer
+
+
+ commons-logging
+ commons-logging
+
+
+
+
+ org.graalvm.nativeimage
+ svm
+ provided
+
+
+
+
+
+
+ io.quarkus
+ quarkus-extension-maven-plugin
+
+
+ maven-compiler-plugin
+
+
+
+ io.quarkus
+ quarkus-extension-processor
+ ${quarkus.version}
+
+
+
+
+
+
+
diff --git a/opensearch-rest-client-common/runtime/src/main/java/io/quarkiverse/opensearch/restclient/common/runtime/graal/Substitute_RestClient.java b/opensearch-rest-client-common/runtime/src/main/java/io/quarkiverse/opensearch/restclient/common/runtime/graal/Substitute_RestClient.java
new file mode 100644
index 0000000..9f176c3
--- /dev/null
+++ b/opensearch-rest-client-common/runtime/src/main/java/io/quarkiverse/opensearch/restclient/common/runtime/graal/Substitute_RestClient.java
@@ -0,0 +1,131 @@
+package io.quarkiverse.opensearch.restclient.common.runtime.graal;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.http.HttpHost;
+import org.apache.http.annotation.Contract;
+import org.apache.http.annotation.ThreadingBehavior;
+import org.apache.http.auth.AuthScheme;
+import org.apache.http.client.AuthCache;
+import org.apache.http.conn.SchemePortResolver;
+import org.apache.http.conn.UnsupportedSchemeException;
+import org.apache.http.impl.auth.BasicScheme;
+import org.apache.http.impl.client.BasicAuthCache;
+import org.apache.http.impl.conn.DefaultSchemePortResolver;
+import org.apache.http.util.Args;
+import org.opensearch.client.Node;
+import org.opensearch.client.RestClient;
+
+import com.oracle.svm.core.annotate.Alias;
+import com.oracle.svm.core.annotate.Substitute;
+import com.oracle.svm.core.annotate.TargetClass;
+
+/**
+ * {@link BasicAuthCache} used in the {@link RestClient} is using
+ * serialization which is not supported by GraalVM.
+ *
+ * We substitute it with an implementation which does not use serialization.
+ */
+@TargetClass(className = "org.opensearch.client.RestClient")
+final class Substitute_RestClient {
+
+ @Alias
+ private ConcurrentMap blacklist;
+
+ @Alias
+ private volatile NodeTuple> nodeTuple;
+
+ @Substitute
+ public synchronized void setNodes(Collection nodes) {
+ if (nodes == null || nodes.isEmpty()) {
+ throw new IllegalArgumentException("nodes must not be null or empty");
+ }
+ AuthCache authCache = new NoSerializationBasicAuthCache();
+
+ Map nodesByHost = new LinkedHashMap<>();
+ for (Node node : nodes) {
+ Objects.requireNonNull(node, "node cannot be null");
+ // TODO should we throw an IAE if we have two nodes with the same host?
+ nodesByHost.put(node.getHost(), node);
+ authCache.put(node.getHost(), new BasicScheme());
+ }
+ this.nodeTuple = new NodeTuple<>(List.copyOf(nodesByHost.values()), authCache);
+ this.blacklist.clear();
+ }
+
+ @TargetClass(className = "org.opensearch.client.DeadHostState")
+ final static class DeadHostState {
+ }
+
+ @TargetClass(className = "org.opensearch.client.RestClient", innerClass = "NodeTuple")
+ final static class NodeTuple {
+
+ @Alias
+ NodeTuple(final T nodes, final AuthCache authCache) {
+ }
+ }
+
+ @Contract(threading = ThreadingBehavior.SAFE)
+ private static final class NoSerializationBasicAuthCache implements AuthCache {
+
+ private final Map map;
+ private final SchemePortResolver schemePortResolver;
+
+ public NoSerializationBasicAuthCache(final SchemePortResolver schemePortResolver) {
+ this.map = new ConcurrentHashMap<>();
+ this.schemePortResolver = schemePortResolver != null ? schemePortResolver
+ : DefaultSchemePortResolver.INSTANCE;
+ }
+
+ public NoSerializationBasicAuthCache() {
+ this(null);
+ }
+
+ protected HttpHost getKey(final HttpHost host) {
+ if (host.getPort() <= 0) {
+ final int port;
+ try {
+ port = schemePortResolver.resolve(host);
+ } catch (final UnsupportedSchemeException ignore) {
+ return host;
+ }
+ return new HttpHost(host.getHostName(), port, host.getSchemeName());
+ } else {
+ return host;
+ }
+ }
+
+ @Override
+ public void put(final HttpHost host, final AuthScheme authScheme) {
+ Args.notNull(host, "HTTP host");
+ if (authScheme == null) {
+ return;
+ }
+ this.map.put(getKey(host), authScheme);
+ }
+
+ @Override
+ public AuthScheme get(final HttpHost host) {
+ Args.notNull(host, "HTTP host");
+ return this.map.get(getKey(host));
+ }
+
+ @Override
+ public void remove(final HttpHost host) {
+ Args.notNull(host, "HTTP host");
+ this.map.remove(getKey(host));
+ }
+
+ @Override
+ public void clear() {
+ this.map.clear();
+ }
+
+ @Override
+ public String toString() {
+ return this.map.toString();
+ }
+ }
+}
diff --git a/opensearch-rest-client-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/opensearch-rest-client-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml
new file mode 100644
index 0000000..d573cac
--- /dev/null
+++ b/opensearch-rest-client-common/runtime/src/main/resources/META-INF/quarkus-extension.yaml
@@ -0,0 +1,10 @@
+---
+artifact: ${project.groupId}:${project.artifactId}:${project.version}
+name: "OpenSearch REST Client Common"
+metadata:
+ keywords:
+ - "search"
+ categories:
+ - "data"
+ status: "stable"
+ unlisted: "true"
\ No newline at end of file
diff --git a/opensearch-rest-client/deployment/pom.xml b/opensearch-rest-client/deployment/pom.xml
new file mode 100644
index 0000000..8430163
--- /dev/null
+++ b/opensearch-rest-client/deployment/pom.xml
@@ -0,0 +1,101 @@
+
+
+ 4.0.0
+
+ io.quarkiverse.opensearch
+ quarkus-opensearch-rest-client-parent
+ 0.1.0-SNAPSHOT
+ ../pom.xml
+
+
+ quarkus-opensearch-rest-client-deployment
+ Quarkus - OpenSearch REST client - Deployment
+
+
+
+ io.quarkus
+ quarkus-core-deployment
+
+
+ io.quarkiverse.opensearch
+ quarkus-opensearch-rest-client-common-deployment
+
+
+ io.quarkiverse.opensearch
+ quarkus-opensearch-rest-client
+
+
+ io.quarkus
+ quarkus-arc-deployment
+
+
+ io.quarkus
+ quarkus-smallrye-health-spi
+
+
+
+
+ io.quarkus
+ quarkus-junit5-internal
+ test
+
+
+ io.quarkus
+ quarkus-resteasy-jackson-deployment
+ test
+
+
+ io.rest-assured
+ rest-assured
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ io.quarkus
+ quarkus-extension-processor
+ ${quarkus.version}
+
+
+
+
+
+ maven-surefire-plugin
+
+ true
+
+
+
+
+
+
+
+ test-opensearch
+
+
+ test-containers
+
+
+
+
+
+ maven-surefire-plugin
+
+ false
+
+
+
+
+
+
+
+
diff --git a/opensearch-rest-client/deployment/src/main/java/io/quarkiverse/opensearch/restclient/lowlevel/deployment/OpenSearchBuildTimeConfig.java b/opensearch-rest-client/deployment/src/main/java/io/quarkiverse/opensearch/restclient/lowlevel/deployment/OpenSearchBuildTimeConfig.java
new file mode 100644
index 0000000..c70fd9e
--- /dev/null
+++ b/opensearch-rest-client/deployment/src/main/java/io/quarkiverse/opensearch/restclient/lowlevel/deployment/OpenSearchBuildTimeConfig.java
@@ -0,0 +1,14 @@
+package io.quarkiverse.opensearch.restclient.lowlevel.deployment;
+
+import io.quarkus.runtime.annotations.ConfigItem;
+import io.quarkus.runtime.annotations.ConfigPhase;
+import io.quarkus.runtime.annotations.ConfigRoot;
+
+@ConfigRoot(name = "opensearch", phase = ConfigPhase.BUILD_TIME)
+public class OpenSearchBuildTimeConfig {
+ /**
+ * Whether a health check is published in case the smallrye-health extension is present.
+ */
+ @ConfigItem(name = "health.enabled", defaultValue = "true")
+ public boolean healthEnabled;
+}
diff --git a/opensearch-rest-client/deployment/src/main/java/io/quarkiverse/opensearch/restclient/lowlevel/deployment/OpenSearchLowLevelClientProcessor.java b/opensearch-rest-client/deployment/src/main/java/io/quarkiverse/opensearch/restclient/lowlevel/deployment/OpenSearchLowLevelClientProcessor.java
new file mode 100644
index 0000000..db94f58
--- /dev/null
+++ b/opensearch-rest-client/deployment/src/main/java/io/quarkiverse/opensearch/restclient/lowlevel/deployment/OpenSearchLowLevelClientProcessor.java
@@ -0,0 +1,52 @@
+package io.quarkiverse.opensearch.restclient.lowlevel.deployment;
+
+import org.jboss.jandex.DotName;
+
+import io.quarkiverse.opensearch.restclient.common.deployment.DevservicesOpenSearchBuildItem;
+import io.quarkiverse.opensearch.restclient.lowlevel.OpenSearchClientConfig;
+import io.quarkiverse.opensearch.restclient.lowlevel.runtime.OpenSearchRestClientProducer;
+import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
+import io.quarkus.arc.deployment.BeanDefiningAnnotationBuildItem;
+import io.quarkus.arc.processor.DotNames;
+import io.quarkus.deployment.Feature;
+import io.quarkus.deployment.annotations.BuildProducer;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.builditem.FeatureBuildItem;
+import io.quarkus.smallrye.health.deployment.spi.HealthBuildItem;
+
+class OpenSearchLowLevelClientProcessor {
+
+ private static final DotName OPENSEARCH_CLIENT_CONFIG = DotName.createSimple(OpenSearchClientConfig.class.getName());
+
+ @BuildStep
+ FeatureBuildItem feature() {
+ return new FeatureBuildItem(Feature.ELASTICSEARCH_REST_CLIENT);
+ }
+
+ @BuildStep
+ AdditionalBeanBuildItem build() {
+ return AdditionalBeanBuildItem.unremovableOf(OpenSearchRestClientProducer.class);
+ }
+
+ @BuildStep
+ void openSearchClientConfigSupport(BuildProducer additionalBeans,
+ BuildProducer beanDefiningAnnotations) {
+ // add the @OpenSearchClientConfig class otherwise it won't be registered as a qualifier
+ additionalBeans.produce(AdditionalBeanBuildItem.builder().addBeanClass(OpenSearchClientConfig.class).build());
+
+ beanDefiningAnnotations
+ .produce(new BeanDefiningAnnotationBuildItem(OPENSEARCH_CLIENT_CONFIG, DotNames.APPLICATION_SCOPED, false));
+ }
+
+ @BuildStep
+ HealthBuildItem addHealthCheck(OpenSearchBuildTimeConfig buildTimeConfig) {
+ return new HealthBuildItem("io.quarkiverse.opensearch.restclient.lowlevel.runtime.health.OpenSearchHealthCheck",
+ buildTimeConfig.healthEnabled);
+ }
+
+ @BuildStep
+ DevservicesOpenSearchBuildItem devServices() {
+ return new DevservicesOpenSearchBuildItem("quarkiverse.opensearch.hosts");
+ }
+
+}
diff --git a/opensearch-rest-client/deployment/src/test/java/io/quarkiverse/opensearch/restclient/lowlevel/runtime/DevServicesOpenSearchDevModeTestCase.java b/opensearch-rest-client/deployment/src/test/java/io/quarkiverse/opensearch/restclient/lowlevel/runtime/DevServicesOpenSearchDevModeTestCase.java
new file mode 100644
index 0000000..4134ba7
--- /dev/null
+++ b/opensearch-rest-client/deployment/src/test/java/io/quarkiverse/opensearch/restclient/lowlevel/runtime/DevServicesOpenSearchDevModeTestCase.java
@@ -0,0 +1,34 @@
+package io.quarkiverse.opensearch.restclient.lowlevel.runtime;
+
+import static org.hamcrest.Matchers.equalTo;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import io.quarkus.test.QuarkusDevModeTest;
+import io.restassured.RestAssured;
+
+public class DevServicesOpenSearchDevModeTestCase {
+ @RegisterExtension
+ static QuarkusDevModeTest test = new QuarkusDevModeTest()
+ .withApplicationRoot((jar) -> jar
+ .addClass(TestResource.class));
+
+ @Test
+ public void testDatasource() throws Exception {
+ var fruit = new TestResource.Fruit();
+ fruit.id = "1";
+ fruit.name = "banana";
+ fruit.color = "yellow";
+
+ RestAssured
+ .given().body(fruit).contentType("application/json")
+ .when().post("/fruits")
+ .then().statusCode(204);
+
+ RestAssured.when().get("/fruits/search?term=color&match=yellow")
+ .then()
+ .statusCode(200)
+ .body(equalTo("[{\"id\":\"1\",\"name\":\"banana\",\"color\":\"yellow\"}]"));
+ }
+}
diff --git a/opensearch-rest-client/deployment/src/test/java/io/quarkiverse/opensearch/restclient/lowlevel/runtime/OpenSearchClientConfigTest.java b/opensearch-rest-client/deployment/src/test/java/io/quarkiverse/opensearch/restclient/lowlevel/runtime/OpenSearchClientConfigTest.java
new file mode 100644
index 0000000..8574724
--- /dev/null
+++ b/opensearch-rest-client/deployment/src/test/java/io/quarkiverse/opensearch/restclient/lowlevel/runtime/OpenSearchClientConfigTest.java
@@ -0,0 +1,49 @@
+package io.quarkiverse.opensearch.restclient.lowlevel.runtime;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+
+import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.opensearch.client.RestClientBuilder;
+
+import io.quarkiverse.opensearch.restclient.lowlevel.OpenSearchClientConfig;
+import io.quarkus.test.QuarkusUnitTest;
+
+public class OpenSearchClientConfigTest {
+ @RegisterExtension
+ static final QuarkusUnitTest TEST = new QuarkusUnitTest()
+ .setArchiveProducer(
+ () -> ShrinkWrap.create(JavaArchive.class).addClasses(TestConfigurator.class, RestClientBuilderHelper.class)
+ .addAsResource(new StringAsset("quarkiverse.opensearch.hosts=opensearch:9200"),
+ "application.properties"));
+
+ @Inject
+ OpenSearchConfig config;
+
+ @Test
+ public void testRestClientBuilderHelperWithOpenSearchClientConfig() {
+ RestClientBuilderHelper.createRestClientBuilder(config).build();
+ assertTrue(TestConfigurator.invoked);
+ }
+
+ @OpenSearchClientConfig
+ @ApplicationScoped
+ public static class TestConfigurator implements RestClientBuilder.HttpClientConfigCallback {
+
+ private static boolean invoked = false;
+
+ @Override
+ public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder builder) {
+ invoked = true;
+ return builder;
+ }
+ }
+
+}
diff --git a/opensearch-rest-client/deployment/src/test/java/io/quarkiverse/opensearch/restclient/lowlevel/runtime/TestResource.java b/opensearch-rest-client/deployment/src/test/java/io/quarkiverse/opensearch/restclient/lowlevel/runtime/TestResource.java
new file mode 100644
index 0000000..e4a80a4
--- /dev/null
+++ b/opensearch-rest-client/deployment/src/test/java/io/quarkiverse/opensearch/restclient/lowlevel/runtime/TestResource.java
@@ -0,0 +1,65 @@
+package io.quarkiverse.opensearch.restclient.lowlevel.runtime;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.QueryParam;
+
+import org.apache.http.util.EntityUtils;
+import org.opensearch.client.Request;
+import org.opensearch.client.Response;
+import org.opensearch.client.RestClient;
+
+import io.vertx.core.json.JsonArray;
+import io.vertx.core.json.JsonObject;
+
+@Path("/fruits")
+public class TestResource {
+ @Inject
+ RestClient restClient;
+
+ @POST
+ public void index(Fruit fruit) throws IOException {
+ Request request = new Request(
+ "PUT",
+ "/fruits/_doc/" + fruit.id + "?refresh=true");
+ request.setJsonEntity(JsonObject.mapFrom(fruit).toString());
+ restClient.performRequest(request);
+ }
+
+ @GET
+ @Path("/search")
+ public List search(@QueryParam("term") String term, @QueryParam("match") String match) throws IOException {
+ Request request = new Request(
+ "GET",
+ "/fruits/_search");
+ //construct a JSON query like {"query": {"match": {"": " results = new ArrayList<>(hits.size());
+ for (int i = 0; i < hits.size(); i++) {
+ JsonObject hit = hits.getJsonObject(i);
+ Fruit fruit = hit.getJsonObject("_source").mapTo(Fruit.class);
+ results.add(fruit);
+ }
+ return results;
+ }
+
+ public static class Fruit {
+ public String id;
+ public String name;
+ public String color;
+ }
+}
diff --git a/opensearch-rest-client/pom.xml b/opensearch-rest-client/pom.xml
new file mode 100644
index 0000000..58f9c82
--- /dev/null
+++ b/opensearch-rest-client/pom.xml
@@ -0,0 +1,22 @@
+
+
+
+ io.quarkiverse.opensearch
+ quarkus-opensearch-parent
+ 0.1.0-SNAPSHOT
+ ../pom.xml
+
+
+ 4.0.0
+
+ quarkus-opensearch-rest-client-parent
+ Quarkus - OpenSearch REST client - Parent
+ pom
+
+
+ deployment
+ runtime
+
+
diff --git a/opensearch-rest-client/runtime/pom.xml b/opensearch-rest-client/runtime/pom.xml
new file mode 100644
index 0000000..74105a1
--- /dev/null
+++ b/opensearch-rest-client/runtime/pom.xml
@@ -0,0 +1,58 @@
+
+
+ 4.0.0
+
+ io.quarkiverse.opensearch
+ quarkus-opensearch-rest-client-parent
+ 0.1.0-SNAPSHOT
+ ../pom.xml
+
+
+ quarkus-opensearch-rest-client
+ Quarkus - OpenSearch REST client - Runtime
+ Connect to an OpenSearch cluster using the REST low level client
+
+
+
+ io.quarkus
+ quarkus-core
+
+
+ io.quarkiverse.opensearch
+ quarkus-opensearch-rest-client-common
+
+
+ io.quarkus
+ quarkus-arc
+
+
+ io.quarkus
+ quarkus-smallrye-health
+ true
+
+
+
+
+
+
+ io.quarkus
+ quarkus-extension-maven-plugin
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ io.quarkus
+ quarkus-extension-processor
+ ${quarkus.version}
+
+
+
+
+
+
+
diff --git a/opensearch-rest-client/runtime/src/main/java/io/quarkiverse/opensearch/restclient/lowlevel/OpenSearchClientConfig.java b/opensearch-rest-client/runtime/src/main/java/io/quarkiverse/opensearch/restclient/lowlevel/OpenSearchClientConfig.java
new file mode 100644
index 0000000..6408aca
--- /dev/null
+++ b/opensearch-rest-client/runtime/src/main/java/io/quarkiverse/opensearch/restclient/lowlevel/OpenSearchClientConfig.java
@@ -0,0 +1,28 @@
+package io.quarkiverse.opensearch.restclient.lowlevel;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.enterprise.util.AnnotationLiteral;
+import javax.inject.Qualifier;
+
+/**
+ * Annotate implementations of {@code org.opensearch.client.RestClientBuilder.HttpClientConfigCallback} to provide further
+ * configuration of injected OpenSearch {@code RestClient} You may provide multiple implementations each annotated with
+ * {@code OpenSearchClientConfig} and configuration provided by each implementation will be applied in a randomly ordered
+ * cascading manner
+ */
+@Qualifier
+@Target({ FIELD, TYPE, PARAMETER })
+@Retention(RUNTIME)
+public @interface OpenSearchClientConfig {
+
+ class Literal extends AnnotationLiteral implements OpenSearchClientConfig {
+
+ }
+}
diff --git a/opensearch-rest-client/runtime/src/main/java/io/quarkiverse/opensearch/restclient/lowlevel/runtime/OpenSearchConfig.java b/opensearch-rest-client/runtime/src/main/java/io/quarkiverse/opensearch/restclient/lowlevel/runtime/OpenSearchConfig.java
new file mode 100644
index 0000000..d2488b4
--- /dev/null
+++ b/opensearch-rest-client/runtime/src/main/java/io/quarkiverse/opensearch/restclient/lowlevel/runtime/OpenSearchConfig.java
@@ -0,0 +1,95 @@
+package io.quarkiverse.opensearch.restclient.lowlevel.runtime;
+
+import java.net.InetSocketAddress;
+import java.time.Duration;
+import java.util.List;
+import java.util.Optional;
+
+import io.quarkus.runtime.annotations.ConfigGroup;
+import io.quarkus.runtime.annotations.ConfigItem;
+import io.quarkus.runtime.annotations.ConfigRoot;
+
+@ConfigRoot(prefix = "quarkiverse.opensearch")
+public class OpenSearchConfig {
+
+ /**
+ * The list of hosts of the OpenSearch servers.
+ */
+ @ConfigItem(defaultValue = "localhost:9200")
+ public List hosts;
+
+ /**
+ * The protocol to use when contacting OpenSearch servers.
+ * Set to "https" to enable SSL/TLS.
+ */
+ @ConfigItem(defaultValue = "http")
+ public String protocol;
+
+ /**
+ * The username for basic HTTP authentication.
+ */
+ @ConfigItem
+ public Optional username;
+
+ /**
+ * The password for basic HTTP authentication.
+ */
+ @ConfigItem
+ public Optional password;
+
+ /**
+ * The connection timeout.
+ */
+ @ConfigItem(defaultValue = "1S")
+ public Duration connectionTimeout;
+
+ /**
+ * The socket timeout.
+ */
+ @ConfigItem(defaultValue = "30S")
+ public Duration socketTimeout;
+
+ /**
+ * The maximum number of connections to all the OpenSearch servers.
+ */
+ @ConfigItem(defaultValue = "20")
+ public int maxConnections;
+
+ /**
+ * The maximum number of connections per OpenSearch server.
+ */
+ @ConfigItem(defaultValue = "10")
+ public int maxConnectionsPerRoute;
+
+ /**
+ * The number of IO thread.
+ * By default, this is the number of locally detected processors.
+ *
+ * Thread counts higher than the number of processors should not be necessary because the I/O threads rely on non-blocking
+ * operations, but you may want to use a thread count lower than the number of processors.
+ */
+ @ConfigItem
+ public Optional ioThreadCounts;
+
+ /**
+ * Configuration for the automatic discovery of new OpenSearch nodes.
+ */
+ @ConfigItem
+ public DiscoveryConfig discovery;
+
+ @ConfigGroup
+ public static class DiscoveryConfig {
+
+ /**
+ * Defines if automatic discovery is enabled.
+ */
+ @ConfigItem(defaultValue = "false")
+ public boolean enabled;
+
+ /**
+ * Refresh interval of the node list.
+ */
+ @ConfigItem(defaultValue = "5M")
+ public Duration refreshInterval;
+ }
+}
diff --git a/opensearch-rest-client/runtime/src/main/java/io/quarkiverse/opensearch/restclient/lowlevel/runtime/OpenSearchRestClientProducer.java b/opensearch-rest-client/runtime/src/main/java/io/quarkiverse/opensearch/restclient/lowlevel/runtime/OpenSearchRestClientProducer.java
new file mode 100644
index 0000000..05bd722
--- /dev/null
+++ b/opensearch-rest-client/runtime/src/main/java/io/quarkiverse/opensearch/restclient/lowlevel/runtime/OpenSearchRestClientProducer.java
@@ -0,0 +1,52 @@
+package io.quarkiverse.opensearch.restclient.lowlevel.runtime;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+
+import javax.annotation.PreDestroy;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Produces;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.opensearch.client.RestClient;
+import org.opensearch.client.RestClientBuilder;
+import org.opensearch.client.sniff.Sniffer;
+
+@ApplicationScoped
+public class OpenSearchRestClientProducer {
+
+ @Inject
+ OpenSearchConfig config;
+
+ private RestClient client;
+
+ private Sniffer sniffer;
+
+ @Produces
+ @Singleton
+ public RestClient restClient() {
+ RestClientBuilder builder = RestClientBuilderHelper.createRestClientBuilder(config);
+
+ this.client = builder.build();
+ if (config.discovery.enabled) {
+ this.sniffer = RestClientBuilderHelper.createSniffer(client, config);
+ }
+
+ return this.client;
+ }
+
+ @PreDestroy
+ void destroy() {
+ try {
+ if (this.sniffer != null) {
+ this.sniffer.close();
+ }
+ if (this.client != null) {
+ this.client.close();
+ }
+ } catch (IOException ioe) {
+ throw new UncheckedIOException(ioe);
+ }
+ }
+}
diff --git a/opensearch-rest-client/runtime/src/main/java/io/quarkiverse/opensearch/restclient/lowlevel/runtime/RestClientBuilderHelper.java b/opensearch-rest-client/runtime/src/main/java/io/quarkiverse/opensearch/restclient/lowlevel/runtime/RestClientBuilderHelper.java
new file mode 100644
index 0000000..2c6838d
--- /dev/null
+++ b/opensearch-rest-client/runtime/src/main/java/io/quarkiverse/opensearch/restclient/lowlevel/runtime/RestClientBuilderHelper.java
@@ -0,0 +1,115 @@
+package io.quarkiverse.opensearch.restclient.lowlevel.runtime;
+
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.http.HttpHost;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.impl.client.BasicCredentialsProvider;
+import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
+import org.apache.http.impl.nio.reactor.IOReactorConfig;
+import org.apache.http.nio.conn.NoopIOSessionStrategy;
+import org.jboss.logging.Logger;
+import org.opensearch.client.RestClient;
+import org.opensearch.client.RestClientBuilder;
+import org.opensearch.client.sniff.NodesSniffer;
+import org.opensearch.client.sniff.OpenSearchNodesSniffer;
+import org.opensearch.client.sniff.Sniffer;
+import org.opensearch.client.sniff.SnifferBuilder;
+
+import io.quarkiverse.opensearch.restclient.lowlevel.OpenSearchClientConfig;
+import io.quarkus.arc.Arc;
+import io.quarkus.arc.InstanceHandle;
+
+public final class RestClientBuilderHelper {
+
+ private static final Logger LOG = Logger.getLogger(RestClientBuilderHelper.class);
+
+ private RestClientBuilderHelper() {
+ // avoid instantiation
+ }
+
+ public static RestClientBuilder createRestClientBuilder(OpenSearchConfig config) {
+ List hosts = new ArrayList<>(config.hosts.size());
+ for (InetSocketAddress host : config.hosts) {
+ hosts.add(new HttpHost(host.getHostString(), host.getPort(), config.protocol));
+ }
+
+ RestClientBuilder builder = RestClient.builder(hosts.toArray(new HttpHost[0]));
+
+ builder.setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() {
+ @Override
+ public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) {
+ return requestConfigBuilder
+ .setConnectTimeout((int) config.connectionTimeout.toMillis())
+ .setSocketTimeout((int) config.socketTimeout.toMillis())
+ .setConnectionRequestTimeout(0); // Avoid requests being flagged as timed out even when they didn't time out.
+ }
+ });
+
+ builder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
+ @Override
+ public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
+ if (config.username.isPresent()) {
+ if (!"https".equalsIgnoreCase(config.protocol)) {
+ LOG.warn("Using Basic authentication in HTTP implies sending plain text passwords over the wire, " +
+ "use the HTTPS protocol instead.");
+ }
+ CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
+ credentialsProvider.setCredentials(AuthScope.ANY,
+ new UsernamePasswordCredentials(config.username.get(), config.password.orElse(null)));
+ httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
+ }
+
+ if (config.ioThreadCounts.isPresent()) {
+ IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
+ .setIoThreadCount(config.ioThreadCounts.get())
+ .build();
+ httpClientBuilder.setDefaultIOReactorConfig(ioReactorConfig);
+ }
+
+ httpClientBuilder.setMaxConnTotal(config.maxConnections);
+ httpClientBuilder.setMaxConnPerRoute(config.maxConnectionsPerRoute);
+
+ if ("http".equalsIgnoreCase(config.protocol)) {
+ // In this case disable the SSL capability as it might have an impact on
+ // bootstrap time, for example consuming entropy for no reason
+ httpClientBuilder.setSSLStrategy(NoopIOSessionStrategy.INSTANCE);
+ }
+
+ // Apply configuration from RestClientBuilder.HttpClientConfigCallback implementations annotated with OpenSearchClientConfig
+ HttpAsyncClientBuilder result = httpClientBuilder;
+ Iterable> handles = Arc.container()
+ .select(RestClientBuilder.HttpClientConfigCallback.class, new OpenSearchClientConfig.Literal())
+ .handles();
+ for (InstanceHandle handle : handles) {
+ result = handle.get().customizeHttpClient(result);
+ handle.close();
+ }
+ return result;
+ }
+ });
+
+ return builder;
+ }
+
+ public static Sniffer createSniffer(RestClient client, OpenSearchConfig config) {
+ SnifferBuilder builder = Sniffer.builder(client)
+ .setSniffIntervalMillis((int) config.discovery.refreshInterval.toMillis());
+
+ // https discovery support
+ if ("https".equalsIgnoreCase(config.protocol)) {
+ NodesSniffer hostsSniffer = new OpenSearchNodesSniffer(
+ client,
+ OpenSearchNodesSniffer.DEFAULT_SNIFF_REQUEST_TIMEOUT, // 1sec
+ OpenSearchNodesSniffer.Scheme.HTTPS);
+ builder.setNodesSniffer(hostsSniffer);
+ }
+
+ return builder.build();
+ }
+}
diff --git a/opensearch-rest-client/runtime/src/main/java/io/quarkiverse/opensearch/restclient/lowlevel/runtime/health/OpenSearchHealthCheck.java b/opensearch-rest-client/runtime/src/main/java/io/quarkiverse/opensearch/restclient/lowlevel/runtime/health/OpenSearchHealthCheck.java
new file mode 100644
index 0000000..4e98a99
--- /dev/null
+++ b/opensearch-rest-client/runtime/src/main/java/io/quarkiverse/opensearch/restclient/lowlevel/runtime/health/OpenSearchHealthCheck.java
@@ -0,0 +1,43 @@
+package io.quarkiverse.opensearch.restclient.lowlevel.runtime.health;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+
+import org.apache.http.util.EntityUtils;
+import org.eclipse.microprofile.health.HealthCheck;
+import org.eclipse.microprofile.health.HealthCheckResponse;
+import org.eclipse.microprofile.health.HealthCheckResponseBuilder;
+import org.eclipse.microprofile.health.Readiness;
+import org.opensearch.client.Request;
+import org.opensearch.client.Response;
+import org.opensearch.client.RestClient;
+
+import io.vertx.core.json.JsonObject;
+
+@Readiness
+@ApplicationScoped
+public class OpenSearchHealthCheck implements HealthCheck {
+ @Inject
+ RestClient restClient;
+
+ @Override
+ public HealthCheckResponse call() {
+ HealthCheckResponseBuilder builder = HealthCheckResponse.named("OpenSearch cluster health check").up();
+ try {
+ Request request = new Request("GET", "/_cluster/health");
+ Response response = restClient.performRequest(request);
+ String responseBody = EntityUtils.toString(response.getEntity());
+ JsonObject json = new JsonObject(responseBody);
+ String status = json.getString("status");
+ if ("red".equals(status)) {
+ builder.down().withData("status", status);
+ } else {
+ builder.up().withData("status", status);
+ }
+
+ } catch (Exception e) {
+ return builder.down().withData("reason", e.getMessage()).build();
+ }
+ return builder.build();
+ }
+}
diff --git a/opensearch-rest-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/opensearch-rest-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml
new file mode 100644
index 0000000..baf3993
--- /dev/null
+++ b/opensearch-rest-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml
@@ -0,0 +1,13 @@
+---
+artifact: ${project.groupId}:${project.artifactId}:${project.version}
+name: "OpenSearch REST client"
+metadata:
+ keywords:
+ - "opensearch"
+ - "full text"
+ - "search"
+ categories:
+ - "data"
+ status: "stable"
+ config:
+ - "quarkiverse.opensearch."
diff --git a/opensearch-rest-high-level-client/deployment/pom.xml b/opensearch-rest-high-level-client/deployment/pom.xml
new file mode 100644
index 0000000..ed25668
--- /dev/null
+++ b/opensearch-rest-high-level-client/deployment/pom.xml
@@ -0,0 +1,58 @@
+
+
+
+ io.quarkiverse.opensearch
+ quarkus-opensearch-rest-high-level-client-parent
+ 0.1.0-SNAPSHOT
+ ../pom.xml
+
+ 4.0.0
+
+ quarkus-opensearch-rest-high-level-client-deployment
+ Quarkus - OpenSearch REST high level client - Deployment
+
+
+
+ io.quarkus
+ quarkus-core-deployment
+
+
+ io.quarkiverse.opensearch
+ quarkus-opensearch-rest-client-common-deployment
+
+
+ io.quarkiverse.opensearch
+ quarkus-opensearch-rest-client-deployment
+
+
+ io.quarkiverse.opensearch
+ quarkus-opensearch-rest-high-level-client
+
+
+ io.quarkus
+ quarkus-arc-deployment
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ io.quarkus
+ quarkus-extension-processor
+ ${quarkus.version}
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/opensearch-rest-high-level-client/deployment/src/main/java/io/quarkiverse/opensearch/restclient/highlevel/deployment/OpenSearchHighLevelClientProcessor.java b/opensearch-rest-high-level-client/deployment/src/main/java/io/quarkiverse/opensearch/restclient/highlevel/deployment/OpenSearchHighLevelClientProcessor.java
new file mode 100644
index 0000000..00ce09d
--- /dev/null
+++ b/opensearch-rest-high-level-client/deployment/src/main/java/io/quarkiverse/opensearch/restclient/highlevel/deployment/OpenSearchHighLevelClientProcessor.java
@@ -0,0 +1,21 @@
+package io.quarkiverse.opensearch.restclient.highlevel.deployment;
+
+import io.quarkiverse.opensearch.restclient.highlevel.runtime.OpenSearchRestHighLevelClientProducer;
+import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
+import io.quarkus.deployment.Feature;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.builditem.FeatureBuildItem;
+
+class OpenSearchHighLevelClientProcessor {
+
+ @BuildStep
+ FeatureBuildItem feature() {
+ return new FeatureBuildItem(Feature.ELASTICSEARCH_REST_HIGH_LEVEL_CLIENT);
+ }
+
+ @BuildStep()
+ AdditionalBeanBuildItem build() {
+ return AdditionalBeanBuildItem.unremovableOf(OpenSearchRestHighLevelClientProducer.class);
+ }
+
+}
diff --git a/opensearch-rest-high-level-client/pom.xml b/opensearch-rest-high-level-client/pom.xml
new file mode 100644
index 0000000..3ac5abd
--- /dev/null
+++ b/opensearch-rest-high-level-client/pom.xml
@@ -0,0 +1,23 @@
+
+
+
+ io.quarkiverse.opensearch
+ quarkus-opensearch-parent
+ 0.1.0-SNAPSHOT
+ ../pom.xml
+
+
+ 4.0.0
+
+ quarkus-opensearch-rest-high-level-client-parent
+ Quarkus - OpenSearch REST high level client - Parent
+ pom
+
+
+ runtime
+ deployment
+
+
+
\ No newline at end of file
diff --git a/opensearch-rest-high-level-client/runtime/pom.xml b/opensearch-rest-high-level-client/runtime/pom.xml
new file mode 100644
index 0000000..61560af
--- /dev/null
+++ b/opensearch-rest-high-level-client/runtime/pom.xml
@@ -0,0 +1,121 @@
+
+
+
+ io.quarkiverse.opensearch
+ quarkus-opensearch-rest-high-level-client-parent
+ 0.1.0-SNAPSHOT
+ ../pom.xml
+
+ 4.0.0
+
+ quarkus-opensearch-rest-high-level-client
+ Quarkus - OpenSearch REST high level client - Runtime
+ Connect to an OpenSearch cluster using the REST high level client
+
+
+
+ io.quarkus
+ quarkus-core
+
+
+ io.quarkiverse.opensearch
+ quarkus-opensearch-rest-client-common
+
+
+ io.quarkiverse.opensearch
+ quarkus-opensearch-rest-client
+
+
+ io.quarkus
+ quarkus-arc
+
+
+ org.jboss.logmanager
+ log4j2-jboss-logmanager
+
+
+ org.opensearch.client
+ opensearch-rest-high-level-client
+
+
+
+
+
+ org.apache.lucene
+ lucene-analyzers-common
+
+
+ org.apache.lucene
+ lucene-backward-codecs
+
+
+ org.apache.lucene
+ lucene-grouping
+
+
+ org.apache.lucene
+ lucene-memory
+
+
+ org.apache.lucene
+ lucene-misc
+
+
+ org.apache.lucene
+ lucene-queryparser
+
+
+ org.apache.lucene
+ lucene-sandbox
+
+
+ org.apache.lucene
+ lucene-spatial
+
+
+ org.apache.lucene
+ lucene-spatial-extras
+
+
+ org.apache.lucene
+ lucene-spatial3d
+
+
+ org.apache.lucene
+ lucene-suggest
+
+
+
+
+
+
+
+
+
+ io.quarkus
+ quarkus-extension-maven-plugin
+
+
+ io.quarkiverse.opensearch-rest-high-level-client
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ io.quarkus
+ quarkus-extension-processor
+ ${quarkus.version}
+
+
+
+
+
+
+
+
diff --git a/opensearch-rest-high-level-client/runtime/src/main/java/io/quarkiverse/opensearch/restclient/highlevel/runtime/OpenSearchRestHighLevelClientProducer.java b/opensearch-rest-high-level-client/runtime/src/main/java/io/quarkiverse/opensearch/restclient/highlevel/runtime/OpenSearchRestHighLevelClientProducer.java
new file mode 100644
index 0000000..97c9a9a
--- /dev/null
+++ b/opensearch-rest-high-level-client/runtime/src/main/java/io/quarkiverse/opensearch/restclient/highlevel/runtime/OpenSearchRestHighLevelClientProducer.java
@@ -0,0 +1,43 @@
+package io.quarkiverse.opensearch.restclient.highlevel.runtime;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.Collections;
+
+import javax.annotation.PreDestroy;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Default;
+import javax.enterprise.inject.Produces;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.opensearch.client.RestClient;
+import org.opensearch.client.RestHighLevelClient;
+
+@ApplicationScoped
+public class OpenSearchRestHighLevelClientProducer {
+
+ @Inject
+ @Default
+ RestClient restClient;
+
+ private RestHighLevelClient client;
+
+ @Produces
+ @Singleton
+ public RestHighLevelClient restHighLevelClient() {
+ this.client = new QuarkusRestHighLevelClient(restClient, RestClient::close, Collections.emptyList());
+ return this.client;
+ }
+
+ @PreDestroy
+ void destroy() {
+ try {
+ if (this.client != null) {
+ this.client.close();
+ }
+ } catch (IOException ioe) {
+ throw new UncheckedIOException(ioe);
+ }
+ }
+}
diff --git a/opensearch-rest-high-level-client/runtime/src/main/java/io/quarkiverse/opensearch/restclient/highlevel/runtime/QuarkusRestHighLevelClient.java b/opensearch-rest-high-level-client/runtime/src/main/java/io/quarkiverse/opensearch/restclient/highlevel/runtime/QuarkusRestHighLevelClient.java
new file mode 100644
index 0000000..6c4bfaa
--- /dev/null
+++ b/opensearch-rest-high-level-client/runtime/src/main/java/io/quarkiverse/opensearch/restclient/highlevel/runtime/QuarkusRestHighLevelClient.java
@@ -0,0 +1,22 @@
+package io.quarkiverse.opensearch.restclient.highlevel.runtime;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.opensearch.client.RestClient;
+import org.opensearch.client.RestHighLevelClient;
+import org.opensearch.common.CheckedConsumer;
+import org.opensearch.common.xcontent.NamedXContentRegistry;
+
+/**
+ * The RestHighLevelClient cannot be built with an existing RestClient.
+ *
+ * The only (and documented - see javadoc) way to do it is to subclass it and use its protected constructor.
+ */
+class QuarkusRestHighLevelClient extends RestHighLevelClient {
+
+ protected QuarkusRestHighLevelClient(RestClient restClient, CheckedConsumer doClose,
+ List namedXContentEntries) {
+ super(restClient, doClose, namedXContentEntries);
+ }
+}
diff --git a/opensearch-rest-high-level-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/opensearch-rest-high-level-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml
new file mode 100644
index 0000000..b27fae1
--- /dev/null
+++ b/opensearch-rest-high-level-client/runtime/src/main/resources/META-INF/quarkus-extension.yaml
@@ -0,0 +1,12 @@
+---
+artifact: ${project.groupId}:${project.artifactId}:${project.version}
+name: "OpenSearch REST High Level Client"
+metadata:
+ keywords:
+ - "opensearch"
+ - "full text"
+ - "search"
+ categories:
+ - "data"
+ config:
+ - "quarkiverse.opensearch."
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..d62b228
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,133 @@
+
+
+ 4.0.0
+
+ io.quarkiverse
+ quarkiverse-parent
+ 12
+
+ io.quarkiverse.opensearch
+ quarkus-opensearch-parent
+ 0.1.0-SNAPSHOT
+ pom
+ Quarkus - OpenSearch Client - Parent
+
+ opensearch-rest-client-common
+ opensearch-rest-client
+ opensearch-rest-high-level-client
+
+
+ 3.8.1
+ true
+ 11
+ 11
+ UTF-8
+ UTF-8
+ 2.4.1
+ 2.0.0
+ 2.15.0.Final
+
+
+
+
+ io.quarkus
+ quarkus-bom
+ ${quarkus.version}
+ pom
+ import
+
+
+
+ org.opensearch.client
+ opensearch-rest-client
+ ${opensearch.version}
+
+
+ org.opensearch.client
+ opensearch-rest-high-level-client
+ ${opensearch.version}
+
+
+
+ org.apache.logging.log4j
+ log4j-api
+
+
+
+
+ org.opensearch.client
+ opensearch-rest-client-sniffer
+ ${opensearch.version}
+
+
+ org.opensearch
+ opensearch-testcontainers
+ ${opensearch-testcontainers.version}
+
+
+
+ io.quarkiverse.opensearch
+ quarkus-opensearch-rest-client-common
+ ${project.version}
+
+
+ io.quarkiverse.opensearch
+ quarkus-opensearch-rest-client-common-deployment
+ ${project.version}
+
+
+ io.quarkiverse.opensearch
+ quarkus-opensearch-rest-client
+ ${project.version}
+
+
+ io.quarkiverse.opensearch
+ quarkus-opensearch-rest-client-deployment
+ ${project.version}
+
+
+ io.quarkiverse.opensearch
+ quarkus-opensearch-rest-high-level-client
+ ${project.version}
+
+
+ io.quarkiverse.opensearch
+ quarkus-opensearch-rest-high-level-client-deployment
+ ${project.version}
+
+
+
+
+
+
+
+
+ io.quarkus
+ quarkus-maven-plugin
+ ${quarkus.version}
+
+
+ maven-compiler-plugin
+ ${compiler-plugin.version}
+
+
+
+
+
+
+ it
+
+
+ performRelease
+ !true
+
+
+
+
+
+