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/27 17:40:14 UTC

[solr] 02/06: Migrade add-replica to 'api' module

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

gerlowskija pushed a commit to branch SOLR-16825-migrate-definitions-to-api-module-pt4
in repository https://gitbox.apache.org/repos/asf/solr.git

commit 0f68b36ab5a4181932db2f942387bf0c871bac60
Author: Jason Gerlowski <ge...@apache.org>
AuthorDate: Tue Sep 26 16:30:15 2023 -0400

    Migrade add-replica to 'api' module
---
 .../solr/client/api/endpoint/CreateReplicaApi.java |  44 +++++++++
 .../client/api/model/CreateReplicaRequestBody.java |  48 ++++++++++
 .../solr/handler/admin/CollectionsHandler.java     |   9 +-
 .../{CreateReplicaAPI.java => CreateReplica.java}  | 105 +++++++--------------
 .../handler/admin/api/CreateReplicaAPITest.java    |  23 ++---
 .../solr/jersey/PostRequestLoggingFilterTest.java  |   6 +-
 6 files changed, 144 insertions(+), 91 deletions(-)

diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/CreateReplicaApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/CreateReplicaApi.java
new file mode 100644
index 00000000000..21c26ea8f49
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/CreateReplicaApi.java
@@ -0,0 +1,44 @@
+/*
+ * 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.CreateReplicaRequestBody;
+import org.apache.solr.client.api.model.SubResponseAccumulatingJerseyResponse;
+
+/**
+ * V2 API definition for adding a new replica to an existing shard.
+ *
+ * <p>This API (POST /v2/collections/cName/shards/sName/replicas {...}) is analogous to the v1
+ * /admin/collections?action=ADDREPLICA command.
+ */
+@Path("/collections/{collectionName}/shards/{shardName}/replicas")
+public interface CreateReplicaApi {
+
+  @POST
+  @Operation(
+      summary = "Creates a new replica of an existing shard.",
+      tags = {"replicas"})
+  SubResponseAccumulatingJerseyResponse createReplica(
+      @PathParam("collectionName") String collectionName,
+      @PathParam("shardName") String shardName,
+      CreateReplicaRequestBody requestBody)
+      throws Exception;
+}
diff --git a/solr/api/src/java/org/apache/solr/client/api/model/CreateReplicaRequestBody.java b/solr/api/src/java/org/apache/solr/client/api/model/CreateReplicaRequestBody.java
new file mode 100644
index 00000000000..a669cdaf414
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/model/CreateReplicaRequestBody.java
@@ -0,0 +1,48 @@
+/*
+ * 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 java.util.List;
+import java.util.Map;
+
+public class CreateReplicaRequestBody {
+  @JsonProperty public String name;
+  @JsonProperty public String type; // TODO Make this an enum - see SOLR-15796
+  @JsonProperty public String instanceDir;
+  @JsonProperty public String dataDir;
+  @JsonProperty public String ulogDir;
+  @JsonProperty public String route;
+  @JsonProperty public Integer nrtReplicas;
+  @JsonProperty public Integer tlogReplicas;
+  @JsonProperty public Integer pullReplicas;
+  @JsonProperty public Boolean waitForFinalState;
+  @JsonProperty public Boolean followAliases;
+
+  @JsonProperty public String async;
+
+  // TODO This cluster of properties could probably be simplified down to just "nodeSet".  See
+  // SOLR-15542
+  @JsonProperty public String node;
+
+  @JsonProperty("nodeSet")
+  public List<String> nodeSet;
+
+  @JsonProperty public Boolean skipNodeAssignment;
+
+  @JsonProperty public Map<String, String> properties;
+}
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 a3ebbf4ae95..5231393ea4e 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
@@ -175,7 +175,7 @@ import org.apache.solr.handler.admin.api.CreateAliasAPI;
 import org.apache.solr.handler.admin.api.CreateCollectionAPI;
 import org.apache.solr.handler.admin.api.CreateCollectionBackupAPI;
 import org.apache.solr.handler.admin.api.CreateCollectionSnapshotAPI;
-import org.apache.solr.handler.admin.api.CreateReplicaAPI;
+import org.apache.solr.handler.admin.api.CreateReplica;
 import org.apache.solr.handler.admin.api.CreateShardAPI;
 import org.apache.solr.handler.admin.api.DeleteAlias;
 import org.apache.solr.handler.admin.api.DeleteCollection;
@@ -942,9 +942,8 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
           final var params = req.getParams();
           params.required().check(COLLECTION_PROP, SHARD_ID_PROP);
 
-          final var api = new CreateReplicaAPI(h.coreContainer, req, rsp);
-          final var requestBody =
-              CreateReplicaAPI.AddReplicaRequestBody.fromV1Params(req.getParams());
+          final var api = new CreateReplica(h.coreContainer, req, rsp);
+          final var requestBody = CreateReplica.createRequestBodyFromV1Params(req.getParams());
           final var response =
               api.createReplica(
                   params.get(COLLECTION_PROP), params.get(SHARD_ID_PROP), requestBody);
@@ -1362,7 +1361,7 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
   @Override
   public Collection<Class<? extends JerseyResource>> getJerseyResources() {
     return List.of(
-        CreateReplicaAPI.class,
+        CreateReplica.class,
         AddReplicaProperty.class,
         BalanceShardUniqueAPI.class,
         CreateAliasAPI.class,
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/api/CreateReplicaAPI.java b/solr/core/src/java/org/apache/solr/handler/admin/api/CreateReplica.java
similarity index 66%
rename from solr/core/src/java/org/apache/solr/handler/admin/api/CreateReplicaAPI.java
rename to solr/core/src/java/org/apache/solr/handler/admin/api/CreateReplica.java
index c119f27db60..2f34556dbda 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/api/CreateReplicaAPI.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/api/CreateReplica.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.cloud.Overseer.QUEUE_OPERATION;
 import static org.apache.solr.cloud.api.collections.CollectionHandlingUtils.CREATE_NODE_SET;
 import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_PROP;
@@ -41,16 +40,12 @@ import static org.apache.solr.common.params.ShardParams._ROUTE_;
 import static org.apache.solr.handler.admin.api.CreateCollectionAPI.copyPrefixedPropertiesWithoutPrefix;
 import static org.apache.solr.security.PermissionNameProvider.Name.COLL_EDIT_PERM;
 
-import com.fasterxml.jackson.annotation.JsonProperty;
 import java.util.Arrays;
 import java.util.HashMap;
-import java.util.List;
 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.CreateReplicaApi;
+import org.apache.solr.client.api.model.CreateReplicaRequestBody;
 import org.apache.solr.client.api.model.SubResponseAccumulatingJerseyResponse;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.cloud.ZkNodeProps;
@@ -59,35 +54,29 @@ import org.apache.solr.common.params.CoreAdminParams;
 import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.common.util.CollectionUtil;
 import org.apache.solr.core.CoreContainer;
-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 adding a new replica to an existing shard.
+ * V2 API implementation for adding a new replica to an existing shard.
  *
  * <p>This API (POST /v2/collections/cName/shards/sName/replicas {...}) is analogous to the v1
  * /admin/collections?action=ADDREPLICA command.
  */
