You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by ge...@apache.org on 2023/09/11 18:03:43 UTC
[solr] branch branch_9x updated: SOLR-16825: Migrate api definitions to submodule, pt 3 (#1902)
This is an automated email from the ASF dual-hosted git repository.
gerlowskija pushed a commit to branch branch_9x
in repository https://gitbox.apache.org/repos/asf/solr.git
The following commit(s) were added to refs/heads/branch_9x by this push:
new 44ff92b6f74 SOLR-16825: Migrate api definitions to submodule, pt 3 (#1902)
44ff92b6f74 is described below
commit 44ff92b6f740f8bc7c402d41eafc88d49446f335
Author: Jason Gerlowski <ge...@apache.org>
AuthorDate: Mon Sep 11 13:58:40 2023 -0400
SOLR-16825: Migrate api definitions to submodule, pt 3 (#1902)
This commit covers the rename-collection, get-public-key, sync-shard, balance-
replicas, force-leader, and replace-node APIs.
Extracting annotated interfaces for these APIs includes them in the SolrRequest-
generation we now do in SolrJ.
---
.../client/api/endpoint/BalanceReplicasApi.java} | 34 +++++++------
.../solr/client/api/endpoint/ForceLeaderApi.java | 34 +++++++++++++
.../solr/client/api/endpoint/GetPublicKeyApi.java} | 29 ++++++-----
.../client/api/endpoint/RenameCollectionApi.java | 37 ++++++++++++++
.../solr/client/api/endpoint/ReplaceNodeApi.java | 45 +++++++++++++++++
.../solr/client/api/endpoint/SyncShardApi.java | 37 ++++++++++++++
.../api/model/BalanceReplicasRequestBody.java | 50 +++++++++++++++++++
.../solr/client/api/model/PublicKeyResponse.java} | 24 +++------
.../api/model/RenameCollectionRequestBody.java} | 23 ++++-----
.../client/api/model/ReplaceNodeRequestBody.java | 50 +++++++++++++++++++
.../solr/handler/admin/CollectionsHandler.java | 30 ++++++------
...alanceReplicasAPI.java => BalanceReplicas.java} | 54 +++-----------------
.../api/{ForceLeaderAPI.java => ForceLeader.java} | 25 +++-------
...ameCollectionAPI.java => RenameCollection.java} | 41 +++++-----------
.../api/{ReplaceNodeAPI.java => ReplaceNode.java} | 57 +++-------------------
.../api/{SyncShardAPI.java => SyncShard.java} | 24 +++------
.../{PublicKeyAPI.java => GetPublicKey.java} | 26 +++-------
.../org/apache/solr/security/PublicKeyHandler.java | 4 +-
.../org/apache/solr/cloud/BalanceReplicasTest.java | 9 ++--
.../solr/handler/admin/api/ForceLeaderAPITest.java | 10 ++--
.../handler/admin/api/MigrateReplicasAPITest.java | 2 +-
.../solr/handler/admin/api/ReplaceNodeAPITest.java | 13 +++--
.../solr/handler/admin/api/SyncShardAPITest.java | 6 +--
...PublicKeyAPITest.java => GetPublicKeyTest.java} | 6 +--
.../solrj/src/resources/java-template/api.mustache | 1 +
25 files changed, 389 insertions(+), 282 deletions(-)
diff --git a/solr/core/src/test/org/apache/solr/security/PublicKeyAPITest.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/BalanceReplicasApi.java
similarity index 50%
copy from solr/core/src/test/org/apache/solr/security/PublicKeyAPITest.java
copy to solr/api/src/java/org/apache/solr/client/api/endpoint/BalanceReplicasApi.java
index f75b32b85d9..d05719efea8 100644
--- a/solr/core/src/test/org/apache/solr/security/PublicKeyAPITest.java
+++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/BalanceReplicasApi.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,21 +14,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package org.apache.solr.client.api.endpoint;
-package org.apache.solr.security;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import org.apache.solr.client.api.model.BalanceReplicasRequestBody;
+import org.apache.solr.client.api.model.SolrJerseyResponse;
-import org.apache.solr.SolrTestCaseJ4;
-import org.junit.Test;
-
-/** Unit test for {@link PublicKeyAPI} */
-public class PublicKeyAPITest extends SolrTestCaseJ4 {
-
- @Test
- public void testRetrievesPublicKey() {
- final SolrNodeKeyPair nodeKeyPair = new SolrNodeKeyPair(null);
-
- final PublicKeyAPI.PublicKeyResponse response = new PublicKeyAPI(nodeKeyPair).getPublicKey();
-
- assertEquals(nodeKeyPair.getKeyPair().getPublicKeyStr(), response.key);
- }
+@Path("cluster/replicas/balance")
+public interface BalanceReplicasApi {
+ @POST
+ @Operation(
+ summary = "Balance Replicas across the given set of Nodes.",
+ tags = {"cluster"})
+ SolrJerseyResponse balanceReplicas(
+ @RequestBody(description = "Contains user provided parameters")
+ BalanceReplicasRequestBody requestBody)
+ throws Exception;
}
diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/ForceLeaderApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/ForceLeaderApi.java
new file mode 100644
index 00000000000..2a0336a2d3d
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/ForceLeaderApi.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.client.api.endpoint;
+
+import io.swagger.v3.oas.annotations.Operation;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import org.apache.solr.client.api.model.SolrJerseyResponse;
+
+/** V2 API definition for triggering a leader election on a particular collection and shard. */
+@Path("/collections/{collectionName}/shards/{shardName}/force-leader")
+public interface ForceLeaderApi {
+ @POST
+ @Operation(
+ summary = "Force leader election to occur on the specified collection and shard",
+ tags = {"shards"})
+ SolrJerseyResponse forceShardLeader(
+ @PathParam("collectionName") String collectionName, @PathParam("shardName") String shardName);
+}
diff --git a/solr/core/src/test/org/apache/solr/security/PublicKeyAPITest.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/GetPublicKeyApi.java
similarity index 58%
copy from solr/core/src/test/org/apache/solr/security/PublicKeyAPITest.java
copy to solr/api/src/java/org/apache/solr/client/api/endpoint/GetPublicKeyApi.java
index f75b32b85d9..562a2945d9e 100644
--- a/solr/core/src/test/org/apache/solr/security/PublicKeyAPITest.java
+++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/GetPublicKeyApi.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,21 +14,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package org.apache.solr.client.api.endpoint;
-package org.apache.solr.security;
+import io.swagger.v3.oas.annotations.Operation;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import org.apache.solr.client.api.model.PublicKeyResponse;
-import org.apache.solr.SolrTestCaseJ4;
-import org.junit.Test;
+/** V2 API definition to fetch the public key of the receiving node. */
+@Path("/node/key")
+public interface GetPublicKeyApi {
-/** Unit test for {@link PublicKeyAPI} */
-public class PublicKeyAPITest extends SolrTestCaseJ4 {
-
- @Test
- public void testRetrievesPublicKey() {
- final SolrNodeKeyPair nodeKeyPair = new SolrNodeKeyPair(null);
-
- final PublicKeyAPI.PublicKeyResponse response = new PublicKeyAPI(nodeKeyPair).getPublicKey();
-
- assertEquals(nodeKeyPair.getKeyPair().getPublicKeyStr(), response.key);
- }
+ @GET
+ @Operation(
+ summary = "Retrieve the public key of the receiving Solr node.",
+ tags = {"node"})
+ PublicKeyResponse getPublicKey();
}
diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/RenameCollectionApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/RenameCollectionApi.java
new file mode 100644
index 00000000000..6eee0d431f2
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/RenameCollectionApi.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.client.api.endpoint;
+
+import io.swagger.v3.oas.annotations.Operation;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import org.apache.solr.client.api.model.RenameCollectionRequestBody;
+import org.apache.solr.client.api.model.SubResponseAccumulatingJerseyResponse;
+
+/** V2 API definition for "renaming" an existing collection */
+@Path("/collections/{collectionName}/rename")
+public interface RenameCollectionApi {
+
+ @POST
+ @Operation(
+ summary = "Rename a SolrCloud collection",
+ tags = {"collections"})
+ SubResponseAccumulatingJerseyResponse renameCollection(
+ @PathParam("collectionName") String collectionName, RenameCollectionRequestBody requestBody)
+ throws Exception;
+}
diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/ReplaceNodeApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/ReplaceNodeApi.java
new file mode 100644
index 00000000000..56762fa524d
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/ReplaceNodeApi.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.client.api.endpoint;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import org.apache.solr.client.api.model.ReplaceNodeRequestBody;
+import org.apache.solr.client.api.model.SolrJerseyResponse;
+
+/**
+ * V2 API definition for recreating replicas in one node (the source) on another node(s) (the
+ * target).
+ */
+@Path("cluster/nodes/{sourceNodeName}/replace/")
+public interface ReplaceNodeApi {
+ @POST
+ @Operation(
+ summary = "'Replace' a specified node by moving all replicas elsewhere",
+ tags = {"node"})
+ SolrJerseyResponse replaceNode(
+ @Parameter(description = "The name of the node to be replaced.", required = true)
+ @PathParam("sourceNodeName")
+ String sourceNodeName,
+ @RequestBody(description = "Contains user provided parameters", required = true)
+ ReplaceNodeRequestBody requestBody)
+ throws Exception;
+}
diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/SyncShardApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/SyncShardApi.java
new file mode 100644
index 00000000000..1e9805be65a
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/SyncShardApi.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.client.api.endpoint;
+
+import io.swagger.v3.oas.annotations.Operation;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import org.apache.solr.client.api.model.SolrJerseyResponse;
+
+/**
+ * V2 API definition for triggering a shard-sync operation within a particular collection and shard.
+ */
+@Path("/collections/{collectionName}/shards/{shardName}/sync")
+public interface SyncShardApi {
+ @POST
+ @Operation(
+ summary = "Trigger a 'sync' operation for the specified shard",
+ tags = {"shards"})
+ SolrJerseyResponse syncShard(
+ @PathParam("collectionName") String collectionName, @PathParam("shardName") String shardName)
+ throws Exception;
+}
diff --git a/solr/api/src/java/org/apache/solr/client/api/model/BalanceReplicasRequestBody.java b/solr/api/src/java/org/apache/solr/client/api/model/BalanceReplicasRequestBody.java
new file mode 100644
index 00000000000..f270a48b269
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/model/BalanceReplicasRequestBody.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.client.api.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import java.util.Set;
+
+public class BalanceReplicasRequestBody {
+
+ public BalanceReplicasRequestBody() {}
+
+ public BalanceReplicasRequestBody(Set<String> nodes, Boolean waitForFinalState, String async) {
+ this.nodes = nodes;
+ this.waitForFinalState = waitForFinalState;
+ this.async = async;
+ }
+
+ @Schema(
+ description =
+ "The set of nodes across which replicas will be balanced. Defaults to all live data nodes.")
+ @JsonProperty(value = "nodes")
+ public Set<String> nodes;
+
+ @Schema(
+ description =
+ "If true, the request will complete only when all affected replicas become active. "
+ + "If false, the API will return the status of the single action, which may be "
+ + "before the new replica is online and active.")
+ @JsonProperty("waitForFinalState")
+ public Boolean waitForFinalState = false;
+
+ @Schema(description = "Request ID to track this action which will be processed asynchronously.")
+ @JsonProperty("async")
+ public String async;
+}
diff --git a/solr/core/src/test/org/apache/solr/security/PublicKeyAPITest.java b/solr/api/src/java/org/apache/solr/client/api/model/PublicKeyResponse.java
similarity index 58%
copy from solr/core/src/test/org/apache/solr/security/PublicKeyAPITest.java
copy to solr/api/src/java/org/apache/solr/client/api/model/PublicKeyResponse.java
index f75b32b85d9..d561b16fcbb 100644
--- a/solr/core/src/test/org/apache/solr/security/PublicKeyAPITest.java
+++ b/solr/api/src/java/org/apache/solr/client/api/model/PublicKeyResponse.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,21 +14,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package org.apache.solr.client.api.model;
-package org.apache.solr.security;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
-import org.apache.solr.SolrTestCaseJ4;
-import org.junit.Test;
-
-/** Unit test for {@link PublicKeyAPI} */
-public class PublicKeyAPITest extends SolrTestCaseJ4 {
-
- @Test
- public void testRetrievesPublicKey() {
- final SolrNodeKeyPair nodeKeyPair = new SolrNodeKeyPair(null);
-
- final PublicKeyAPI.PublicKeyResponse response = new PublicKeyAPI(nodeKeyPair).getPublicKey();
-
- assertEquals(nodeKeyPair.getKeyPair().getPublicKeyStr(), response.key);
- }
+public class PublicKeyResponse extends SolrJerseyResponse {
+ @JsonProperty("key")
+ @Schema(description = "The public key of the receiving Solr node.")
+ public String key;
}
diff --git a/solr/core/src/test/org/apache/solr/security/PublicKeyAPITest.java b/solr/api/src/java/org/apache/solr/client/api/model/RenameCollectionRequestBody.java
similarity index 58%
copy from solr/core/src/test/org/apache/solr/security/PublicKeyAPITest.java
copy to solr/api/src/java/org/apache/solr/client/api/model/RenameCollectionRequestBody.java
index f75b32b85d9..145618d029e 100644
--- a/solr/core/src/test/org/apache/solr/security/PublicKeyAPITest.java
+++ b/solr/api/src/java/org/apache/solr/client/api/model/RenameCollectionRequestBody.java
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,21 +14,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package org.apache.solr.client.api.model;
-package org.apache.solr.security;
+import static org.apache.solr.client.api.model.Constants.ASYNC;
-import org.apache.solr.SolrTestCaseJ4;
-import org.junit.Test;
+import com.fasterxml.jackson.annotation.JsonProperty;
-/** Unit test for {@link PublicKeyAPI} */
-public class PublicKeyAPITest extends SolrTestCaseJ4 {
+public class RenameCollectionRequestBody {
+ @JsonProperty(required = true)
+ public String to;
- @Test
- public void testRetrievesPublicKey() {
- final SolrNodeKeyPair nodeKeyPair = new SolrNodeKeyPair(null);
+ @JsonProperty(ASYNC)
+ public String async;
- final PublicKeyAPI.PublicKeyResponse response = new PublicKeyAPI(nodeKeyPair).getPublicKey();
-
- assertEquals(nodeKeyPair.getKeyPair().getPublicKeyStr(), response.key);
- }
+ @JsonProperty public Boolean followAliases;
}
diff --git a/solr/api/src/java/org/apache/solr/client/api/model/ReplaceNodeRequestBody.java b/solr/api/src/java/org/apache/solr/client/api/model/ReplaceNodeRequestBody.java
new file mode 100644
index 00000000000..303fd64e8db
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/model/ReplaceNodeRequestBody.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.client.api.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+public class ReplaceNodeRequestBody {
+
+ public ReplaceNodeRequestBody() {}
+
+ public ReplaceNodeRequestBody(String targetNodeName, Boolean waitForFinalState, String async) {
+ this.targetNodeName = targetNodeName;
+ this.waitForFinalState = waitForFinalState;
+ this.async = async;
+ }
+
+ @Schema(
+ description =
+ "The target node where replicas will be copied. If this parameter is not provided, Solr "
+ + "will identify nodes automatically based on policies or number of cores in each node.")
+ @JsonProperty("targetNodeName")
+ public String targetNodeName;
+
+ @Schema(
+ description =
+ "If true, the request will complete only when all affected replicas become active. "
+ + "If false, the API will return the status of the single action, which may be "
+ + "before the new replica is online and active.")
+ @JsonProperty("waitForFinalState")
+ public Boolean waitForFinalState = false;
+
+ @Schema(description = "Request ID to track this action which will be processed asynchronously.")
+ @JsonProperty("async")
+ public String async;
+}
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java
index b1949c993a1..97de7a36bb3 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java
@@ -123,6 +123,7 @@ import org.apache.solr.api.AnnotatedApi;
import org.apache.solr.api.Api;
import org.apache.solr.api.JerseyResource;
import org.apache.solr.client.api.model.AddReplicaPropertyRequestBody;
+import org.apache.solr.client.api.model.ReplaceNodeRequestBody;
import org.apache.solr.client.api.model.SolrJerseyResponse;
import org.apache.solr.client.api.model.UpdateAliasPropertiesRequestBody;
import org.apache.solr.client.solrj.SolrResponse;
@@ -166,7 +167,7 @@ import org.apache.solr.handler.RequestHandlerBase;
import org.apache.solr.handler.admin.api.AddReplicaProperty;
import org.apache.solr.handler.admin.api.AdminAPIBase;
import org.apache.solr.handler.admin.api.AliasProperty;
-import org.apache.solr.handler.admin.api.BalanceReplicasAPI;
+import org.apache.solr.handler.admin.api.BalanceReplicas;
import org.apache.solr.handler.admin.api.BalanceShardUniqueAPI;
import org.apache.solr.handler.admin.api.CollectionPropertyAPI;
import org.apache.solr.handler.admin.api.CollectionStatusAPI;
@@ -184,7 +185,7 @@ import org.apache.solr.handler.admin.api.DeleteNode;
import org.apache.solr.handler.admin.api.DeleteReplica;
import org.apache.solr.handler.admin.api.DeleteReplicaProperty;
import org.apache.solr.handler.admin.api.DeleteShardAPI;
-import org.apache.solr.handler.admin.api.ForceLeaderAPI;
+import org.apache.solr.handler.admin.api.ForceLeader;
import org.apache.solr.handler.admin.api.InstallShardDataAPI;
import org.apache.solr.handler.admin.api.ListAliases;
import org.apache.solr.handler.admin.api.ListCollectionBackups;
@@ -196,11 +197,11 @@ import org.apache.solr.handler.admin.api.ModifyCollectionAPI;
import org.apache.solr.handler.admin.api.MoveReplicaAPI;
import org.apache.solr.handler.admin.api.RebalanceLeadersAPI;
import org.apache.solr.handler.admin.api.ReloadCollectionAPI;
-import org.apache.solr.handler.admin.api.RenameCollectionAPI;
-import org.apache.solr.handler.admin.api.ReplaceNodeAPI;
+import org.apache.solr.handler.admin.api.RenameCollection;
+import org.apache.solr.handler.admin.api.ReplaceNode;
import org.apache.solr.handler.admin.api.RestoreCollectionAPI;
import org.apache.solr.handler.admin.api.SplitShardAPI;
-import org.apache.solr.handler.admin.api.SyncShardAPI;
+import org.apache.solr.handler.admin.api.SyncShard;
import org.apache.solr.handler.api.V2ApiUtils;
import org.apache.solr.logging.MDCLoggingContext;
import org.apache.solr.request.SolrQueryRequest;
@@ -607,7 +608,7 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
SYNCSHARD_OP(
SYNCSHARD,
(req, rsp, h) -> {
- SyncShardAPI.invokeFromV1Params(h.coreContainer, req, rsp);
+ SyncShard.invokeFromV1Params(h.coreContainer, req, rsp);
return null;
}),
@@ -722,7 +723,7 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
FORCELEADER_OP(
FORCELEADER,
(req, rsp, h) -> {
- ForceLeaderAPI.invokeFromV1Params(h.coreContainer, req, rsp);
+ ForceLeader.invokeFromV1Params(h.coreContainer, req, rsp);
return null;
}),
CREATESHARD_OP(
@@ -1175,12 +1176,11 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
(req, rsp, h) -> {
final SolrParams params = req.getParams();
final RequiredSolrParams requiredParams = req.getParams().required();
- final ReplaceNodeAPI.ReplaceNodeRequestBody requestBody =
- new ReplaceNodeAPI.ReplaceNodeRequestBody();
+ final var requestBody = new ReplaceNodeRequestBody();
requestBody.targetNodeName = params.get(TARGET_NODE);
requestBody.waitForFinalState = params.getBool(WAIT_FOR_FINAL_STATE);
requestBody.async = params.get(ASYNC);
- final ReplaceNodeAPI replaceNodeAPI = new ReplaceNodeAPI(h.coreContainer, req, rsp);
+ final ReplaceNode replaceNodeAPI = new ReplaceNode(h.coreContainer, req, rsp);
final SolrJerseyResponse replaceNodeResponse =
replaceNodeAPI.replaceNode(requiredParams.get(SOURCE_NODE), requestBody);
V2ApiUtils.squashIntoSolrResponseWithoutHeader(rsp, replaceNodeResponse);
@@ -1375,17 +1375,17 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
DeleteReplica.class,
DeleteReplicaProperty.class,
DeleteShardAPI.class,
- ForceLeaderAPI.class,
+ ForceLeader.class,
InstallShardDataAPI.class,
ListCollections.class,
ListCollectionBackups.class,
ReloadCollectionAPI.class,
- RenameCollectionAPI.class,
- ReplaceNodeAPI.class,
+ RenameCollection.class,
+ ReplaceNode.class,
MigrateReplicasAPI.class,
- BalanceReplicasAPI.class,
+ BalanceReplicas.class,
RestoreCollectionAPI.class,
- SyncShardAPI.class,
+ SyncShard.class,
CollectionPropertyAPI.class,
DeleteNode.class,
ListAliases.class,
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/api/BalanceReplicasAPI.java b/solr/core/src/java/org/apache/solr/handler/admin/api/BalanceReplicas.java
similarity index 63%
rename from solr/core/src/java/org/apache/solr/handler/admin/api/BalanceReplicasAPI.java
rename to solr/core/src/java/org/apache/solr/handler/admin/api/BalanceReplicas.java
index 53e23886585..6e163857296 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/api/BalanceReplicasAPI.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/api/BalanceReplicas.java
@@ -16,7 +16,6 @@
*/
package org.apache.solr.handler.admin.api;
-import static org.apache.solr.client.solrj.impl.BinaryResponseParser.BINARY_CONTENT_TYPE_V2;
import static org.apache.solr.cloud.Overseer.QUEUE_OPERATION;
import static org.apache.solr.common.params.CollectionParams.NODES;
import static org.apache.solr.common.params.CommonAdminParams.ASYNC;
@@ -24,47 +23,35 @@ import static org.apache.solr.common.params.CommonAdminParams.WAIT_FOR_FINAL_STA
import static org.apache.solr.handler.admin.CollectionsHandler.DEFAULT_COLLECTION_OP_TIMEOUT;
import static org.apache.solr.security.PermissionNameProvider.Name.COLL_EDIT_PERM;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.media.Schema;
-import io.swagger.v3.oas.annotations.parameters.RequestBody;
import java.util.HashMap;
import java.util.Map;
-import java.util.Set;
import javax.inject.Inject;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
+import org.apache.solr.client.api.endpoint.BalanceReplicasApi;
+import org.apache.solr.client.api.model.BalanceReplicasRequestBody;
import org.apache.solr.client.api.model.SolrJerseyResponse;
import org.apache.solr.client.solrj.SolrResponse;
import org.apache.solr.common.cloud.ZkNodeProps;
import org.apache.solr.common.params.CollectionParams.CollectionAction;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.handler.admin.CollectionsHandler;
-import org.apache.solr.jersey.JacksonReflectMapWriter;
import org.apache.solr.jersey.PermissionName;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
/** V2 API for balancing the replicas that already exist across a set of nodes. */
-@Path("cluster/replicas/balance")
-public class BalanceReplicasAPI extends AdminAPIBase {
+public class BalanceReplicas extends AdminAPIBase implements BalanceReplicasApi {
@Inject
- public BalanceReplicasAPI(
+ public BalanceReplicas(
CoreContainer coreContainer,
SolrQueryRequest solrQueryRequest,
SolrQueryResponse solrQueryResponse) {
super(coreContainer, solrQueryRequest, solrQueryResponse);
}
- @POST
- @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2})
+ @Override
@PermissionName(COLL_EDIT_PERM)
- @Operation(summary = "Balance Replicas across the given set of Nodes.")
- public SolrJerseyResponse balanceReplicas(
- @RequestBody(description = "Contains user provided parameters")
- BalanceReplicasRequestBody requestBody)
+ public SolrJerseyResponse balanceReplicas(BalanceReplicasRequestBody requestBody)
throws Exception {
final SolrJerseyResponse response = instantiateJerseyResponse(SolrJerseyResponse.class);
final CoreContainer coreContainer = fetchAndValidateZooKeeperAwareCoreContainer();
@@ -96,33 +83,4 @@ public class BalanceReplicasAPI extends AdminAPIBase {
return new ZkNodeProps(remoteMessage);
}
-
- public static class BalanceReplicasRequestBody implements JacksonReflectMapWriter {
-
- public BalanceReplicasRequestBody() {}
-
- public BalanceReplicasRequestBody(Set<String> nodes, Boolean waitForFinalState, String async) {
- this.nodes = nodes;
- this.waitForFinalState = waitForFinalState;
- this.async = async;
- }
-
- @Schema(
- description =
- "The set of nodes across which replicas will be balanced. Defaults to all live data nodes.")
- @JsonProperty(value = "nodes")
- public Set<String> nodes;
-
- @Schema(
- description =
- "If true, the request will complete only when all affected replicas become active. "
- + "If false, the API will return the status of the single action, which may be "
- + "before the new replica is online and active.")
- @JsonProperty("waitForFinalState")
- public Boolean waitForFinalState = false;
-
- @Schema(description = "Request ID to track this action which will be processed asynchronously.")
- @JsonProperty("async")
- public String async;
- }
}
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/api/ForceLeaderAPI.java b/solr/core/src/java/org/apache/solr/handler/admin/api/ForceLeader.java
similarity index 88%
rename from solr/core/src/java/org/apache/solr/handler/admin/api/ForceLeaderAPI.java
rename to solr/core/src/java/org/apache/solr/handler/admin/api/ForceLeader.java
index b0881a34bac..c3080e3ef16 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/api/ForceLeaderAPI.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/api/ForceLeader.java
@@ -17,7 +17,6 @@
package org.apache.solr.handler.admin.api;
-import static org.apache.solr.client.solrj.impl.BinaryResponseParser.BINARY_CONTENT_TYPE_V2;
import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_PROP;
import static org.apache.solr.common.cloud.ZkStateReader.SHARD_ID_PROP;
import static org.apache.solr.security.PermissionNameProvider.Name.COLL_EDIT_PERM;
@@ -27,11 +26,7 @@ import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.inject.Inject;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
+import org.apache.solr.client.api.endpoint.ForceLeaderApi;
import org.apache.solr.client.api.model.SolrJerseyResponse;
import org.apache.solr.cloud.ZkController;
import org.apache.solr.cloud.ZkShardTerms;
@@ -49,29 +44,25 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * V2 API for triggering a leader election on a particular collection and shard.
+ * V2 API implementation for triggering a leader election on a particular collection and shard.
*
* <p>This API (POST /v2/collections/collectionName/shards/shardName/force-leader) is analogous to
* the v1 /admin/collections?action=FORCELEADER command.
*/
-@Path("/collections/{collectionName}/shards/{shardName}/force-leader")
-public class ForceLeaderAPI extends AdminAPIBase {
+public class ForceLeader extends AdminAPIBase implements ForceLeaderApi {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@Inject
- public ForceLeaderAPI(
+ public ForceLeader(
CoreContainer coreContainer,
SolrQueryRequest solrQueryRequest,
SolrQueryResponse solrQueryResponse) {
super(coreContainer, solrQueryRequest, solrQueryResponse);
}
- @POST
- @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2})
+ @Override
@PermissionName(COLL_EDIT_PERM)
- public SolrJerseyResponse forceLeader(
- @PathParam("collectionName") String collectionName,
- @PathParam("shardName") String shardName) {
+ public SolrJerseyResponse forceShardLeader(String collectionName, String shardName) {
final SolrJerseyResponse response = instantiateJerseyResponse(SolrJerseyResponse.class);
ensureRequiredParameterProvided(COLLECTION_PROP, collectionName);
ensureRequiredParameterProvided(SHARD_ID_PROP, shardName);
@@ -84,12 +75,12 @@ public class ForceLeaderAPI extends AdminAPIBase {
public static void invokeFromV1Params(
CoreContainer coreContainer, SolrQueryRequest request, SolrQueryResponse response) {
- final var api = new ForceLeaderAPI(coreContainer, request, response);
+ final var api = new ForceLeader(coreContainer, request, response);
final var params = request.getParams();
params.required().check(COLLECTION_PROP, SHARD_ID_PROP);
V2ApiUtils.squashIntoSolrResponseWithoutHeader(
- response, api.forceLeader(params.get(COLLECTION_PROP), params.get(SHARD_ID_PROP)));
+ response, api.forceShardLeader(params.get(COLLECTION_PROP), params.get(SHARD_ID_PROP)));
}
private void doForceLeaderElection(String extCollectionName, String shardName) {
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/api/RenameCollectionAPI.java b/solr/core/src/java/org/apache/solr/handler/admin/api/RenameCollection.java
similarity index 76%
rename from solr/core/src/java/org/apache/solr/handler/admin/api/RenameCollectionAPI.java
rename to solr/core/src/java/org/apache/solr/handler/admin/api/RenameCollection.java
index 2fd2d7fb405..8cec8535a7f 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/api/RenameCollectionAPI.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/api/RenameCollection.java
@@ -16,7 +16,6 @@
*/
package org.apache.solr.handler.admin.api;
-import static org.apache.solr.client.solrj.impl.BinaryResponseParser.BINARY_CONTENT_TYPE_V2;
import static org.apache.solr.cloud.Overseer.QUEUE_OPERATION;
import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_PROP;
import static org.apache.solr.common.params.CollectionAdminParams.FOLLOW_ALIASES;
@@ -25,48 +24,40 @@ import static org.apache.solr.common.params.CommonAdminParams.ASYNC;
import static org.apache.solr.common.params.CommonParams.NAME;
import static org.apache.solr.security.PermissionNameProvider.Name.COLL_EDIT_PERM;
-import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
+import org.apache.solr.client.api.endpoint.RenameCollectionApi;
+import org.apache.solr.client.api.model.RenameCollectionRequestBody;
import org.apache.solr.client.api.model.SubResponseAccumulatingJerseyResponse;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.cloud.ZkNodeProps;
import org.apache.solr.common.params.CollectionParams;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.handler.api.V2ApiUtils;
-import org.apache.solr.jersey.JacksonReflectMapWriter;
import org.apache.solr.jersey.PermissionName;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
/**
- * V2 API for "renaming" an existing collection
+ * V2 API implementation to "rename" an existing collection
*
* <p>This API is analogous to the v1 /admin/collections?action=RENAME command.
*/
-@Path("/collections/{collectionName}/rename")
-public class RenameCollectionAPI extends AdminAPIBase {
+public class RenameCollection extends AdminAPIBase implements RenameCollectionApi {
@Inject
- public RenameCollectionAPI(
+ public RenameCollection(
CoreContainer coreContainer,
SolrQueryRequest solrQueryRequest,
SolrQueryResponse solrQueryResponse) {
super(coreContainer, solrQueryRequest, solrQueryResponse);
}
- @POST
- @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2})
+ @Override
@PermissionName(COLL_EDIT_PERM)
public SubResponseAccumulatingJerseyResponse renameCollection(
- @PathParam("collectionName") String collectionName, RenameCollectionRequestBody requestBody)
- throws Exception {
+ String collectionName, RenameCollectionRequestBody requestBody) throws Exception {
final var response = instantiateJerseyResponse(SubResponseAccumulatingJerseyResponse.class);
if (requestBody == null) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Missing required request body");
@@ -81,7 +72,7 @@ public class RenameCollectionAPI extends AdminAPIBase {
response,
CollectionParams.CollectionAction.RENAME,
remoteMessage,
- requestBody != null ? requestBody.asyncId : null);
+ requestBody != null ? requestBody.async : null);
return response;
}
@@ -92,7 +83,7 @@ public class RenameCollectionAPI extends AdminAPIBase {
remoteMessage.put(NAME, collectionName);
remoteMessage.put(TARGET, requestBody.to);
insertIfNotNull(remoteMessage, FOLLOW_ALIASES, requestBody.followAliases);
- insertIfNotNull(remoteMessage, ASYNC, requestBody.asyncId);
+ insertIfNotNull(remoteMessage, ASYNC, requestBody.async);
return new ZkNodeProps(remoteMessage);
}
@@ -100,26 +91,16 @@ public class RenameCollectionAPI extends AdminAPIBase {
public static void invokeFromV1Params(
CoreContainer coreContainer, SolrQueryRequest request, SolrQueryResponse response)
throws Exception {
- final var api = new RenameCollectionAPI(coreContainer, request, response);
+ final var api = new RenameCollection(coreContainer, request, response);
final var params = request.getParams();
params.required().check(COLLECTION_PROP, TARGET);
final var requestBody = new RenameCollectionRequestBody();
requestBody.to = params.get(TARGET);
// Optional parameters
- requestBody.asyncId = params.get(ASYNC);
+ requestBody.async = params.get(ASYNC);
requestBody.followAliases = params.getBool(FOLLOW_ALIASES);
V2ApiUtils.squashIntoSolrResponseWithoutHeader(
response, api.renameCollection(params.get(COLLECTION_PROP), requestBody));
}
-
- public static class RenameCollectionRequestBody implements JacksonReflectMapWriter {
- @JsonProperty(required = true)
- public String to;
-
- @JsonProperty(ASYNC)
- public String asyncId;
-
- @JsonProperty public Boolean followAliases;
- }
}
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/api/ReplaceNodeAPI.java b/solr/core/src/java/org/apache/solr/handler/admin/api/ReplaceNode.java
similarity index 64%
rename from solr/core/src/java/org/apache/solr/handler/admin/api/ReplaceNodeAPI.java
rename to solr/core/src/java/org/apache/solr/handler/admin/api/ReplaceNode.java
index e2e63760ab7..ab597b54038 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/api/ReplaceNodeAPI.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/api/ReplaceNode.java
@@ -16,7 +16,6 @@
*/
package org.apache.solr.handler.admin.api;
-import static org.apache.solr.client.solrj.impl.BinaryResponseParser.BINARY_CONTENT_TYPE_V2;
import static org.apache.solr.cloud.Overseer.QUEUE_OPERATION;
import static org.apache.solr.common.params.CollectionParams.SOURCE_NODE;
import static org.apache.solr.common.params.CollectionParams.TARGET_NODE;
@@ -25,17 +24,11 @@ import static org.apache.solr.common.params.CommonAdminParams.WAIT_FOR_FINAL_STA
import static org.apache.solr.handler.admin.CollectionsHandler.DEFAULT_COLLECTION_OP_TIMEOUT;
import static org.apache.solr.security.PermissionNameProvider.Name.COLL_EDIT_PERM;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.media.Schema;
-import io.swagger.v3.oas.annotations.parameters.RequestBody;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
+import org.apache.solr.client.api.endpoint.ReplaceNodeApi;
+import org.apache.solr.client.api.model.ReplaceNodeRequestBody;
import org.apache.solr.client.api.model.SolrJerseyResponse;
import org.apache.solr.client.solrj.SolrResponse;
import org.apache.solr.common.cloud.ZkNodeProps;
@@ -43,7 +36,6 @@ import org.apache.solr.common.params.CollectionParams;
import org.apache.solr.common.params.CollectionParams.CollectionAction;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.handler.admin.CollectionsHandler;
-import org.apache.solr.jersey.JacksonReflectMapWriter;
import org.apache.solr.jersey.PermissionName;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
@@ -53,26 +45,19 @@ import org.apache.solr.response.SolrQueryResponse;
*
* <p>This API is analogous to the v1 /admin/collections?action=REPLACENODE command.
*/
-@Path("cluster/nodes/{sourceNodeName}/replace/")
-public class ReplaceNodeAPI extends AdminAPIBase {
+public class ReplaceNode extends AdminAPIBase implements ReplaceNodeApi {
@Inject
- public ReplaceNodeAPI(
+ public ReplaceNode(
CoreContainer coreContainer,
SolrQueryRequest solrQueryRequest,
SolrQueryResponse solrQueryResponse) {
super(coreContainer, solrQueryRequest, solrQueryResponse);
}
- @POST
- @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2})
+ @Override
@PermissionName(COLL_EDIT_PERM)
- public SolrJerseyResponse replaceNode(
- @Parameter(description = "The name of the node to be replaced.", required = true)
- @PathParam("sourceNodeName")
- String sourceNodeName,
- @RequestBody(description = "Contains user provided parameters", required = true)
- ReplaceNodeRequestBody requestBody)
+ public SolrJerseyResponse replaceNode(String sourceNodeName, ReplaceNodeRequestBody requestBody)
throws Exception {
final SolrJerseyResponse response = instantiateJerseyResponse(SolrJerseyResponse.class);
final CoreContainer coreContainer = fetchAndValidateZooKeeperAwareCoreContainer();
@@ -111,34 +96,4 @@ public class ReplaceNodeAPI extends AdminAPIBase {
dest.put(key, value);
}
}
-
- public static class ReplaceNodeRequestBody implements JacksonReflectMapWriter {
-
- public ReplaceNodeRequestBody() {}
-
- public ReplaceNodeRequestBody(String targetNodeName, Boolean waitForFinalState, String async) {
- this.targetNodeName = targetNodeName;
- this.waitForFinalState = waitForFinalState;
- this.async = async;
- }
-
- @Schema(
- description =
- "The target node where replicas will be copied. If this parameter is not provided, Solr "
- + "will identify nodes automatically based on policies or number of cores in each node.")
- @JsonProperty("targetNodeName")
- public String targetNodeName;
-
- @Schema(
- description =
- "If true, the request will complete only when all affected replicas become active. "
- + "If false, the API will return the status of the single action, which may be "
- + "before the new replica is online and active.")
- @JsonProperty("waitForFinalState")
- public Boolean waitForFinalState = false;
-
- @Schema(description = "Request ID to track this action which will be processed asynchronously.")
- @JsonProperty("async")
- public String async;
- }
}
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/api/SyncShardAPI.java b/solr/core/src/java/org/apache/solr/handler/admin/api/SyncShard.java
similarity index 83%
rename from solr/core/src/java/org/apache/solr/handler/admin/api/SyncShardAPI.java
rename to solr/core/src/java/org/apache/solr/handler/admin/api/SyncShard.java
index 1b7b44b0dea..b506f585673 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/api/SyncShardAPI.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/api/SyncShard.java
@@ -17,7 +17,6 @@
package org.apache.solr.handler.admin.api;
-import static org.apache.solr.client.solrj.impl.BinaryResponseParser.BINARY_CONTENT_TYPE_V2;
import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_PROP;
import static org.apache.solr.common.cloud.ZkStateReader.SHARD_ID_PROP;
import static org.apache.solr.security.PermissionNameProvider.Name.COLL_EDIT_PERM;
@@ -25,11 +24,7 @@ import static org.apache.solr.security.PermissionNameProvider.Name.COLL_EDIT_PER
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
+import org.apache.solr.client.api.endpoint.SyncShardApi;
import org.apache.solr.client.api.model.SolrJerseyResponse;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrServerException;
@@ -46,28 +41,25 @@ import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
/**
- * V2 API for triggering a shard-sync operation within a particular collection and shard.
+ * V2 API implementation for triggering a shard-sync operation within a particular collection and
+ * shard.
*
* <p>This API (POST /v2/collections/cName/shards/sName/sync {...}) is analogous to the v1
* /admin/collections?action=SYNCSHARD command.
*/
-@Path("/collections/{collectionName}/shards/{shardName}/sync")
-public class SyncShardAPI extends AdminAPIBase {
+public class SyncShard extends AdminAPIBase implements SyncShardApi {
@Inject
- public SyncShardAPI(
+ public SyncShard(
CoreContainer coreContainer,
SolrQueryRequest solrQueryRequest,
SolrQueryResponse solrQueryResponse) {
super(coreContainer, solrQueryRequest, solrQueryResponse);
}
- @POST
- @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2})
+ @Override
@PermissionName(COLL_EDIT_PERM)
- public SolrJerseyResponse syncShard(
- @PathParam("collectionName") String collectionName, @PathParam("shardName") String shardName)
- throws Exception {
+ public SolrJerseyResponse syncShard(String collectionName, String shardName) throws Exception {
final SolrJerseyResponse response = instantiateJerseyResponse(SolrJerseyResponse.class);
ensureRequiredParameterProvided(COLLECTION_PROP, collectionName);
ensureRequiredParameterProvided(SHARD_ID_PROP, shardName);
@@ -105,7 +97,7 @@ public class SyncShardAPI extends AdminAPIBase {
public static void invokeFromV1Params(
CoreContainer coreContainer, SolrQueryRequest request, SolrQueryResponse response)
throws Exception {
- final var api = new SyncShardAPI(coreContainer, request, response);
+ final var api = new SyncShard(coreContainer, request, response);
final var params = request.getParams();
params.required().check(COLLECTION_PROP, SHARD_ID_PROP);
diff --git a/solr/core/src/java/org/apache/solr/security/PublicKeyAPI.java b/solr/core/src/java/org/apache/solr/security/GetPublicKey.java
similarity index 63%
rename from solr/core/src/java/org/apache/solr/security/PublicKeyAPI.java
rename to solr/core/src/java/org/apache/solr/security/GetPublicKey.java
index 46483462e5f..1f7e991667d 100644
--- a/solr/core/src/java/org/apache/solr/security/PublicKeyAPI.java
+++ b/solr/core/src/java/org/apache/solr/security/GetPublicKey.java
@@ -17,45 +17,31 @@
package org.apache.solr.security;
-import static org.apache.solr.client.solrj.impl.BinaryResponseParser.BINARY_CONTENT_TYPE_V2;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import io.swagger.v3.oas.annotations.media.Schema;
import javax.inject.Inject;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
import org.apache.solr.api.JerseyResource;
-import org.apache.solr.client.api.model.SolrJerseyResponse;
+import org.apache.solr.client.api.endpoint.GetPublicKeyApi;
+import org.apache.solr.client.api.model.PublicKeyResponse;
import org.apache.solr.jersey.PermissionName;
/**
- * V2 API for fetching the public key of the receiving node.
+ * V2 API implementation to fetch the public key of the receiving node.
*
* <p>This API is analogous to the v1 /admin/info/key endpoint.
*/
-@Path("/node/key")
-public class PublicKeyAPI extends JerseyResource {
+public class GetPublicKey extends JerseyResource implements GetPublicKeyApi {
private final SolrNodeKeyPair nodeKeyPair;
@Inject
- public PublicKeyAPI(SolrNodeKeyPair nodeKeyPair) {
+ public GetPublicKey(SolrNodeKeyPair nodeKeyPair) {
this.nodeKeyPair = nodeKeyPair;
}
- @GET
- @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2})
+ @Override
@PermissionName(PermissionNameProvider.Name.ALL)
public PublicKeyResponse getPublicKey() {
final PublicKeyResponse response = instantiateJerseyResponse(PublicKeyResponse.class);
response.key = nodeKeyPair.getKeyPair().getPublicKeyStr();
return response;
}
-
- public static class PublicKeyResponse extends SolrJerseyResponse {
- @JsonProperty("key")
- @Schema(description = "The public key of the receiving Solr node.")
- public String key;
- }
}
diff --git a/solr/core/src/java/org/apache/solr/security/PublicKeyHandler.java b/solr/core/src/java/org/apache/solr/security/PublicKeyHandler.java
index 9dbde9d0966..5f2941fec23 100644
--- a/solr/core/src/java/org/apache/solr/security/PublicKeyHandler.java
+++ b/solr/core/src/java/org/apache/solr/security/PublicKeyHandler.java
@@ -50,7 +50,7 @@ public class PublicKeyHandler extends RequestHandlerBase {
@Override
public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception {
V2ApiUtils.squashIntoSolrResponseWithoutHeader(
- rsp, new PublicKeyAPI(nodeKeyPair).getPublicKey());
+ rsp, new GetPublicKey(nodeKeyPair).getPublicKey());
}
@Override
@@ -80,6 +80,6 @@ public class PublicKeyHandler extends RequestHandlerBase {
@Override
public Collection<Class<? extends JerseyResource>> getJerseyResources() {
- return List.of(PublicKeyAPI.class);
+ return List.of(GetPublicKey.class);
}
}
diff --git a/solr/core/src/test/org/apache/solr/cloud/BalanceReplicasTest.java b/solr/core/src/test/org/apache/solr/cloud/BalanceReplicasTest.java
index 82a75027e68..a14b372df2e 100644
--- a/solr/core/src/test/org/apache/solr/cloud/BalanceReplicasTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/BalanceReplicasTest.java
@@ -33,14 +33,15 @@ import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.util.EntityUtils;
+import org.apache.solr.client.api.model.BalanceReplicasRequestBody;
import org.apache.solr.client.solrj.impl.CloudLegacySolrClient;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
+import org.apache.solr.common.MapWriterMap;
import org.apache.solr.common.cloud.DocCollection;
import org.apache.solr.common.cloud.Replica;
import org.apache.solr.common.util.StrUtils;
import org.apache.solr.common.util.Utils;
-import org.apache.solr.handler.admin.api.BalanceReplicasAPI;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -101,7 +102,7 @@ public class BalanceReplicasTest extends SolrCloudTestCase {
postDataAndGetResponse(
cluster.getSolrClient(),
"/api/cluster/replicas/balance",
- BalanceReplicasAPI.BalanceReplicasRequestBody.EMPTY);
+ new MapWriterMap(Collections.emptyMap()));
collection = cloudClient.getClusterState().getCollectionOrNull(coll, false);
log.debug("### After balancing: {}", collection);
@@ -149,8 +150,8 @@ public class BalanceReplicasTest extends SolrCloudTestCase {
postDataAndGetResponse(
cluster.getSolrClient(),
"/api/cluster/replicas/balance",
- new BalanceReplicasAPI.BalanceReplicasRequestBody(
- new HashSet<>(l.subList(1, 4)), true, null));
+ Utils.getReflectWriter(
+ new BalanceReplicasRequestBody(new HashSet<>(l.subList(1, 4)), true, null)));
collection = cloudClient.getClusterState().getCollectionOrNull(coll, false);
log.debug("### After balancing: {}", collection);
diff --git a/solr/core/src/test/org/apache/solr/handler/admin/api/ForceLeaderAPITest.java b/solr/core/src/test/org/apache/solr/handler/admin/api/ForceLeaderAPITest.java
index 09f97a4757f..be1fce44fb8 100644
--- a/solr/core/src/test/org/apache/solr/handler/admin/api/ForceLeaderAPITest.java
+++ b/solr/core/src/test/org/apache/solr/handler/admin/api/ForceLeaderAPITest.java
@@ -21,7 +21,7 @@ import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.common.SolrException;
import org.junit.Test;
-/** Unit tests for {@link ForceLeaderAPI} */
+/** Unit tests for {@link ForceLeader} */
public class ForceLeaderAPITest extends SolrTestCaseJ4 {
@Test
public void testReportsErrorIfCollectionNameMissing() {
@@ -29,8 +29,8 @@ public class ForceLeaderAPITest extends SolrTestCaseJ4 {
expectThrows(
SolrException.class,
() -> {
- final var api = new ForceLeaderAPI(null, null, null);
- api.forceLeader(null, "someShard");
+ final var api = new ForceLeader(null, null, null);
+ api.forceShardLeader(null, "someShard");
});
assertEquals(400, thrown.code());
@@ -43,8 +43,8 @@ public class ForceLeaderAPITest extends SolrTestCaseJ4 {
expectThrows(
SolrException.class,
() -> {
- final var api = new ForceLeaderAPI(null, null, null);
- api.forceLeader("someCollection", null);
+ final var api = new ForceLeader(null, null, null);
+ api.forceShardLeader("someCollection", null);
});
assertEquals(400, thrown.code());
diff --git a/solr/core/src/test/org/apache/solr/handler/admin/api/MigrateReplicasAPITest.java b/solr/core/src/test/org/apache/solr/handler/admin/api/MigrateReplicasAPITest.java
index e87a4c67532..f9bf865d4e0 100644
--- a/solr/core/src/test/org/apache/solr/handler/admin/api/MigrateReplicasAPITest.java
+++ b/solr/core/src/test/org/apache/solr/handler/admin/api/MigrateReplicasAPITest.java
@@ -40,7 +40,7 @@ import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
-/** Unit tests for {@link ReplaceNodeAPI} */
+/** Unit tests for {@link ReplaceNode} */
public class MigrateReplicasAPITest extends SolrTestCaseJ4 {
private CoreContainer mockCoreContainer;
diff --git a/solr/core/src/test/org/apache/solr/handler/admin/api/ReplaceNodeAPITest.java b/solr/core/src/test/org/apache/solr/handler/admin/api/ReplaceNodeAPITest.java
index 3a460245775..e49eb56de0d 100644
--- a/solr/core/src/test/org/apache/solr/handler/admin/api/ReplaceNodeAPITest.java
+++ b/solr/core/src/test/org/apache/solr/handler/admin/api/ReplaceNodeAPITest.java
@@ -25,6 +25,7 @@ import static org.mockito.Mockito.when;
import java.util.Map;
import java.util.Optional;
import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.client.api.model.ReplaceNodeRequestBody;
import org.apache.solr.cloud.OverseerSolrResponse;
import org.apache.solr.cloud.api.collections.DistributedCollectionConfigSetCommandRunner;
import org.apache.solr.common.cloud.ZkNodeProps;
@@ -37,13 +38,13 @@ import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
-/** Unit tests for {@link ReplaceNodeAPI} */
+/** Unit tests for {@link ReplaceNode} */
public class ReplaceNodeAPITest extends SolrTestCaseJ4 {
private CoreContainer mockCoreContainer;
private SolrQueryRequest mockQueryRequest;
private SolrQueryResponse queryResponse;
- private ReplaceNodeAPI replaceNodeApi;
+ private ReplaceNode replaceNodeApi;
private DistributedCollectionConfigSetCommandRunner mockCommandRunner;
private ArgumentCaptor<ZkNodeProps> messageCapturer;
@@ -65,7 +66,7 @@ public class ReplaceNodeAPITest extends SolrTestCaseJ4 {
.thenReturn(new OverseerSolrResponse(new NamedList<>()));
mockQueryRequest = mock(SolrQueryRequest.class);
queryResponse = new SolrQueryResponse();
- replaceNodeApi = new ReplaceNodeAPI(mockCoreContainer, mockQueryRequest, queryResponse);
+ replaceNodeApi = new ReplaceNode(mockCoreContainer, mockQueryRequest, queryResponse);
messageCapturer = ArgumentCaptor.forClass(ZkNodeProps.class);
when(mockCoreContainer.isZooKeeperAware()).thenReturn(true);
@@ -73,8 +74,7 @@ public class ReplaceNodeAPITest extends SolrTestCaseJ4 {
@Test
public void testCreatesValidOverseerMessage() throws Exception {
- ReplaceNodeAPI.ReplaceNodeRequestBody requestBody =
- new ReplaceNodeAPI.ReplaceNodeRequestBody("demoTargetNode", false, "async");
+ final var requestBody = new ReplaceNodeRequestBody("demoTargetNode", false, "async");
replaceNodeApi.replaceNode("demoSourceNode", requestBody);
verify(mockCommandRunner).runCollectionCommand(messageCapturer.capture(), any(), anyLong());
@@ -102,8 +102,7 @@ public class ReplaceNodeAPITest extends SolrTestCaseJ4 {
@Test
public void testOptionalValuesNotAddedToRemoteMessageIfNotProvided() throws Exception {
- ReplaceNodeAPI.ReplaceNodeRequestBody requestBody =
- new ReplaceNodeAPI.ReplaceNodeRequestBody("demoTargetNode", null, null);
+ final var requestBody = new ReplaceNodeRequestBody("demoTargetNode", null, null);
replaceNodeApi.replaceNode("demoSourceNode", requestBody);
verify(mockCommandRunner).runCollectionCommand(messageCapturer.capture(), any(), anyLong());
diff --git a/solr/core/src/test/org/apache/solr/handler/admin/api/SyncShardAPITest.java b/solr/core/src/test/org/apache/solr/handler/admin/api/SyncShardAPITest.java
index 25ca5bb9cd1..23d3f8982a2 100644
--- a/solr/core/src/test/org/apache/solr/handler/admin/api/SyncShardAPITest.java
+++ b/solr/core/src/test/org/apache/solr/handler/admin/api/SyncShardAPITest.java
@@ -21,7 +21,7 @@ import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.common.SolrException;
import org.junit.Test;
-/** Unit tests for {@link SyncShardAPI} */
+/** Unit tests for {@link SyncShard} */
public class SyncShardAPITest extends SolrTestCaseJ4 {
@Test
public void testReportsErrorIfCollectionNameMissing() {
@@ -29,7 +29,7 @@ public class SyncShardAPITest extends SolrTestCaseJ4 {
expectThrows(
SolrException.class,
() -> {
- final var api = new SyncShardAPI(null, null, null);
+ final var api = new SyncShard(null, null, null);
api.syncShard(null, "someShard");
});
@@ -43,7 +43,7 @@ public class SyncShardAPITest extends SolrTestCaseJ4 {
expectThrows(
SolrException.class,
() -> {
- final var api = new SyncShardAPI(null, null, null);
+ final var api = new SyncShard(null, null, null);
api.syncShard("someCollection", null);
});
diff --git a/solr/core/src/test/org/apache/solr/security/PublicKeyAPITest.java b/solr/core/src/test/org/apache/solr/security/GetPublicKeyTest.java
similarity index 84%
rename from solr/core/src/test/org/apache/solr/security/PublicKeyAPITest.java
rename to solr/core/src/test/org/apache/solr/security/GetPublicKeyTest.java
index f75b32b85d9..77bf4646a74 100644
--- a/solr/core/src/test/org/apache/solr/security/PublicKeyAPITest.java
+++ b/solr/core/src/test/org/apache/solr/security/GetPublicKeyTest.java
@@ -20,14 +20,14 @@ package org.apache.solr.security;
import org.apache.solr.SolrTestCaseJ4;
import org.junit.Test;
-/** Unit test for {@link PublicKeyAPI} */
-public class PublicKeyAPITest extends SolrTestCaseJ4 {
+/** Unit test for {@link GetPublicKey} */
+public class GetPublicKeyTest extends SolrTestCaseJ4 {
@Test
public void testRetrievesPublicKey() {
final SolrNodeKeyPair nodeKeyPair = new SolrNodeKeyPair(null);
- final PublicKeyAPI.PublicKeyResponse response = new PublicKeyAPI(nodeKeyPair).getPublicKey();
+ final var response = new GetPublicKey(nodeKeyPair).getPublicKey();
assertEquals(nodeKeyPair.getKeyPair().getPublicKeyStr(), response.key);
}
diff --git a/solr/solrj/src/resources/java-template/api.mustache b/solr/solrj/src/resources/java-template/api.mustache
index 84f7f06ebf3..93108eae513 100644
--- a/solr/solrj/src/resources/java-template/api.mustache
+++ b/solr/solrj/src/resources/java-template/api.mustache
@@ -22,6 +22,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest;