This is an automated email from the ASF dual-hosted git repository.
jdyer pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git
The following commit(s) were added to refs/heads/main by this push:
new caf5f5ee05e SOLR-17943: ClusterStateProvider to support
HttpJdkSolrClient (#3730)
caf5f5ee05e is described below
commit caf5f5ee05e42b3346727dd2b94df82f3e6177c5
Author: James Dyer <[email protected]>
AuthorDate: Mon Oct 6 12:37:25 2025 -0500
SOLR-17943: ClusterStateProvider to support HttpJdkSolrClient (#3730)
---
solr/CHANGES.txt | 2 +
.../client/solrj/impl/CloudHttp2SolrClient.java | 2 +-
.../solrj/impl/Http2ClusterStateProvider.java | 34 +++---
.../solr/client/solrj/impl/Http2SolrClient.java | 26 ++---
.../solr/client/solrj/impl/HttpJdkSolrClient.java | 21 +++-
.../solr/client/solrj/impl/HttpSolrClientBase.java | 2 +
.../solrj/impl/HttpSolrClientBuilderBase.java | 31 ++++++
.../solrj/impl/ClusterStateProviderTest.java | 118 ++++++++++++++++-----
8 files changed, 173 insertions(+), 63 deletions(-)
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index a9031067e4e..5b91accaedc 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -80,6 +80,8 @@ Improvements
always create and manage these internal clients. The ability for callers to
provide a pre-built client is removed. Callers may specify the internal client
details by providing an instance of either `Http2SolrClient.Builder` or
`HttpJdkSolrClient.Builder`. (James Dyer)
+* SOLR-17943: `Http2ClusterStateProvider` now also can work with
`HttpJdkSolrClient`. (James Dyer)
+
Optimizations
---------------------
diff --git
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/CloudHttp2SolrClient.java
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/CloudHttp2SolrClient.java
index ade1ebe433f..8849650c244 100644
---
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/CloudHttp2SolrClient.java
+++
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/CloudHttp2SolrClient.java
@@ -115,7 +115,7 @@ public class CloudHttp2SolrClient extends CloudSolrClient {
private ClusterStateProvider createHttp2ClusterStateProvider(
List<String> solrUrls, Http2SolrClient httpClient) {
try {
- return new Http2ClusterStateProvider(solrUrls, httpClient);
+ return new Http2ClusterStateProvider<>(solrUrls, httpClient);
} catch (Exception e) {
closeMyClientIfNeeded();
throw new RuntimeException(
diff --git
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Http2ClusterStateProvider.java
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Http2ClusterStateProvider.java
index cb4226c58d5..d6407514522 100644
---
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Http2ClusterStateProvider.java
+++
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Http2ClusterStateProvider.java
@@ -19,33 +19,39 @@ package org.apache.solr.client.solrj.impl;
import java.io.IOException;
import java.util.List;
-import org.apache.solr.client.solrj.SolrClient;
-public class Http2ClusterStateProvider extends BaseHttpClusterStateProvider {
- final Http2SolrClient httpClient;
- final boolean closeClient;
+public class Http2ClusterStateProvider<C extends HttpSolrClientBase>
+ extends BaseHttpClusterStateProvider {
+ final C httpClient;
- public Http2ClusterStateProvider(List<String> solrUrls, Http2SolrClient
httpClient)
- throws Exception {
- this.httpClient = httpClient == null ? new
Http2SolrClient.Builder().build() : httpClient;
- this.closeClient = httpClient == null;
+ /**
+ * Provide the solr urls and a solr http client for this cluster state
provider to use. It is the
+ * caller's responsibiity to close the client.
+ *
+ * @param solrUrls root path solr urls
+ * @param httpClient an instance of HttpSolrClientBase
+ * @throws Exception if a problem with initialization occurs
+ */
+ public Http2ClusterStateProvider(List<String> solrUrls, C httpClient) throws
Exception {
+ if (httpClient == null) {
+ throw new IllegalArgumentException("You must provide an Http client.");
+ }
+ this.httpClient = httpClient;
initConfiguredNodes(solrUrls);
}
@Override
public void close() throws IOException {
- if (this.closeClient && this.httpClient != null) {
- httpClient.close();
- }
super.close();
}
@Override
- protected SolrClient getSolrClient(String baseUrl) {
- return new
Http2SolrClient.Builder(baseUrl).withHttpClient(httpClient).build();
+ @SuppressWarnings("unchecked")
+ protected C getSolrClient(String baseUrl) {
+ return (C) httpClient.builder().withBaseSolrUrl(baseUrl).build();
}
- public Http2SolrClient getHttpClient() {
+ public C getHttpClient() {
return httpClient;
}
}
diff --git
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Http2SolrClient.java
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Http2SolrClient.java
index d291283123a..6cb95e9e3e5 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Http2SolrClient.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Http2SolrClient.java
@@ -643,6 +643,11 @@ public class Http2SolrClient extends HttpSolrClientBase {
}
}
+ @Override
+ public HttpSolrClientBuilderBase<?, ?> builder() {
+ return new Http2SolrClient.Builder().withHttpClient(this);
+ }
+
private NamedList<Object> processErrorsAndResponse(
SolrRequest<?> solrRequest, Response response, InputStream is, String
urlExceptionMessage)
throws SolrServerException {
@@ -1102,31 +1107,14 @@ public class Http2SolrClient extends HttpSolrClientBase
{
return new Http2SolrClient(baseSolrUrl, this);
}
- /**
- * Provide a seed Http2SolrClient for the builder values, values can still
be overridden by
- * using builder methods
- */
+ @Override
public Builder withHttpClient(Http2SolrClient http2SolrClient) {
+ super.withHttpClient(http2SolrClient);
this.httpClient = http2SolrClient.httpClient;
- if (this.basicAuthAuthorizationStr == null) {
- this.basicAuthAuthorizationStr =
http2SolrClient.basicAuthAuthorizationStr;
- }
if (this.idleTimeoutMillis == null) {
this.idleTimeoutMillis = http2SolrClient.idleTimeoutMillis;
}
- if (this.requestTimeoutMillis == null) {
- this.requestTimeoutMillis = http2SolrClient.requestTimeoutMillis;
- }
- if (this.requestWriter == null) {
- this.requestWriter = http2SolrClient.requestWriter;
- }
- if (this.responseParser == null) {
- this.responseParser = http2SolrClient.parser;
- }
- if (this.urlParamNames == null) {
- this.urlParamNames = http2SolrClient.urlParamNames;
- }
if (this.listenerFactories == null) {
this.listenerFactories = http2SolrClient.listenerFactory;
}
diff --git
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpJdkSolrClient.java
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpJdkSolrClient.java
index 0bcecb2d89d..15e686d5773 100644
---
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpJdkSolrClient.java
+++
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpJdkSolrClient.java
@@ -205,7 +205,7 @@ public class HttpJdkSolrClient extends HttpSolrClientBase {
return requestWithBaseUrl(null, solrRequest, collection);
}
- private PreparedRequest prepareRequest(
+ protected PreparedRequest prepareRequest(
SolrRequest<?> solrRequest, String collection, String overrideBaseUrl)
throws SolrServerException, IOException {
checkClosed();
@@ -342,7 +342,7 @@ public class HttpJdkSolrClient extends HttpSolrClientBase {
return new PreparedRequest(reqb, contentWritingFuture);
}
- private static class PreparedRequest {
+ protected static class PreparedRequest {
Future<?> contentWritingFuture;
HttpRequest.Builder reqb;
@@ -537,6 +537,11 @@ public class HttpJdkSolrClient extends HttpSolrClientBase {
.collect(Collectors.joining(", "));
}
+ @Override
+ public HttpSolrClientBuilderBase<?, ?> builder() {
+ return new HttpJdkSolrClient.Builder().withHttpClient(this);
+ }
+
public static class Builder
extends HttpSolrClientBuilderBase<HttpJdkSolrClient.Builder,
HttpJdkSolrClient> {
@@ -558,6 +563,18 @@ public class HttpJdkSolrClient extends HttpSolrClientBase {
return new HttpJdkSolrClient(baseSolrUrl, this);
}
+ @Override
+ public Builder withHttpClient(HttpJdkSolrClient httpSolrClient) {
+ super.withHttpClient(httpSolrClient);
+ if (this.executor == null) {
+ this.executor = httpSolrClient.executor;
+ }
+ if (this.sslContext == null) {
+ this.sslContext = httpSolrClient.httpClient.sslContext();
+ }
+ return this;
+ }
+
/**
* Use the provided SSLContext. See {@link
* java.net.http.HttpClient.Builder#sslContext(SSLContext)}.
diff --git
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClientBase.java
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClientBase.java
index 987342e9374..55a4f8de0f5 100644
---
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClientBase.java
+++
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClientBase.java
@@ -99,6 +99,8 @@ public abstract class HttpSolrClientBase extends SolrClient {
}
}
+ public abstract HttpSolrClientBuilderBase<?, ?> builder();
+
protected String getRequestUrl(SolrRequest<?> solrRequest, String collection)
throws MalformedURLException {
return ClientUtils.buildRequestUrl(solrRequest, serverBaseUrl, collection);
diff --git
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClientBuilderBase.java
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClientBuilderBase.java
index b2b2d4a6900..2821ebc4cae 100644
---
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClientBuilderBase.java
+++
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClientBuilderBase.java
@@ -47,6 +47,37 @@ public abstract class HttpSolrClientBuilderBase<
public abstract C build();
+ /**
+ * Provide a seed HttpSolrClient for the builder values, values can still be
overridden by using
+ * builder methods
+ */
+ @SuppressWarnings("unchecked")
+ public B withHttpClient(C httpSolrClient) {
+ if (this.basicAuthAuthorizationStr == null) {
+ this.basicAuthAuthorizationStr =
httpSolrClient.basicAuthAuthorizationStr;
+ }
+ if (this.requestTimeoutMillis == null) {
+ this.requestTimeoutMillis = httpSolrClient.requestTimeoutMillis;
+ }
+ if (this.requestWriter == null) {
+ this.requestWriter = httpSolrClient.requestWriter;
+ }
+ if (this.responseParser == null) {
+ this.responseParser = httpSolrClient.parser;
+ }
+ if (this.urlParamNames == null) {
+ this.urlParamNames = httpSolrClient.urlParamNames;
+ }
+ return (B) (this);
+ }
+
+ /** Provides the Base Solr Url. */
+ @SuppressWarnings("unchecked")
+ public B withBaseSolrUrl(String baseSolrUrl) {
+ this.baseSolrUrl = baseSolrUrl;
+ return (B) this;
+ }
+
/** Provides a {@link RequestWriter} for created clients to use when handing
requests. */
@SuppressWarnings("unchecked")
public B withRequestWriter(RequestWriter requestWriter) {
diff --git
a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/ClusterStateProviderTest.java
b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/ClusterStateProviderTest.java
index 57479c1c263..18f990b41c7 100644
---
a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/ClusterStateProviderTest.java
+++
b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/ClusterStateProviderTest.java
@@ -32,6 +32,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
+import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
import org.apache.solr.client.solrj.response.CollectionAdminResponse;
@@ -45,9 +46,32 @@ import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.BeforeClass;
import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class ClusterStateProviderTest extends SolrCloudTestCase {
+ private static final Logger log =
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+ static class UserAgentChangingJdkClient extends HttpJdkSolrClient {
+
+ final String userAgent;
+
+ protected UserAgentChangingJdkClient(Builder builder, String userAgent) {
+ super(null, builder);
+ this.userAgent = userAgent;
+ }
+
+ @Override
+ protected PreparedRequest prepareRequest(
+ SolrRequest<?> solrRequest, String collection, String overrideBaseUrl)
+ throws SolrServerException, IOException {
+ var pr = super.prepareRequest(solrRequest, collection, overrideBaseUrl);
+ pr.reqb.header("User-Agent", userAgent);
+ return pr;
+ }
+ }
+
@BeforeClass
public static void setupCluster() throws Exception {
configureCluster(2)
@@ -76,18 +100,70 @@ public class ClusterStateProviderTest extends
SolrCloudTestCase {
new String[] {"http2ClusterStateProvider"}, new String[]
{"zkClientClusterStateProvider"});
}
- private static Http2ClusterStateProvider http2ClusterStateProvider() {
+ static class ClosingHttp2ClusterStateProvider
+ extends Http2ClusterStateProvider<HttpSolrClientBase> {
+ public ClosingHttp2ClusterStateProvider(List<String> solrUrls,
HttpSolrClientBase httpClient)
+ throws Exception {
+ super(solrUrls, httpClient);
+ }
+
+ @Override
+ public void close() throws IOException {
+ super.close();
+ try {
+ httpClient.close();
+ } catch (IOException e) {
+ log.error("error closing the client.", e);
+ }
+ }
+ }
+
+ private static Http2ClusterStateProvider<?> http2ClusterStateProvider(String
userAgent) {
try {
- return new Http2ClusterStateProvider(
- List.of(
- cluster.getJettySolrRunner(0).getBaseUrl().toString(),
- cluster.getJettySolrRunner(1).getBaseUrl().toString()),
- null);
+ var useJdkProvider = random().nextBoolean();
+ HttpSolrClientBase client;
+
+ if (userAgent != null) {
+ if (useJdkProvider) {
+ client =
+ new UserAgentChangingJdkClient(
+ new HttpJdkSolrClient.Builder()
+
.withSSLContext(MockTrustManager.ALL_TRUSTING_SSL_CONTEXT),
+ userAgent);
+ } else {
+ var http2SolrClient = new Http2SolrClient.Builder().build();
+ http2SolrClient
+ .getHttpClient()
+ .setUserAgentField(new HttpField(HttpHeader.USER_AGENT,
userAgent));
+ client = http2SolrClient;
+ }
+ } else {
+ client =
+ useJdkProvider
+ ? new HttpJdkSolrClient.Builder()
+ .withSSLContext(MockTrustManager.ALL_TRUSTING_SSL_CONTEXT)
+ .build()
+ : new Http2SolrClient.Builder().build();
+ }
+ var clientClassName = client.getClass().getName();
+ log.info("Using Http client implementation: {}", clientClassName);
+
+ var csp =
+ new ClosingHttp2ClusterStateProvider(
+ List.of(
+ cluster.getJettySolrRunner(0).getBaseUrl().toString(),
+ cluster.getJettySolrRunner(1).getBaseUrl().toString()),
+ client);
+ return csp;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
+ private static Http2ClusterStateProvider<?> http2ClusterStateProvider() {
+ return http2ClusterStateProvider(null);
+ }
+
private static ClusterStateProvider zkClientClusterStateProvider() {
return new ZkClientClusterStateProvider(cluster.getZkStateReader());
}
@@ -209,15 +285,10 @@ public class ClusterStateProviderTest extends
SolrCloudTestCase {
createCollection("col2");
try (var cspZk = zkClientClusterStateProvider();
- var cspHttp = http2ClusterStateProvider()) {
- // SolrJ < version 9.9.0 for non streamed response
- cspHttp
- .getHttpClient()
- .getHttpClient()
- .setUserAgentField(
- new HttpField(
- HttpHeader.USER_AGENT,
- "Solr[" + MethodHandles.lookup().lookupClass().getName() +
"] " + "9.8.0"));
+ // SolrJ < version 9.9.0 for non streamed response
+ var cspHttp =
+ http2ClusterStateProvider(
+ "Solr[" + MethodHandles.lookup().lookupClass().getName() + "]
" + "9.8.0")) {
assertThat(cspHttp.getCollection("col1"),
equalTo(cspZk.getCollection("col1")));
@@ -237,15 +308,10 @@ public class ClusterStateProviderTest extends
SolrCloudTestCase {
}
try (var cspZk = zkClientClusterStateProvider();
- var cspHttp = http2ClusterStateProvider()) {
- // Even older SolrJ versionsg for non streamed response
- cspHttp
- .getHttpClient()
- .getHttpClient()
- .setUserAgentField(
- new HttpField(
- HttpHeader.USER_AGENT,
- "Solr[" + MethodHandles.lookup().lookupClass().getName() +
"] " + "2.0"));
+ // Even older SolrJ versions for non streamed response
+ var cspHttp =
+ http2ClusterStateProvider(
+ "Solr[" + MethodHandles.lookup().lookupClass().getName() + "]
" + "2.0")) {
assertThat(cspHttp.getCollection("col1"),
equalTo(cspZk.getCollection("col1")));
@@ -272,9 +338,7 @@ public class ClusterStateProviderTest extends
SolrCloudTestCase {
createCollection("col2");
try (var cspZk = zkClientClusterStateProvider();
- var cspHttp = http2ClusterStateProvider()) {
-
- cspHttp.getHttpClient().getHttpClient().setUserAgentField(null);
+ var cspHttp = http2ClusterStateProvider("")) {
assertThat(cspHttp.getCollection("col1"),
equalTo(cspZk.getCollection("col1")));