-@Path("/collections/{collectionName}/shards/{shardName}/replicas")
-public class CreateReplicaAPI extends AdminAPIBase {
+public class CreateReplica extends AdminAPIBase implements CreateReplicaApi {
 
   @Inject
-  public CreateReplicaAPI(
+  public CreateReplica(
       CoreContainer coreContainer,
       SolrQueryRequest solrQueryRequest,
       SolrQueryResponse solrQueryResponse) {
     super(coreContainer, solrQueryRequest, solrQueryResponse);
   }
 
-  @POST
-  @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2})
   @PermissionName(COLL_EDIT_PERM)
   public SubResponseAccumulatingJerseyResponse createReplica(
-      @PathParam("collectionName") String collectionName,
-      @PathParam("shardName") String shardName,
-      AddReplicaRequestBody requestBody)
+      String collectionName, String shardName, CreateReplicaRequestBody requestBody)
       throws Exception {
     final var response = instantiateJerseyResponse(SubResponseAccumulatingJerseyResponse.class);
     if (requestBody == null) {
@@ -103,12 +92,12 @@ public class CreateReplicaAPI extends AdminAPIBase {
     final ZkNodeProps remoteMessage =
         createRemoteMessage(resolvedCollectionName, shardName, requestBody);
     submitRemoteMessageAndHandleResponse(
-        response, CollectionParams.CollectionAction.ADDREPLICA, remoteMessage, requestBody.asyncId);
+        response, CollectionParams.CollectionAction.ADDREPLICA, remoteMessage, requestBody.async);
     return response;
   }
 
   public static ZkNodeProps createRemoteMessage(
-      String collectionName, String shardName, AddReplicaRequestBody requestBody) {
+      String collectionName, String shardName, CreateReplicaRequestBody requestBody) {
     final Map<String, Object> remoteMessage = new HashMap<>();
     remoteMessage.put(QUEUE_OPERATION, CollectionParams.CollectionAction.ADDREPLICA.toLower());
     remoteMessage.put(COLLECTION_PROP, collectionName);
@@ -129,7 +118,7 @@ public class CreateReplicaAPI extends AdminAPIBase {
     insertIfNotNull(remoteMessage, TLOG_REPLICAS, requestBody.tlogReplicas);
     insertIfNotNull(remoteMessage, PULL_REPLICAS, requestBody.pullReplicas);
     insertIfNotNull(remoteMessage, FOLLOW_ALIASES, requestBody.followAliases);
-    insertIfNotNull(remoteMessage, ASYNC, requestBody.asyncId);
+    insertIfNotNull(remoteMessage, ASYNC, requestBody.async);
 
     if (requestBody.properties != null) {
       requestBody
@@ -144,59 +133,31 @@ public class CreateReplicaAPI extends AdminAPIBase {
     return new ZkNodeProps(remoteMessage);
   }
 
-  public static class AddReplicaRequestBody implements JacksonReflectMapWriter {
-    @JsonProperty public String name;
-    @JsonProperty public String type; // TODO Make this an enum - see SOLR-15796
-    @JsonProperty public String instanceDir;
-    @JsonProperty public String dataDir;
-    @JsonProperty public String ulogDir;
-    @JsonProperty public String route;
-    @JsonProperty public Integer nrtReplicas;
-    @JsonProperty public Integer tlogReplicas;
-    @JsonProperty public Integer pullReplicas;
-    @JsonProperty public Boolean waitForFinalState;
-    @JsonProperty public Boolean followAliases;
-
-    @JsonProperty(ASYNC)
-    public String asyncId;
-
-    // TODO This cluster of properties could probably be simplified down to just "nodeSet".  See
-    // SOLR-15542
-    @JsonProperty public String node;
-
-    @JsonProperty("nodeSet")
-    public List<String> nodeSet;
-
-    @JsonProperty public Boolean skipNodeAssignment;
-
-    @JsonProperty public Map<String, String> properties;
-
-    public static AddReplicaRequestBody fromV1Params(SolrParams params) {
-      final var requestBody = new AddReplicaRequestBody();
-
-      requestBody.name = params.get(NAME);
-      requestBody.type = params.get(REPLICA_TYPE);
-      requestBody.instanceDir = params.get(INSTANCE_DIR);
-      requestBody.dataDir = params.get(DATA_DIR);
-      requestBody.ulogDir = params.get(ULOG_DIR);
-      requestBody.route = params.get(_ROUTE_);
-      requestBody.nrtReplicas = params.getInt(NRT_REPLICAS);
-      requestBody.tlogReplicas = params.getInt(TLOG_REPLICAS);
-      requestBody.pullReplicas = params.getInt(PULL_REPLICAS);
-      requestBody.waitForFinalState = params.getBool(WAIT_FOR_FINAL_STATE);
-      requestBody.followAliases = params.getBool(FOLLOW_ALIASES);
-      requestBody.asyncId = params.get(ASYNC);
-
-      requestBody.node = params.get(NODE);
-      if (params.get(CREATE_NODE_SET_PARAM) != null) {
-        requestBody.nodeSet = Arrays.asList(params.get(CREATE_NODE_SET).split(","));
-      }
-      requestBody.skipNodeAssignment = params.getBool(SKIP_NODE_ASSIGNMENT);
+  public static CreateReplicaRequestBody createRequestBodyFromV1Params(SolrParams params) {
+    final var requestBody = new CreateReplicaRequestBody();
+
+    requestBody.name = params.get(NAME);
+    requestBody.type = params.get(REPLICA_TYPE);
+    requestBody.instanceDir = params.get(INSTANCE_DIR);
+    requestBody.dataDir = params.get(DATA_DIR);
+    requestBody.ulogDir = params.get(ULOG_DIR);
+    requestBody.route = params.get(_ROUTE_);
+    requestBody.nrtReplicas = params.getInt(NRT_REPLICAS);
+    requestBody.tlogReplicas = params.getInt(TLOG_REPLICAS);
+    requestBody.pullReplicas = params.getInt(PULL_REPLICAS);
+    requestBody.waitForFinalState = params.getBool(WAIT_FOR_FINAL_STATE);
+    requestBody.followAliases = params.getBool(FOLLOW_ALIASES);
+    requestBody.async = params.get(ASYNC);
+
+    requestBody.node = params.get(NODE);
+    if (params.get(CREATE_NODE_SET_PARAM) != null) {
+      requestBody.nodeSet = Arrays.asList(params.get(CREATE_NODE_SET).split(","));
+    }
+    requestBody.skipNodeAssignment = params.getBool(SKIP_NODE_ASSIGNMENT);
 
-      requestBody.properties =
-          copyPrefixedPropertiesWithoutPrefix(params, new HashMap<>(), PROPERTY_PREFIX);
+    requestBody.properties =
+        copyPrefixedPropertiesWithoutPrefix(params, new HashMap<>(), PROPERTY_PREFIX);
 
-      return requestBody;
-    }
+    return requestBody;
   }
 }
diff --git a/solr/core/src/test/org/apache/solr/handler/admin/api/CreateReplicaAPITest.java b/solr/core/src/test/org/apache/solr/handler/admin/api/CreateReplicaAPITest.java
index d4e9772e866..2abe5d13397 100644
--- a/solr/core/src/test/org/apache/solr/handler/admin/api/CreateReplicaAPITest.java
+++ b/solr/core/src/test/org/apache/solr/handler/admin/api/CreateReplicaAPITest.java
@@ -39,11 +39,12 @@ import static org.apache.solr.common.params.ShardParams._ROUTE_;
 import java.util.List;
 import java.util.Map;
 import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.client.api.model.CreateReplicaRequestBody;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.params.ModifiableSolrParams;
 import org.junit.Test;
 
-/** Unit tests for {@link CreateReplicaAPI} */
+/** Unit tests for {@link CreateReplica} */
 public class CreateReplicaAPITest extends SolrTestCaseJ4 {
   @Test
   public void testReportsErrorIfRequestBodyMissing() {
@@ -51,7 +52,7 @@ public class CreateReplicaAPITest extends SolrTestCaseJ4 {
         expectThrows(
             SolrException.class,
             () -> {
-              final var api = new CreateReplicaAPI(null, null, null);
+              final var api = new CreateReplica(null, null, null);
               api.createReplica("someCollName", "someShardName", null);
             });
 
@@ -61,12 +62,12 @@ public class CreateReplicaAPITest extends SolrTestCaseJ4 {
 
   @Test
   public void testReportsErrorIfCollectionNameMissing() {
-    final var requestBody = new CreateReplicaAPI.AddReplicaRequestBody();
+    final var requestBody = new CreateReplicaRequestBody();
     final SolrException thrown =
         expectThrows(
             SolrException.class,
             () -> {
-              final var api = new CreateReplicaAPI(null, null, null);
+              final var api = new CreateReplica(null, null, null);
               api.createReplica(null, "shardName", requestBody);
             });
 
@@ -76,12 +77,12 @@ public class CreateReplicaAPITest extends SolrTestCaseJ4 {
 
   @Test
   public void testReportsErrorIfShardNameMissing() {
-    final var requestBody = new CreateReplicaAPI.AddReplicaRequestBody();
+    final var requestBody = new CreateReplicaRequestBody();
     final SolrException thrown =
         expectThrows(
             SolrException.class,
             () -> {
-              final var api = new CreateReplicaAPI(null, null, null);
+              final var api = new CreateReplica(null, null, null);
               api.createReplica("someCollectionName", null, requestBody);
             });
 
@@ -91,7 +92,7 @@ public class CreateReplicaAPITest extends SolrTestCaseJ4 {
 
   @Test
   public void testCreateRemoteMessageAllProperties() {
-    final var requestBody = new CreateReplicaAPI.AddReplicaRequestBody();
+    final var requestBody = new CreateReplicaRequestBody();
     requestBody.name = "someName";
     requestBody.type = "NRT";
     requestBody.instanceDir = "/some/dir1";
@@ -106,11 +107,11 @@ public class CreateReplicaAPITest extends SolrTestCaseJ4 {
     requestBody.skipNodeAssignment = Boolean.TRUE;
     requestBody.waitForFinalState = true;
     requestBody.followAliases = true;
-    requestBody.asyncId = "someAsyncId";
+    requestBody.async = "someAsyncId";
     requestBody.properties = Map.of("propName1", "propVal1", "propName2", "propVal2");
 
     final var remoteMessage =
-        CreateReplicaAPI.createRemoteMessage("someCollectionName", "someShardName", requestBody)
+        CreateReplica.createRemoteMessage("someCollectionName", "someShardName", requestBody)
             .getProperties();
 
     assertEquals(20, remoteMessage.size());
@@ -159,7 +160,7 @@ public class CreateReplicaAPITest extends SolrTestCaseJ4 {
     v1Params.add("property.propName1", "propVal1");
     v1Params.add("property.propName2", "propVal2");
 
-    final var requestBody = CreateReplicaAPI.AddReplicaRequestBody.fromV1Params(v1Params);
+    final var requestBody = CreateReplica.createRequestBodyFromV1Params(v1Params);
 
     assertEquals("someName", requestBody.name);
     assertEquals("NRT", requestBody.type);
@@ -175,7 +176,7 @@ public class CreateReplicaAPITest extends SolrTestCaseJ4 {
     assertEquals(Boolean.TRUE, requestBody.skipNodeAssignment);
     assertEquals(Boolean.TRUE, requestBody.waitForFinalState);
     assertEquals(Boolean.TRUE, requestBody.followAliases);
-    assertEquals("someAsyncId", requestBody.asyncId);
+    assertEquals("someAsyncId", requestBody.async);
     assertEquals("propVal1", requestBody.properties.get("propName1"));
     assertEquals("propVal2", requestBody.properties.get("propName2"));
   }
diff --git a/solr/core/src/test/org/apache/solr/jersey/PostRequestLoggingFilterTest.java b/solr/core/src/test/org/apache/solr/jersey/PostRequestLoggingFilterTest.java
index c0770c4912e..985085b7829 100644
--- a/solr/core/src/test/org/apache/solr/jersey/PostRequestLoggingFilterTest.java
+++ b/solr/core/src/test/org/apache/solr/jersey/PostRequestLoggingFilterTest.java
@@ -26,7 +26,7 @@ import javax.ws.rs.container.ContainerRequestContext;
 import javax.ws.rs.core.MultivaluedHashMap;
 import javax.ws.rs.core.UriInfo;
 import org.apache.solr.SolrTestCaseJ4;
-import org.apache.solr.handler.admin.api.CreateReplicaAPI;
+import org.apache.solr.client.api.model.CreateReplicaRequestBody;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
@@ -122,10 +122,10 @@ public class PostRequestLoggingFilterTest extends SolrTestCaseJ4 {
 
   @Test
   public void testRequestBodyRepresentedAsJsonWhenFound() {
-    final var requestBody = new CreateReplicaAPI.AddReplicaRequestBody();
+    final var requestBody = new CreateReplicaRequestBody();
     requestBody.name = "someReplicaName";
     requestBody.type = "NRT";
-    requestBody.asyncId = "someAsyncId";
+    requestBody.async = "someAsyncId";
     final var mockContext = mock(ContainerRequestContext.class);
     when(mockContext.getProperty(DESERIALIZED_REQUEST_BODY_KEY)).thenReturn(requestBody);