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

dsmiley pushed a commit to branch branch_9x
in repository https://gitbox.apache.org/repos/asf/solr.git

commit 6de48936afdea86382d0e059987ed484eac74097
Author: David Smiley <[email protected]>
AuthorDate: Sun Nov 30 21:20:57 2025 -0500

    SOLR-17996: SolrRequest.processWithBaseUrl and 
HttpSolrClientBase.requestWithBaseUrl (#3881)
    
    New HttpSolrClientBase.requestWithBaseUrl (abstract, returns NamedList).
    Change Http2SolrClient.requestWithBaseUrl to implement it, return NamedList 
instead of SolrRequest generic return type.
    New SolrRequest.processWithBaseUrl that returns the SolrRequest response.
    
    backported to 9x; kept existing requestWithBaseUrl overload and deprecated
    Ported HttpJdkSolrClient.requestWithBaseUrl from 10x
---
 .../unreleased/SOLR-17996-requestWithBaseUrl.yml   |  8 +++++++
 .../org/apache/solr/bench/MiniClusterState.java    | 15 ++++++------
 .../org/apache/solr/bench/index/CloudIndexing.java |  2 +-
 .../org/apache/solr/bench/search/FilterCache.java  |  8 +++----
 .../org/apache/solr/bench/search/JsonFaceting.java |  5 +---
 .../apache/solr/bench/search/NumericSearch.java    |  4 ++--
 .../api/collections/ReindexCollectionCmd.java      |  5 ++--
 .../java/org/apache/solr/core/CoreContainer.java   |  5 ++--
 .../java/org/apache/solr/handler/IndexFetcher.java |  9 ++++----
 .../org/apache/solr/handler/admin/ColStatus.java   |  2 +-
 .../solr/security/PKIAuthenticationPlugin.java     |  2 +-
 .../org/apache/solr/update/PeerSyncWithLeader.java |  2 +-
 .../org/apache/solr/update/SolrCmdDistributor.java |  2 +-
 .../processor/DistributedUpdateProcessor.java      |  6 +----
 .../TestUserManagedReplicationWithAuth.java        |  4 ++--
 .../solrj/impl/SolrClientNodeStateProvider.java    |  2 +-
 .../solr/common/cloud/NodesSysPropsCacher.java     |  4 +---
 .../org/apache/solr/client/solrj/SolrRequest.java  | 24 +++++++++++++++++++
 .../impl/ConcurrentUpdateHttp2SolrClient.java      |  9 ++++----
 .../solr/client/solrj/impl/Http2SolrClient.java    |  8 +++++++
 .../solr/client/solrj/impl/HttpJdkSolrClient.java  | 27 ++++++++++++++++------
 .../solr/client/solrj/impl/HttpSolrClientBase.java | 15 ++++++++++++
 .../solr/client/solrj/impl/LBSolrClient.java       | 12 +++++-----
 .../client/solrj/impl/Http2SolrClientTest.java     |  4 ++--
 .../client/solrj/impl/HttpJdkSolrClientTest.java   | 19 +++++++++++++++
 25 files changed, 139 insertions(+), 64 deletions(-)

diff --git a/changelog/unreleased/SOLR-17996-requestWithBaseUrl.yml 
b/changelog/unreleased/SOLR-17996-requestWithBaseUrl.yml
new file mode 100644
index 00000000000..cdd4d944a74
--- /dev/null
+++ b/changelog/unreleased/SOLR-17996-requestWithBaseUrl.yml
@@ -0,0 +1,8 @@
+# See https://github.com/apache/solr/blob/main/dev-docs/changelog.adoc
+title: New SolrJ SolrRequest.processWithBaseUrl, new 
HttpSolrClientBase.requestWithBaseUrl.  HttpJdkSolrClient.requestWithBaseUrl 
ported from 10x.
+type: other # added, changed, fixed, deprecated, removed, dependency_update, 
security, other
+authors:
+  - name: David Smiley
+links:
+  - name: SOLR-17996
+    url: https://issues.apache.org/jira/browse/SOLR-17996
diff --git 
a/solr/benchmark/src/java/org/apache/solr/bench/MiniClusterState.java 
b/solr/benchmark/src/java/org/apache/solr/bench/MiniClusterState.java
index 34a970b3392..6fa2b06a346 100755
--- a/solr/benchmark/src/java/org/apache/solr/bench/MiniClusterState.java
+++ b/solr/benchmark/src/java/org/apache/solr/bench/MiniClusterState.java
@@ -318,7 +318,7 @@ public class MiniClusterState {
           CollectionAdminRequest.Create request =
               CollectionAdminRequest.createCollection(collection, "conf", 
numShards, numReplicas);
           client.requestWithBaseUrl(
-              nodes.get(random.nextInt(cluster.getJettySolrRunners().size())), 
null, request);
+              nodes.get(random.nextInt(cluster.getJettySolrRunners().size())), 
request, null);
 
           cluster.waitForActiveCollection(
               collection, 15, TimeUnit.SECONDS, numShards, numShards * 
numReplicas);
@@ -368,7 +368,7 @@ public class MiniClusterState {
         UpdateRequest commitRequest = new UpdateRequest();
         final var url = 
nodes.get(random.nextInt(cluster.getJettySolrRunners().size()));
         commitRequest.setAction(UpdateRequest.ACTION.COMMIT, false, true);
-        client.requestWithBaseUrl(url, collection, commitRequest);
+        client.requestWithBaseUrl(url, commitRequest, collection);
         log("done committing data");
       } else {
         cluster.waitForActiveCollection(collection, 15, TimeUnit.SECONDS);
@@ -376,8 +376,7 @@ public class MiniClusterState {
 
       QueryRequest queryRequest = new QueryRequest(new SolrQuery("q", "*:*", 
"rows", "1"));
       final var url = 
nodes.get(random.nextInt(cluster.getJettySolrRunners().size()));
-      NamedList<Object> result =
-          client.requestWithBaseUrl(url, collection, 
queryRequest).getResponse();
+      NamedList<Object> result = client.requestWithBaseUrl(url, queryRequest, 
collection);
 
       log("sanity check of single row query result: " + result);
       log("");
@@ -424,7 +423,7 @@ public class MiniClusterState {
                 meter.mark();
 
                 try {
-                  client.requestWithBaseUrl(url, collection, updateRequest);
+                  client.requestWithBaseUrl(url, updateRequest, collection);
                 } catch (Exception e) {
                   throw new RuntimeException(e);
                 }
@@ -452,7 +451,7 @@ public class MiniClusterState {
         if (i % batchSize == 0) {
           UpdateRequest updateRequest = new UpdateRequest();
           updateRequest.add(batch);
-          client.requestWithBaseUrl(nodes.get(0), collection, updateRequest);
+          client.requestWithBaseUrl(nodes.get(0), updateRequest, collection);
           meter.mark(batch.size());
           batch.clear();
           log(meter.getCount() + " docs at " + (long) meter.getMeanRate() + " 
doc/s");
@@ -461,7 +460,7 @@ public class MiniClusterState {
       if (!batch.isEmpty()) {
         UpdateRequest updateRequest = new UpdateRequest();
         updateRequest.add(batch);
-        client.requestWithBaseUrl(nodes.get(0), collection, updateRequest);
+        client.requestWithBaseUrl(nodes.get(0), updateRequest, collection);
         meter.mark(batch.size());
         batch = null;
       }
@@ -499,7 +498,7 @@ public class MiniClusterState {
         UpdateRequest optimizeRequest = new UpdateRequest();
         final var url = 
nodes.get(random.nextInt(cluster.getJettySolrRunners().size()));
         optimizeRequest.setAction(UpdateRequest.ACTION.OPTIMIZE, false, true, 
maxMergeSegments);
-        client.requestWithBaseUrl(url, collection, optimizeRequest);
+        client.requestWithBaseUrl(url, optimizeRequest, collection);
       }
     }
 
diff --git 
a/solr/benchmark/src/java/org/apache/solr/bench/index/CloudIndexing.java 
b/solr/benchmark/src/java/org/apache/solr/bench/index/CloudIndexing.java
index 0ee950e7231..5f6c6526690 100755
--- a/solr/benchmark/src/java/org/apache/solr/bench/index/CloudIndexing.java
+++ b/solr/benchmark/src/java/org/apache/solr/bench/index/CloudIndexing.java
@@ -130,6 +130,6 @@ public class CloudIndexing {
     updateRequest.add(state.getNextDoc());
     final var url =
         
miniClusterState.nodes.get(miniClusterState.getRandom().nextInt(state.nodeCount));
-    return miniClusterState.client.requestWithBaseUrl(url, 
BenchState.COLLECTION, updateRequest);
+    return miniClusterState.client.requestWithBaseUrl(url, updateRequest, 
BenchState.COLLECTION);
   }
 }
diff --git 
a/solr/benchmark/src/java/org/apache/solr/bench/search/FilterCache.java 
b/solr/benchmark/src/java/org/apache/solr/bench/search/FilterCache.java
index 6b7f6bf4a4f..4b1bf9485e8 100644
--- a/solr/benchmark/src/java/org/apache/solr/bench/search/FilterCache.java
+++ b/solr/benchmark/src/java/org/apache/solr/bench/search/FilterCache.java
@@ -109,7 +109,7 @@ public class FilterCache {
         throws SolrServerException, IOException {
       // Reload the collection/core to drop existing caches
       CollectionAdminRequest.Reload reload = 
CollectionAdminRequest.reloadCollection(COLLECTION);
-      
miniClusterState.client.requestWithBaseUrl(miniClusterState.nodes.get(0), null, 
reload);
+      
miniClusterState.client.requestWithBaseUrl(miniClusterState.nodes.get(0), 
reload, null);
     }
 
     @TearDown(Level.Iteration)
@@ -139,8 +139,8 @@ public class FilterCache {
       throws SolrServerException, IOException {
     return miniClusterState.client.requestWithBaseUrl(
         benchState.baseUrl,
-        COLLECTION,
-        miniClusterState.getRandom().nextBoolean() ? benchState.q1 : 
benchState.q2);
+        miniClusterState.getRandom().nextBoolean() ? benchState.q1 : 
benchState.q2,
+        COLLECTION);
   }
 
   @Benchmark
@@ -148,6 +148,6 @@ public class FilterCache {
       BenchState benchState, MiniClusterState.MiniClusterBenchState 
miniClusterState)
       throws SolrServerException, IOException {
     return miniClusterState.client.requestWithBaseUrl(
-        benchState.baseUrl, COLLECTION, benchState.q1);
+        benchState.baseUrl, benchState.q1, COLLECTION);
   }
 }
diff --git 
a/solr/benchmark/src/java/org/apache/solr/bench/search/JsonFaceting.java 
b/solr/benchmark/src/java/org/apache/solr/bench/search/JsonFaceting.java
index 1595de56d3b..2577581611e 100755
--- a/solr/benchmark/src/java/org/apache/solr/bench/search/JsonFaceting.java
+++ b/solr/benchmark/src/java/org/apache/solr/bench/search/JsonFaceting.java
@@ -183,10 +183,7 @@ public class JsonFaceting {
     final var url = 
miniClusterState.nodes.get(threadState.random.nextInt(state.nodeCount));
     QueryRequest queryRequest = new QueryRequest(state.params);
     NamedList<Object> result =
-        miniClusterState
-            .client
-            .requestWithBaseUrl(url, state.collection, queryRequest)
-            .getResponse();
+        miniClusterState.client.requestWithBaseUrl(url, queryRequest, 
state.collection);
 
     // MiniClusterState.log("result: " + result);
 
diff --git 
a/solr/benchmark/src/java/org/apache/solr/bench/search/NumericSearch.java 
b/solr/benchmark/src/java/org/apache/solr/bench/search/NumericSearch.java
index 398d102ec7c..7717b005fb3 100644
--- a/solr/benchmark/src/java/org/apache/solr/bench/search/NumericSearch.java
+++ b/solr/benchmark/src/java/org/apache/solr/bench/search/NumericSearch.java
@@ -102,7 +102,7 @@ public class NumericSearch {
       q.setParam("facet.limit", String.valueOf(maxCardinality));
       QueryRequest req = new QueryRequest(q);
       QueryResponse response =
-          miniClusterState.client.requestWithBaseUrl(basePath, COLLECTION, 
req);
+          req.processWithBaseUrl(miniClusterState.client, basePath, 
COLLECTION);
       Set<String> numbers =
           response.getFacetField("numbers_i_dv").getValues().stream()
               .map(FacetField.Count::getName)
@@ -144,7 +144,7 @@ public class NumericSearch {
         throws SolrServerException, IOException {
       // Reload the collection/core to drop existing caches
       CollectionAdminRequest.Reload reload = 
CollectionAdminRequest.reloadCollection(COLLECTION);
-      
miniClusterState.client.requestWithBaseUrl(miniClusterState.nodes.get(0), null, 
reload);
+      
miniClusterState.client.requestWithBaseUrl(miniClusterState.nodes.get(0), 
reload, null);
     }
 
     public QueryRequest intSetQuery(boolean dvs) {
diff --git 
a/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java
 
b/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java
index 9620cff4260..a4bffd5b795 100644
--- 
a/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java
+++ 
b/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java
@@ -872,9 +872,8 @@ public class ReindexCollectionCmd implements 
CollApiCmds.CollectionApiCommand {
     solrParams.set(CommonParams.DISTRIB, false);
 
     final var req = new QueryRequest(solrParams);
-    final var solrResponse =
-        solrClient.requestWithBaseUrl(daemonReplica.getBaseUrl(), 
daemonReplica.getCoreName(), req);
-    return solrResponse.getResponse();
+    return solrClient.requestWithBaseUrl(
+        daemonReplica.getBaseUrl(), req, daemonReplica.getCoreName());
   }
 
   private void cleanup(
diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java 
b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
index d5106edb252..2ed0a3fb2d1 100644
--- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java
+++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
@@ -71,6 +71,7 @@ import org.apache.solr.api.JerseyResource;
 import org.apache.solr.client.solrj.SolrRequest;
 import org.apache.solr.client.solrj.impl.Http2SolrClient;
 import org.apache.solr.client.solrj.impl.HttpClientUtil;
+import org.apache.solr.client.solrj.impl.HttpSolrClientBase;
 import org.apache.solr.client.solrj.impl.SolrHttpClientBuilder;
 import org.apache.solr.client.solrj.impl.SolrHttpClientContextBuilder;
 import 
org.apache.solr.client.solrj.impl.SolrHttpClientContextBuilder.AuthSchemeRegistryProvider;
@@ -762,7 +763,7 @@ public class CoreContainer {
    *
    * @see #getDefaultHttpSolrClient()
    * @see ZkController#getSolrClient()
-   * @see Http2SolrClient#requestWithBaseUrl(String, String, SolrRequest)
+   * @see HttpSolrClientBase#requestWithBaseUrl(String, SolrRequest, String)
    * @deprecated likely to simply be moved to the ObjectCache so as to not be 
used
    */
   @Deprecated
@@ -2585,7 +2586,7 @@ public class CoreContainer {
    * <p>The caller does not need to close the client.
    *
    * @return the existing {@link Http2SolrClient}
-   * @see Http2SolrClient#requestWithBaseUrl(String, String, SolrRequest)
+   * @see HttpSolrClientBase#requestWithBaseUrl(String, SolrRequest, String)
    */
   public Http2SolrClient getDefaultHttpSolrClient() {
     return solrClientProvider.getSolrClient();
diff --git a/solr/core/src/java/org/apache/solr/handler/IndexFetcher.java 
b/solr/core/src/java/org/apache/solr/handler/IndexFetcher.java
index cc9d4cd79ce..17664a9fcd5 100644
--- a/solr/core/src/java/org/apache/solr/handler/IndexFetcher.java
+++ b/solr/core/src/java/org/apache/solr/handler/IndexFetcher.java
@@ -361,7 +361,7 @@ public class IndexFetcher {
     params.set(CommonParams.QT, ReplicationHandler.PATH);
     QueryRequest req = new QueryRequest(params);
     try {
-      return solrClient.requestWithBaseUrl(leaderBaseUrl, leaderCoreName, 
req).getResponse();
+      return solrClient.requestWithBaseUrl(leaderBaseUrl, req, leaderCoreName);
     } catch (SolrServerException e) {
       throw new SolrException(ErrorCode.SERVER_ERROR, e.getMessage(), e);
     }
@@ -380,8 +380,7 @@ public class IndexFetcher {
     params.set(CommonParams.QT, ReplicationHandler.PATH);
     QueryRequest req = new QueryRequest(params);
     try {
-      NamedList<?> response =
-          solrClient.requestWithBaseUrl(leaderBaseUrl, leaderCoreName, 
req).getResponse();
+      NamedList<?> response = solrClient.requestWithBaseUrl(leaderBaseUrl, 
req, leaderCoreName);
 
       List<Map<String, Object>> files = (List<Map<String, Object>>) 
response.get(CMD_GET_FILE_LIST);
       if (files != null) filesToDownload = Collections.synchronizedList(files);
@@ -1955,7 +1954,7 @@ public class IndexFetcher {
         QueryRequest req = new QueryRequest(params);
         req.setResponseParser(new InputStreamResponseParser(FILE_STREAM));
         if (useExternalCompression) req.addHeader("Accept-Encoding", "gzip");
-        response = solrClient.requestWithBaseUrl(leaderBaseUrl, 
leaderCoreName, req).getResponse();
+        response = solrClient.requestWithBaseUrl(leaderBaseUrl, req, 
leaderCoreName);
         final var responseStatus = (Integer) response.get("responseStatus");
         is = (InputStream) response.get("stream");
 
@@ -2101,7 +2100,7 @@ public class IndexFetcher {
 
     QueryRequest request = new QueryRequest(params);
     // TODO use shardhandler
-    return solrClient.requestWithBaseUrl(leaderBaseUrl, leaderCoreName, 
request).getResponse();
+    return solrClient.requestWithBaseUrl(leaderBaseUrl, request, 
leaderCoreName);
   }
 
   public void destroy() {
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/ColStatus.java 
b/solr/core/src/java/org/apache/solr/handler/admin/ColStatus.java
index 39e115146b9..d3576d364b8 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/ColStatus.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/ColStatus.java
@@ -201,7 +201,7 @@ public class ColStatus {
               params.add(RAW_SIZE_SAMPLING_PERCENT_PROP, 
String.valueOf(samplingPercent));
             }
             QueryRequest req = new QueryRequest(params);
-            NamedList<Object> rsp = solrClient.requestWithBaseUrl(url, null, 
req).getResponse();
+            NamedList<Object> rsp = solrClient.requestWithBaseUrl(url, req, 
null);
             final var segmentResponse =
                 SolrJacksonMapper.getObjectMapper().convertValue(rsp, 
GetSegmentDataResponse.class);
             segmentResponse.responseHeader = null;
diff --git 
a/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java 
b/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java
index fe5923eb751..ce1c09a8742 100644
--- a/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java
+++ b/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java
@@ -390,7 +390,7 @@ public class PKIAuthenticationPlugin extends 
AuthenticationPlugin
       final var request = new GenericSolrRequest(GET, PublicKeyHandler.PATH, 
solrParams);
       log.debug("Fetching fresh public key from: {}", url);
       var solrClient = cores.getDefaultHttpSolrClient();
-      NamedList<Object> resp = solrClient.requestWithBaseUrl(url, 
request::process).getResponse();
+      NamedList<Object> resp = solrClient.requestWithBaseUrl(url, request, 
null);
 
       String key = (String) resp.get("key");
       if (key == null) {
diff --git a/solr/core/src/java/org/apache/solr/update/PeerSyncWithLeader.java 
b/solr/core/src/java/org/apache/solr/update/PeerSyncWithLeader.java
index f46e0c161e7..df356944e17 100644
--- a/solr/core/src/java/org/apache/solr/update/PeerSyncWithLeader.java
+++ b/solr/core/src/java/org/apache/solr/update/PeerSyncWithLeader.java
@@ -334,7 +334,7 @@ public class PeerSyncWithLeader implements 
SolrMetricProducer {
   private NamedList<Object> request(ModifiableSolrParams params, String 
onFail) {
     try {
       QueryRequest request = new QueryRequest(params, SolrRequest.METHOD.POST);
-      QueryResponse rsp = clientToLeader.requestWithBaseUrl(leaderBaseUrl, 
coreName, request);
+      QueryResponse rsp = request.processWithBaseUrl(clientToLeader, 
leaderBaseUrl, coreName);
       Exception exception = rsp.getException();
       if (exception != null) {
         throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, onFail);
diff --git a/solr/core/src/java/org/apache/solr/update/SolrCmdDistributor.java 
b/solr/core/src/java/org/apache/solr/update/SolrCmdDistributor.java
index 7f1998d6c82..de00ffa9213 100644
--- a/solr/core/src/java/org/apache/solr/update/SolrCmdDistributor.java
+++ b/solr/core/src/java/org/apache/solr/update/SolrCmdDistributor.java
@@ -317,7 +317,7 @@ public class SolrCmdDistributor implements Closeable {
       try {
         clients
             .getHttpClient()
-            .requestWithBaseUrl(req.node.getBaseUrl(), req.node.getCoreName(), 
req.uReq);
+            .requestWithBaseUrl(req.node.getBaseUrl(), req.uReq, 
req.node.getCoreName());
       } catch (Exception e) {
         log.error("Exception making request", e);
         SolrError error = new SolrError();
diff --git 
a/solr/core/src/java/org/apache/solr/update/processor/DistributedUpdateProcessor.java
 
b/solr/core/src/java/org/apache/solr/update/processor/DistributedUpdateProcessor.java
index 8e3153046ad..3485e3d9e17 100644
--- 
a/solr/core/src/java/org/apache/solr/update/processor/DistributedUpdateProcessor.java
+++ 
b/solr/core/src/java/org/apache/solr/update/processor/DistributedUpdateProcessor.java
@@ -692,11 +692,7 @@ public class DistributedUpdateProcessor extends 
UpdateRequestProcessor {
 
     NamedList<Object> rsp;
     try {
-      rsp =
-          updateShardHandler
-              .getUpdateOnlyHttpClient()
-              .requestWithBaseUrl(leaderUrl, null, ur)
-              .getResponse();
+      rsp = 
updateShardHandler.getUpdateOnlyHttpClient().requestWithBaseUrl(leaderUrl, ur, 
null);
     } catch (SolrServerException e) {
       throw new SolrException(
           ErrorCode.SERVER_ERROR,
diff --git 
a/solr/core/src/test/org/apache/solr/handler/TestUserManagedReplicationWithAuth.java
 
b/solr/core/src/test/org/apache/solr/handler/TestUserManagedReplicationWithAuth.java
index 98a5684791d..fdf8ef49709 100644
--- 
a/solr/core/src/test/org/apache/solr/handler/TestUserManagedReplicationWithAuth.java
+++ 
b/solr/core/src/test/org/apache/solr/handler/TestUserManagedReplicationWithAuth.java
@@ -238,7 +238,7 @@ public class TestUserManagedReplicationWithAuth extends 
SolrTestCaseJ4 {
     withBasicAuth(req);
 
     final var baseUrl = buildUrl(Jetty.getLocalPort());
-    solrClient.requestWithBaseUrl(baseUrl, DEFAULT_TEST_CORENAME, req);
+    solrClient.requestWithBaseUrl(baseUrl, req, DEFAULT_TEST_CORENAME);
   }
 
   private void pullIndexFromTo(
@@ -247,7 +247,7 @@ public class TestUserManagedReplicationWithAuth extends 
SolrTestCaseJ4 {
     String srcUrl = buildUrl(srcSolr.getLocalPort()) + "/" + 
DEFAULT_TEST_CORENAME;
     QueryRequest req = getQueryRequestForFetchIndex(authEnabled, srcUrl);
     final var baseUrl = buildUrl(destSolr.getLocalPort());
-    followerClient.requestWithBaseUrl(baseUrl, DEFAULT_TEST_CORENAME, req);
+    followerClient.requestWithBaseUrl(baseUrl, req, DEFAULT_TEST_CORENAME);
   }
 
   private QueryRequest getQueryRequestForFetchIndex(boolean authEnabled, 
String srcUrl) {
diff --git 
a/solr/solrj-zookeeper/src/java/org/apache/solr/client/solrj/impl/SolrClientNodeStateProvider.java
 
b/solr/solrj-zookeeper/src/java/org/apache/solr/client/solrj/impl/SolrClientNodeStateProvider.java
index eb2e377c3ad..1494f616016 100644
--- 
a/solr/solrj-zookeeper/src/java/org/apache/solr/client/solrj/impl/SolrClientNodeStateProvider.java
+++ 
b/solr/solrj-zookeeper/src/java/org/apache/solr/client/solrj/impl/SolrClientNodeStateProvider.java
@@ -289,7 +289,7 @@ public class SolrClientNodeStateProvider implements 
NodeStateProvider, MapWriter
       request.setResponseParser(new BinaryResponseParser());
 
       try {
-        return cloudSolrClient.getHttpClient().requestWithBaseUrl(url, 
request::process);
+        return request.processWithBaseUrl(cloudSolrClient.getHttpClient(), 
url, null);
       } catch (SolrServerException | IOException e) {
         throw new SolrException(ErrorCode.SERVER_ERROR, "Fetching replica 
metrics failed", e);
       }
diff --git 
a/solr/solrj-zookeeper/src/java/org/apache/solr/common/cloud/NodesSysPropsCacher.java
 
b/solr/solrj-zookeeper/src/java/org/apache/solr/common/cloud/NodesSysPropsCacher.java
index 35d6829f7cb..f16858be16a 100644
--- 
a/solr/solrj-zookeeper/src/java/org/apache/solr/common/cloud/NodesSysPropsCacher.java
+++ 
b/solr/solrj-zookeeper/src/java/org/apache/solr/common/cloud/NodesSysPropsCacher.java
@@ -88,9 +88,7 @@ public class NodesSysPropsCacher implements NodesSysProps, 
AutoCloseable {
     try {
       LinkedHashMap<String, Object> result = new LinkedHashMap<>();
       NavigableObject response =
-          solrClient
-              
.requestWithBaseUrl(zkStateReader.getBaseUrlForNodeName(nodeName), null, req)
-              .getResponse();
+          
solrClient.requestWithBaseUrl(zkStateReader.getBaseUrlForNodeName(nodeName), 
req, null);
       var metrics = NavigableObject.wrap(response._get("metrics"));
       keys.forEach((tag, key) -> result.put(tag, metrics._get(key)));
       return result;
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/SolrRequest.java 
b/solr/solrj/src/java/org/apache/solr/client/solrj/SolrRequest.java
index c86b8046128..49c52f18d36 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/SolrRequest.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/SolrRequest.java
@@ -26,6 +26,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
+import org.apache.solr.client.solrj.impl.HttpSolrClientBase;
 import org.apache.solr.client.solrj.request.RequestWriter;
 import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.common.util.ContentStream;
@@ -283,6 +284,29 @@ public abstract class SolrRequest<T extends SolrResponse> 
implements Serializabl
     return res;
   }
 
+  /**
+   * Send this request to a {@link SolrClient} and return the response
+   *
+   * @param client the SolrClient to communicate with
+   * @param baseUrl the base URL, e.g. {@code Http://localhost:8983/solr}
+   * @param collection the collection to execute the request against
+   * @return the response
+   * @throws SolrServerException if there is an error on the Solr server
+   * @throws IOException if there is a communication error
+   * @lucene.experimental
+   */
+  public final T processWithBaseUrl(HttpSolrClientBase client, String baseUrl, 
String collection)
+      throws SolrServerException, IOException {
+    // duplicative with process(), except for requestWithBaseUrl
+    long startNanos = System.nanoTime();
+    T res = createResponse(client);
+    var namedList = client.requestWithBaseUrl(baseUrl, this, collection);
+    res.setResponse(namedList);
+    long endNanos = System.nanoTime();
+    res.setElapsedTime(TimeUnit.NANOSECONDS.toMillis(endNanos - startNanos));
+    return res;
+  }
+
   /**
    * Send this request to a {@link SolrClient} and return the response
    *
diff --git 
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ConcurrentUpdateHttp2SolrClient.java
 
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ConcurrentUpdateHttp2SolrClient.java
index ae79909e212..895f66f8719 100644
--- 
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ConcurrentUpdateHttp2SolrClient.java
+++ 
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/ConcurrentUpdateHttp2SolrClient.java
@@ -395,7 +395,7 @@ public class ConcurrentUpdateHttp2SolrClient extends 
SolrClient {
             ? defaultCollection
             : collection;
     if (!(request instanceof UpdateRequest)) {
-      return client.requestWithBaseUrl(basePath, (c) -> c.request(request, 
effectiveCollection));
+      return client.requestWithBaseUrl(basePath, request, effectiveCollection);
     }
     UpdateRequest req = (UpdateRequest) request;
     // this happens for commit...
@@ -405,14 +405,13 @@ public class ConcurrentUpdateHttp2SolrClient extends 
SolrClient {
           && (req.getDeleteByIdMap() == null || 
req.getDeleteByIdMap().isEmpty())) {
         if (req.getDeleteQuery() == null) {
           blockUntilFinished();
-          return client.requestWithBaseUrl(
-              basePath, (c) -> c.request(request, effectiveCollection));
+          return client.requestWithBaseUrl(basePath, request, 
effectiveCollection);
         }
       }
     } else {
       if ((req.getDocuments() == null || req.getDocuments().isEmpty())) {
         blockUntilFinished();
-        return client.requestWithBaseUrl(basePath, (c) -> c.request(request, 
effectiveCollection));
+        return client.requestWithBaseUrl(basePath, request, 
effectiveCollection);
       }
     }
 
@@ -422,7 +421,7 @@ public class ConcurrentUpdateHttp2SolrClient extends 
SolrClient {
       if (params.getBool(UpdateParams.WAIT_SEARCHER, false)) {
         log.info("blocking for commit/optimize");
         blockUntilFinished(); // empty the queue
-        return client.requestWithBaseUrl(basePath, (c) -> c.request(request, 
effectiveCollection));
+        return client.requestWithBaseUrl(basePath, request, 
effectiveCollection);
       }
     }
 
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 5b7fbf1e62b..b4936da4160 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
@@ -637,6 +637,13 @@ public class Http2SolrClient extends HttpSolrClientBase {
     }
   }
 
+  @Override
+  public NamedList<Object> requestWithBaseUrl(
+      String baseUrl, SolrRequest<?> solrRequest, String collection)
+      throws SolrServerException, IOException {
+    return requestWithBaseUrl(baseUrl, c -> c.request(solrRequest, 
collection));
+  }
+
   /**
    * Executes a SolrRequest using the provided URL to temporarily override any 
"base URL" currently
    * used by this client
@@ -647,6 +654,7 @@ public class Http2SolrClient extends HttpSolrClientBase {
    *     on the client's default
    * @param req the SolrRequest to send
    */
+  @Deprecated(since = "9.11")
   public final <R extends SolrResponse> R requestWithBaseUrl(
       String baseUrl, String collection, SolrRequest<R> req)
       throws SolrServerException, IOException {
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 fe7612d074e..78b5bf18d28 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
@@ -167,7 +167,7 @@ public class HttpJdkSolrClient extends HttpSolrClientBase {
   public CompletableFuture<NamedList<Object>> requestAsync(
       final SolrRequest<?> solrRequest, String collection) {
     try {
-      PreparedRequest pReq = prepareRequest(solrRequest, collection);
+      PreparedRequest pReq = prepareRequest(solrRequest, collection, null);
       return httpClient
           .sendAsync(pReq.reqb.build(), 
HttpResponse.BodyHandlers.ofInputStream())
           .thenApply(
@@ -187,9 +187,10 @@ public class HttpJdkSolrClient extends HttpSolrClientBase {
   }
 
   @Override
-  public NamedList<Object> request(SolrRequest<?> solrRequest, String 
collection)
+  public NamedList<Object> requestWithBaseUrl(
+      String baseUrl, SolrRequest<?> solrRequest, String collection)
       throws SolrServerException, IOException {
-    PreparedRequest pReq = prepareRequest(solrRequest, collection);
+    PreparedRequest pReq = prepareRequest(solrRequest, collection, baseUrl);
     HttpResponse<InputStream> response = null;
     try {
       response = httpClient.send(pReq.reqb.build(), 
HttpResponse.BodyHandlers.ofInputStream());
@@ -202,8 +203,8 @@ public class HttpJdkSolrClient extends HttpSolrClientBase {
           "Timeout occurred while waiting response from server at: " + 
pReq.url, e);
     } catch (SolrException se) {
       throw se;
-    } catch (RuntimeException re) {
-      throw new SolrServerException(re);
+    } catch (RuntimeException e) {
+      throw new SolrServerException(e);
     } finally {
       if (pReq.contentWritingFuture != null) {
         pReq.contentWritingFuture.cancel(true);
@@ -221,13 +222,25 @@ public class HttpJdkSolrClient extends HttpSolrClientBase 
{
     }
   }
 
-  private PreparedRequest prepareRequest(SolrRequest<?> solrRequest, String 
collection)
+  @Override
+  public NamedList<Object> request(SolrRequest<?> solrRequest, String 
collection)
+      throws SolrServerException, IOException {
+    return requestWithBaseUrl(null, solrRequest, collection);
+  }
+
+  protected PreparedRequest prepareRequest(
+      SolrRequest<?> solrRequest, String collection, String overrideBaseUrl)
       throws SolrServerException, IOException {
     checkClosed();
     if (ClientUtils.shouldApplyDefaultCollection(collection, solrRequest)) {
       collection = defaultCollection;
     }
-    String url = getRequestUrl(solrRequest, collection);
+    String url;
+    if (overrideBaseUrl != null) {
+      url = ClientUtils.buildRequestUrl(solrRequest, requestWriter, 
overrideBaseUrl, collection);
+    } else {
+      url = getRequestUrl(solrRequest, collection);
+    }
     ResponseParser parserToUse = responseParser(solrRequest);
     ModifiableSolrParams queryParams = initializeSolrParams(solrRequest, 
parserToUse);
     var reqb = HttpRequest.newBuilder();
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 b29195f3d9e..9893f6ce7fd 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
@@ -348,6 +348,21 @@ public abstract class HttpSolrClientBase extends 
SolrClient {
 
   protected abstract void updateDefaultMimeTypeForParser();
 
+  /**
+   * Executes a SolrRequest using the provided URL to temporarily override any 
"base URL" currently
+   * used by this client
+   *
+   * @param baseUrl a URL to a root Solr path (i.e. "/solr") that should be 
used for this request
+   * @param solrRequest the SolrRequest to send
+   * @param collection an optional collection or core name used to override 
the client's "default
+   *     collection". May be 'null' for any requests that don't require a 
collection or wish to rely
+   *     on the client's default
+   * @see SolrRequest#processWithBaseUrl(HttpSolrClientBase, String, String)
+   */
+  public abstract NamedList<Object> requestWithBaseUrl(
+      String baseUrl, SolrRequest<?> solrRequest, String collection)
+      throws SolrServerException, IOException;
+
   /**
    * @deprecated use {@link #requestAsync(SolrRequest, String)}.
    * @param solrRequest the request to perform
diff --git 
a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBSolrClient.java 
b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBSolrClient.java
index d8a82df701b..5bdfa4cea05 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBSolrClient.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/LBSolrClient.java
@@ -564,12 +564,12 @@ public abstract class LBSolrClient extends SolrClient {
       throws SolrServerException, IOException {
     final var solrClient = getClient(baseUrl);
 
-    // Some implementations of LBSolrClient.getClient(...) return a 
Http2SolrClient that may not be
-    // pointed at the desired URL (or any URL for that matter).  We special 
case that here to ensure
-    // the appropriate URL is provided.
-    if (solrClient instanceof Http2SolrClient) {
-      final var httpSolrClient = (Http2SolrClient) solrClient;
-      return httpSolrClient.requestWithBaseUrl(baseUrl, (c) -> 
c.request(solrRequest, collection));
+    // Some implementations of LBSolrClient.getClient(...) return a 
HttpSolrClientBase that may not
+    // be pointed at the desired URL (or any URL for that matter).  We 
special-case that here to
+    // ensure the appropriate URL is provided.
+    if (solrClient instanceof HttpSolrClientBase) {
+      final var httpSolrClient = (HttpSolrClientBase) solrClient;
+      return httpSolrClient.requestWithBaseUrl(baseUrl, solrRequest, 
collection);
     }
 
     // Assume provided client already uses 'baseUrl'
diff --git 
a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/Http2SolrClientTest.java
 
b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/Http2SolrClientTest.java
index ab9bf93540b..f9aa19b7c19 100644
--- 
a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/Http2SolrClientTest.java
+++ 
b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/Http2SolrClientTest.java
@@ -138,7 +138,7 @@ public class Http2SolrClientTest extends 
HttpSolrClientTestBase {
     try (Http2SolrClient client = new Http2SolrClient.Builder(null).build()) {
       try {
         // if client base url is null, request url will be used in exception 
message
-        client.requestWithBaseUrl(getBaseUrl() + DEBUG_SERVLET_PATH, 
DEFAULT_CORE, new SolrPing());
+        client.requestWithBaseUrl(getBaseUrl() + DEBUG_SERVLET_PATH, new 
SolrPing(), DEFAULT_CORE);
 
         fail("Didn't get excepted exception from oversided request");
       } catch (SolrException e) {
@@ -231,7 +231,7 @@ public class Http2SolrClientTest extends 
HttpSolrClientTestBase {
     try (Http2SolrClient client =
         new 
Http2SolrClient.Builder(defaultUrl).withDefaultCollection(DEFAULT_CORE).build())
 {
       try {
-        client.requestWithBaseUrl(baseUrlToUse, null, new 
QueryRequest(queryParams));
+        client.requestWithBaseUrl(baseUrlToUse, new QueryRequest(queryParams), 
null);
       } catch (BaseHttpSolrClient.RemoteSolrException rse) {
       }
 
diff --git 
a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpJdkSolrClientTest.java
 
b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpJdkSolrClientTest.java
index 3c32ccfe7e9..f88a67674c4 100644
--- 
a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpJdkSolrClientTest.java
+++ 
b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpJdkSolrClientTest.java
@@ -192,6 +192,25 @@ public class HttpJdkSolrClientTest extends 
HttpSolrClientTestBase {
     }
   }
 
+  @Test
+  public void testRequestWithBaseUrl() throws Exception {
+    DebugServlet.clear();
+    DebugServlet.addResponseHeader("Content-Type", "application/octet-stream");
+    DebugServlet.responseBodyByQueryFragment.put("", javabinResponse());
+    String someOtherUrl = getBaseUrl() + "/some/other/base/url";
+    String intendedUrl = getBaseUrl() + DEBUG_SERVLET_PATH;
+    SolrQuery q = new SolrQuery("foo");
+    q.setParam("a", MUST_ENCODE);
+
+    HttpJdkSolrClient.Builder b =
+        builder(someOtherUrl).withResponseParser(new BinaryResponseParser());
+    try (HttpJdkSolrClient client = b.build()) {
+      client.requestWithBaseUrl(intendedUrl, new QueryRequest(q, 
SolrRequest.METHOD.GET), null);
+      assertEquals(
+          client.getParser().getWriterType(), 
DebugServlet.parameters.get(CommonParams.WT)[0]);
+    }
+  }
+
   @Test
   public void testGetById() throws Exception {
     DebugServlet.clear();


Reply via email to