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 f822d4d4859 SOLR-16393: Tweak paths of remaining 'POST /collections' 
APIs (#1571)
f822d4d4859 is described below

commit f822d4d48590284f2b65554e5161b510a8fb120c
Author: Jason Gerlowski <[email protected]>
AuthorDate: Sun Apr 16 13:48:20 2023 -0400

    SOLR-16393: Tweak paths of remaining 'POST /collections' APIs (#1571)
    
    Prior to this commit the v2 APIs for create-collection, create-alias,
    and restore-collection were all made available as separate "commands"
    under the "POST /collections" API.
    
    This commit changes these APIs to use more differentiated paths:
      - `POST /api/collections` for create-collection (no change)
      - `POST /api/aliases` for create-alias
      - `POST /api/backups/backupName/restore` for restore-collection
    
    This brings the APIs closer (but not fully) into line with their more
    REST-ful v2 forms, and allows us to make further API modifications and
    convert to JAX-RS individually.
    
    (V2 API calls are dispatched in such a way that the legacy and JAX-RS
    framework can never overlap or "share" any of the URL paths that they
    serve.  See #1453 for more context.)
---
 .../java/org/apache/solr/core/CoreContainer.java   |   4 -
 .../org/apache/solr/handler/CollectionsAPI.java    | 165 ---------------------
 .../solr/handler/admin/CollectionsHandler.java     |   6 +
 .../solr/handler/admin/api/CreateAliasAPI.java     |  79 ++++++++++
 .../handler/admin/api/CreateCollectionAPI.java     | 106 +++++++++++++
 .../handler/admin/api/RestoreCollectionAPI.java    |  68 +++++++++
 .../apache/solr/cloud/AliasIntegrationTest.java    |   2 +-
 .../apache/solr/cloud/CreateRoutedAliasTest.java   |   2 +-
 .../org/apache/solr/cloud/TestPullReplica.java     |   2 +-
 .../org/apache/solr/cloud/TestTlogReplica.java     |   2 +-
 .../solr/handler/admin/TestApiFramework.java       |   2 -
 .../solr/handler/admin/TestCollectionAPIs.java     |   6 +-
 .../handler/admin/V2CollectionsAPIMappingTest.java |  17 ++-
 .../request/beans/RestoreCollectionPayload.java    |   3 -
 14 files changed, 273 insertions(+), 191 deletions(-)

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 f13fd275349..6d843b3532b 100644
--- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java
+++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
@@ -109,7 +109,6 @@ import 
org.apache.solr.core.backup.repository.BackupRepositoryFactory;
 import org.apache.solr.filestore.PackageStoreAPI;
 import org.apache.solr.handler.ClusterAPI;
 import org.apache.solr.handler.CollectionBackupsAPI;
-import org.apache.solr.handler.CollectionsAPI;
 import org.apache.solr.handler.RequestHandlerBase;
 import org.apache.solr.handler.SnapShooter;
 import org.apache.solr.handler.admin.CollectionsHandler;
@@ -843,9 +842,6 @@ public class CoreContainer {
     collectionsHandler =
         createHandler(
             COLLECTIONS_HANDLER_PATH, cfg.getCollectionsHandlerClass(), 
CollectionsHandler.class);
-    final CollectionsAPI collectionsAPI = new 
CollectionsAPI(collectionsHandler);
-    registerV2ApiIfEnabled(collectionsAPI);
-    registerV2ApiIfEnabled(collectionsAPI.collectionsCommands);
     final CollectionBackupsAPI collectionBackupsAPI = new 
CollectionBackupsAPI(collectionsHandler);
     registerV2ApiIfEnabled(collectionBackupsAPI);
     configSetsHandler =
diff --git a/solr/core/src/java/org/apache/solr/handler/CollectionsAPI.java 
b/solr/core/src/java/org/apache/solr/handler/CollectionsAPI.java
deleted file mode 100644
index ac3c49d7a90..00000000000
--- a/solr/core/src/java/org/apache/solr/handler/CollectionsAPI.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * 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.handler;
-
-import static org.apache.solr.client.solrj.SolrRequest.METHOD.POST;
-import static 
org.apache.solr.client.solrj.request.beans.V2ApiConstants.ROUTER_KEY;
-import static 
org.apache.solr.cloud.api.collections.RoutedAlias.CREATE_COLLECTION_PREFIX;
-import static 
org.apache.solr.common.params.CollectionAdminParams.PROPERTY_PREFIX;
-import static 
org.apache.solr.common.params.CollectionAdminParams.ROUTER_PREFIX;
-import static org.apache.solr.common.params.CommonParams.ACTION;
-import static org.apache.solr.handler.ClusterAPI.wrapParams;
-import static org.apache.solr.handler.api.V2ApiUtils.flattenMapWithPrefix;
-import static 
org.apache.solr.security.PermissionNameProvider.Name.COLL_EDIT_PERM;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-import org.apache.solr.api.Command;
-import org.apache.solr.api.EndPoint;
-import org.apache.solr.api.PayloadObj;
-import org.apache.solr.client.solrj.request.beans.CreateAliasPayload;
-import org.apache.solr.client.solrj.request.beans.CreatePayload;
-import org.apache.solr.client.solrj.request.beans.RestoreCollectionPayload;
-import org.apache.solr.client.solrj.request.beans.V2ApiConstants;
-import org.apache.solr.common.params.CollectionAdminParams;
-import org.apache.solr.common.params.CollectionParams.CollectionAction;
-import org.apache.solr.handler.admin.CollectionsHandler;
-
-/** All V2 APIs for collection management */
-public class CollectionsAPI {
-
-  public static final String V2_CREATE_COLLECTION_CMD = "create";
-  public static final String V2_RESTORE_CMD = "restore-collection";
-  public static final String V2_CREATE_ALIAS_CMD = "create-alias";
-
-  private final CollectionsHandler collectionsHandler;
-
-  public final CollectionsCommands collectionsCommands = new 
CollectionsCommands();
-
-  public CollectionsAPI(CollectionsHandler collectionsHandler) {
-    this.collectionsHandler = collectionsHandler;
-  }
-
-  @EndPoint(
-      path = {"/c", "/collections"},
-      method = POST,
-      permission = COLL_EDIT_PERM)
-  public class CollectionsCommands {
-
-    @Command(name = V2_RESTORE_CMD)
-    @SuppressWarnings("unchecked")
-    public void restoreBackup(PayloadObj<RestoreCollectionPayload> obj) throws 
Exception {
-      final RestoreCollectionPayload v2Body = obj.get();
-      final Map<String, Object> v1Params = v2Body.toMap(new HashMap<>());
-
-      v1Params.put(ACTION, CollectionAction.RESTORE.toLower());
-      if (v2Body.createCollectionParams != null && 
!v2Body.createCollectionParams.isEmpty()) {
-        final Map<String, Object> createCollParams =
-            (Map<String, Object>) 
v1Params.remove(V2ApiConstants.CREATE_COLLECTION_KEY);
-        convertV2CreateCollectionMapToV1ParamMap(createCollParams);
-        v1Params.putAll(createCollParams);
-      }
-
-      collectionsHandler.handleRequestBody(
-          wrapParams(obj.getRequest(), v1Params), obj.getResponse());
-    }
-
-    @Command(name = V2_CREATE_ALIAS_CMD)
-    @SuppressWarnings("unchecked")
-    public void createAlias(PayloadObj<CreateAliasPayload> obj) throws 
Exception {
-      final CreateAliasPayload v2Body = obj.get();
-      final Map<String, Object> v1Params = v2Body.toMap(new HashMap<>());
-
-      v1Params.put(ACTION, CollectionAction.CREATEALIAS.toLower());
-      if (v2Body.collections != null && !v2Body.collections.isEmpty()) {
-        final String collectionsStr = String.join(",", v2Body.collections);
-        v1Params.remove(V2ApiConstants.COLLECTIONS);
-        v1Params.put(V2ApiConstants.COLLECTIONS, collectionsStr);
-      }
-      if (v2Body.router != null) {
-        Map<String, Object> routerProperties =
-            (Map<String, Object>) v1Params.remove(V2ApiConstants.ROUTER_KEY);
-        flattenMapWithPrefix(routerProperties, v1Params, ROUTER_PREFIX);
-      }
-      if (v2Body.createCollectionParams != null && 
!v2Body.createCollectionParams.isEmpty()) {
-        final Map<String, Object> createCollectionMap =
-            (Map<String, Object>) 
v1Params.remove(V2ApiConstants.CREATE_COLLECTION_KEY);
-        convertV2CreateCollectionMapToV1ParamMap(createCollectionMap);
-        flattenMapWithPrefix(createCollectionMap, v1Params, 
CREATE_COLLECTION_PREFIX);
-      }
-
-      collectionsHandler.handleRequestBody(
-          wrapParams(obj.getRequest(), v1Params), obj.getResponse());
-    }
-
-    @Command(name = V2_CREATE_COLLECTION_CMD)
-    public void create(PayloadObj<CreatePayload> obj) throws Exception {
-      final CreatePayload v2Body = obj.get();
-      final Map<String, Object> v1Params = v2Body.toMap(new HashMap<>());
-
-      v1Params.put(ACTION, CollectionAction.CREATE.toLower());
-      convertV2CreateCollectionMapToV1ParamMap(v1Params);
-
-      collectionsHandler.handleRequestBody(
-          wrapParams(obj.getRequest(), v1Params), obj.getResponse());
-    }
-
-    @SuppressWarnings("unchecked")
-    private void convertV2CreateCollectionMapToV1ParamMap(Map<String, Object> 
v2MapVals) {
-      // Keys are copied so that map can be modified as keys are looped 
through.
-      final Set<String> v2Keys = 
v2MapVals.keySet().stream().collect(Collectors.toSet());
-      for (String key : v2Keys) {
-        switch (key) {
-          case V2ApiConstants.PROPERTIES_KEY:
-            final Map<String, Object> propertiesMap =
-                (Map<String, Object>) 
v2MapVals.remove(V2ApiConstants.PROPERTIES_KEY);
-            flattenMapWithPrefix(propertiesMap, v2MapVals, PROPERTY_PREFIX);
-            break;
-          case ROUTER_KEY:
-            final Map<String, Object> routerProperties =
-                (Map<String, Object>) 
v2MapVals.remove(V2ApiConstants.ROUTER_KEY);
-            flattenMapWithPrefix(routerProperties, v2MapVals, 
CollectionAdminParams.ROUTER_PREFIX);
-            break;
-          case V2ApiConstants.CONFIG:
-            v2MapVals.put(CollectionAdminParams.COLL_CONF, 
v2MapVals.remove(V2ApiConstants.CONFIG));
-            break;
-          case V2ApiConstants.SHUFFLE_NODES:
-            v2MapVals.put(
-                CollectionAdminParams.CREATE_NODE_SET_SHUFFLE_PARAM,
-                v2MapVals.remove(V2ApiConstants.SHUFFLE_NODES));
-            break;
-          case V2ApiConstants.NODE_SET:
-            final Object nodeSetValUncast = 
v2MapVals.remove(V2ApiConstants.NODE_SET);
-            if (nodeSetValUncast instanceof String) {
-              v2MapVals.put(CollectionAdminParams.CREATE_NODE_SET_PARAM, 
nodeSetValUncast);
-            } else {
-              final List<String> nodeSetList = (List<String>) nodeSetValUncast;
-              final String nodeSetStr = String.join(",", nodeSetList);
-              v2MapVals.put(CollectionAdminParams.CREATE_NODE_SET_PARAM, 
nodeSetStr);
-            }
-            break;
-          default:
-            break;
-        }
-      }
-    }
-  }
-}
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 0c302779e5f..f4e121db01b 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
@@ -211,6 +211,8 @@ import org.apache.solr.handler.admin.api.AliasPropertyAPI;
 import org.apache.solr.handler.admin.api.BalanceShardUniqueAPI;
 import org.apache.solr.handler.admin.api.CollectionPropertyAPI;
 import org.apache.solr.handler.admin.api.CollectionStatusAPI;
+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.CreateShardAPI;
 import org.apache.solr.handler.admin.api.DeleteAliasAPI;
@@ -230,6 +232,7 @@ 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.RestoreCollectionAPI;
 import org.apache.solr.handler.admin.api.SplitShardAPI;
 import org.apache.solr.handler.admin.api.SyncShardAPI;
 import org.apache.solr.handler.api.V2ApiUtils;
@@ -2047,6 +2050,9 @@ public class CollectionsHandler extends 
RequestHandlerBase implements Permission
   @Override
   public Collection<Api> getApis() {
     final List<Api> apis = new ArrayList<>();
+    apis.addAll(AnnotatedApi.getApis(new CreateCollectionAPI(this)));
+    apis.addAll(AnnotatedApi.getApis(new CreateAliasAPI(this)));
+    apis.addAll(AnnotatedApi.getApis(new RestoreCollectionAPI(this)));
     apis.addAll(AnnotatedApi.getApis(new SplitShardAPI(this)));
     apis.addAll(AnnotatedApi.getApis(new CreateShardAPI(this)));
     apis.addAll(AnnotatedApi.getApis(new AddReplicaAPI(this)));
diff --git 
a/solr/core/src/java/org/apache/solr/handler/admin/api/CreateAliasAPI.java 
b/solr/core/src/java/org/apache/solr/handler/admin/api/CreateAliasAPI.java
new file mode 100644
index 00000000000..ba7e2e5393a
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/handler/admin/api/CreateAliasAPI.java
@@ -0,0 +1,79 @@
+/*
+ * 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.handler.admin.api;
+
+import static org.apache.solr.client.solrj.SolrRequest.METHOD.POST;
+import static 
org.apache.solr.cloud.api.collections.RoutedAlias.CREATE_COLLECTION_PREFIX;
+import static 
org.apache.solr.common.params.CollectionAdminParams.ROUTER_PREFIX;
+import static org.apache.solr.common.params.CommonParams.ACTION;
+import static org.apache.solr.handler.ClusterAPI.wrapParams;
+import static 
org.apache.solr.handler.admin.api.CreateCollectionAPI.convertV2CreateCollectionMapToV1ParamMap;
+import static org.apache.solr.handler.api.V2ApiUtils.flattenMapWithPrefix;
+import static 
org.apache.solr.security.PermissionNameProvider.Name.COLL_EDIT_PERM;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.solr.api.Command;
+import org.apache.solr.api.EndPoint;
+import org.apache.solr.api.PayloadObj;
+import org.apache.solr.client.solrj.request.beans.CreateAliasPayload;
+import org.apache.solr.client.solrj.request.beans.V2ApiConstants;
+import org.apache.solr.common.params.CollectionParams;
+import org.apache.solr.handler.admin.CollectionsHandler;
+
+@EndPoint(
+    path = {"/aliases"},
+    method = POST,
+    permission = COLL_EDIT_PERM)
+public class CreateAliasAPI {
+
+  public static final String V2_CREATE_ALIAS_CMD = "create-alias";
+
+  private final CollectionsHandler collectionsHandler;
+
+  public CreateAliasAPI(CollectionsHandler collectionsHandler) {
+    this.collectionsHandler = collectionsHandler;
+  }
+
+  @Command(name = V2_CREATE_ALIAS_CMD)
+  @SuppressWarnings("unchecked")
+  public void createAlias(PayloadObj<CreateAliasPayload> obj) throws Exception 
{
+    final CreateAliasPayload v2Body = obj.get();
+    final Map<String, Object> v1Params = v2Body.toMap(new HashMap<>());
+
+    v1Params.put(ACTION, 
CollectionParams.CollectionAction.CREATEALIAS.toLower());
+    if (v2Body.collections != null && !v2Body.collections.isEmpty()) {
+      final String collectionsStr = String.join(",", v2Body.collections);
+      v1Params.remove(V2ApiConstants.COLLECTIONS);
+      v1Params.put(V2ApiConstants.COLLECTIONS, collectionsStr);
+    }
+    if (v2Body.router != null) {
+      Map<String, Object> routerProperties =
+          (Map<String, Object>) v1Params.remove(V2ApiConstants.ROUTER_KEY);
+      flattenMapWithPrefix(routerProperties, v1Params, ROUTER_PREFIX);
+    }
+    if (v2Body.createCollectionParams != null && 
!v2Body.createCollectionParams.isEmpty()) {
+      final Map<String, Object> createCollectionMap =
+          (Map<String, Object>) 
v1Params.remove(V2ApiConstants.CREATE_COLLECTION_KEY);
+      convertV2CreateCollectionMapToV1ParamMap(createCollectionMap);
+      flattenMapWithPrefix(createCollectionMap, v1Params, 
CREATE_COLLECTION_PREFIX);
+    }
+
+    collectionsHandler.handleRequestBody(wrapParams(obj.getRequest(), 
v1Params), obj.getResponse());
+  }
+}
diff --git 
a/solr/core/src/java/org/apache/solr/handler/admin/api/CreateCollectionAPI.java 
b/solr/core/src/java/org/apache/solr/handler/admin/api/CreateCollectionAPI.java
new file mode 100644
index 00000000000..3ba329a47c0
--- /dev/null
+++ 
b/solr/core/src/java/org/apache/solr/handler/admin/api/CreateCollectionAPI.java
@@ -0,0 +1,106 @@
+/*
+ * 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.handler.admin.api;
+
+import static org.apache.solr.client.solrj.SolrRequest.METHOD.POST;
+import static 
org.apache.solr.client.solrj.request.beans.V2ApiConstants.ROUTER_KEY;
+import static 
org.apache.solr.common.params.CollectionAdminParams.PROPERTY_PREFIX;
+import static org.apache.solr.common.params.CommonParams.ACTION;
+import static org.apache.solr.handler.ClusterAPI.wrapParams;
+import static org.apache.solr.handler.api.V2ApiUtils.flattenMapWithPrefix;
+import static 
org.apache.solr.security.PermissionNameProvider.Name.COLL_EDIT_PERM;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.apache.solr.api.Command;
+import org.apache.solr.api.EndPoint;
+import org.apache.solr.api.PayloadObj;
+import org.apache.solr.client.solrj.request.beans.CreatePayload;
+import org.apache.solr.client.solrj.request.beans.V2ApiConstants;
+import org.apache.solr.common.params.CollectionAdminParams;
+import org.apache.solr.common.params.CollectionParams;
+import org.apache.solr.handler.admin.CollectionsHandler;
+
+@EndPoint(
+    path = {"/collections"},
+    method = POST,
+    permission = COLL_EDIT_PERM)
+public class CreateCollectionAPI {
+
+  public static final String V2_CREATE_COLLECTION_CMD = "create";
+
+  private final CollectionsHandler collectionsHandler;
+
+  public CreateCollectionAPI(CollectionsHandler collectionsHandler) {
+    this.collectionsHandler = collectionsHandler;
+  }
+
+  @Command(name = V2_CREATE_COLLECTION_CMD)
+  public void create(PayloadObj<CreatePayload> obj) throws Exception {
+    final CreatePayload v2Body = obj.get();
+    final Map<String, Object> v1Params = v2Body.toMap(new HashMap<>());
+
+    v1Params.put(ACTION, CollectionParams.CollectionAction.CREATE.toLower());
+    convertV2CreateCollectionMapToV1ParamMap(v1Params);
+
+    collectionsHandler.handleRequestBody(wrapParams(obj.getRequest(), 
v1Params), obj.getResponse());
+  }
+
+  @SuppressWarnings("unchecked")
+  public static void convertV2CreateCollectionMapToV1ParamMap(Map<String, 
Object> v2MapVals) {
+    // Keys are copied so that map can be modified as keys are looped through.
+    final Set<String> v2Keys = 
v2MapVals.keySet().stream().collect(Collectors.toSet());
+    for (String key : v2Keys) {
+      switch (key) {
+        case V2ApiConstants.PROPERTIES_KEY:
+          final Map<String, Object> propertiesMap =
+              (Map<String, Object>) 
v2MapVals.remove(V2ApiConstants.PROPERTIES_KEY);
+          flattenMapWithPrefix(propertiesMap, v2MapVals, PROPERTY_PREFIX);
+          break;
+        case ROUTER_KEY:
+          final Map<String, Object> routerProperties =
+              (Map<String, Object>) 
v2MapVals.remove(V2ApiConstants.ROUTER_KEY);
+          flattenMapWithPrefix(routerProperties, v2MapVals, 
CollectionAdminParams.ROUTER_PREFIX);
+          break;
+        case V2ApiConstants.CONFIG:
+          v2MapVals.put(CollectionAdminParams.COLL_CONF, 
v2MapVals.remove(V2ApiConstants.CONFIG));
+          break;
+        case V2ApiConstants.SHUFFLE_NODES:
+          v2MapVals.put(
+              CollectionAdminParams.CREATE_NODE_SET_SHUFFLE_PARAM,
+              v2MapVals.remove(V2ApiConstants.SHUFFLE_NODES));
+          break;
+        case V2ApiConstants.NODE_SET:
+          final Object nodeSetValUncast = 
v2MapVals.remove(V2ApiConstants.NODE_SET);
+          if (nodeSetValUncast instanceof String) {
+            v2MapVals.put(CollectionAdminParams.CREATE_NODE_SET_PARAM, 
nodeSetValUncast);
+          } else {
+            final List<String> nodeSetList = (List<String>) nodeSetValUncast;
+            final String nodeSetStr = String.join(",", nodeSetList);
+            v2MapVals.put(CollectionAdminParams.CREATE_NODE_SET_PARAM, 
nodeSetStr);
+          }
+          break;
+        default:
+          break;
+      }
+    }
+  }
+}
diff --git 
a/solr/core/src/java/org/apache/solr/handler/admin/api/RestoreCollectionAPI.java
 
b/solr/core/src/java/org/apache/solr/handler/admin/api/RestoreCollectionAPI.java
new file mode 100644
index 00000000000..bbbd0304b12
--- /dev/null
+++ 
b/solr/core/src/java/org/apache/solr/handler/admin/api/RestoreCollectionAPI.java
@@ -0,0 +1,68 @@
+/*
+ * 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.handler.admin.api;
+
+import static org.apache.solr.client.solrj.SolrRequest.METHOD.POST;
+import static org.apache.solr.common.params.CommonParams.ACTION;
+import static org.apache.solr.common.params.CommonParams.NAME;
+import static org.apache.solr.handler.ClusterAPI.wrapParams;
+import static 
org.apache.solr.handler.admin.api.CreateCollectionAPI.convertV2CreateCollectionMapToV1ParamMap;
+import static 
org.apache.solr.security.PermissionNameProvider.Name.COLL_EDIT_PERM;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.solr.api.Command;
+import org.apache.solr.api.EndPoint;
+import org.apache.solr.api.PayloadObj;
+import org.apache.solr.client.solrj.request.beans.RestoreCollectionPayload;
+import org.apache.solr.client.solrj.request.beans.V2ApiConstants;
+import org.apache.solr.common.params.CollectionParams;
+import org.apache.solr.handler.admin.CollectionsHandler;
+
+@EndPoint(
+    path = {"/backups/{backupName}"},
+    method = POST,
+    permission = COLL_EDIT_PERM)
+public class RestoreCollectionAPI {
+
+  public static final String V2_RESTORE_CMD = "restore-collection";
+
+  private final CollectionsHandler collectionsHandler;
+
+  public RestoreCollectionAPI(CollectionsHandler collectionsHandler) {
+    this.collectionsHandler = collectionsHandler;
+  }
+
+  @Command(name = V2_RESTORE_CMD)
+  @SuppressWarnings("unchecked")
+  public void restoreBackup(PayloadObj<RestoreCollectionPayload> obj) throws 
Exception {
+    final RestoreCollectionPayload v2Body = obj.get();
+    final Map<String, Object> v1Params = v2Body.toMap(new HashMap<>());
+
+    v1Params.put(ACTION, CollectionParams.CollectionAction.RESTORE.toLower());
+    v1Params.put(NAME, 
obj.getRequest().getPathTemplateValues().get("backupName"));
+    if (v2Body.createCollectionParams != null && 
!v2Body.createCollectionParams.isEmpty()) {
+      final Map<String, Object> createCollParams =
+          (Map<String, Object>) 
v1Params.remove(V2ApiConstants.CREATE_COLLECTION_KEY);
+      convertV2CreateCollectionMapToV1ParamMap(createCollParams);
+      v1Params.putAll(createCollParams);
+    }
+
+    collectionsHandler.handleRequestBody(wrapParams(obj.getRequest(), 
v1Params), obj.getResponse());
+  }
+}
diff --git a/solr/core/src/test/org/apache/solr/cloud/AliasIntegrationTest.java 
b/solr/core/src/test/org/apache/solr/cloud/AliasIntegrationTest.java
index f59c72a3392..3f55ee17f64 100644
--- a/solr/core/src/test/org/apache/solr/cloud/AliasIntegrationTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/AliasIntegrationTest.java
@@ -889,7 +889,7 @@ public class AliasIntegrationTest extends SolrCloudTestCase 
{
 
     ///////////////
     // use v2 API
-    new V2Request.Builder("/collections")
+    new V2Request.Builder("/aliases")
         .withMethod(SolrRequest.METHOD.POST)
         .withPayload(
             "{\"create-alias\": {\"name\": \"testalias6\", 
collections:[\"collection2\",\"collection1\"]}}")
diff --git 
a/solr/core/src/test/org/apache/solr/cloud/CreateRoutedAliasTest.java 
b/solr/core/src/test/org/apache/solr/cloud/CreateRoutedAliasTest.java
index 129efec3deb..43c66daff9e 100644
--- a/solr/core/src/test/org/apache/solr/cloud/CreateRoutedAliasTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/CreateRoutedAliasTest.java
@@ -90,7 +90,7 @@ public class CreateRoutedAliasTest extends SolrCloudTestCase {
 
     final String baseUrl = 
cluster.getRandomJetty(random()).getBaseUrl().toString();
     // TODO fix Solr test infra so that this /____v2/ becomes /api/
-    HttpPost post = new HttpPost(baseUrl + "/____v2/c");
+    HttpPost post = new HttpPost(baseUrl + "/____v2/aliases");
     post.setEntity(
         new StringEntity(
             "{\n"
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestPullReplica.java 
b/solr/core/src/test/org/apache/solr/cloud/TestPullReplica.java
index 6b5da5ea181..edbbf941057 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestPullReplica.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestPullReplica.java
@@ -152,7 +152,7 @@ public class TestPullReplica extends SolrCloudTestCase {
           break;
         case 2:
           // Sometimes use V2 API
-          url = cluster.getRandomJetty(random()).getBaseUrl().toString() + 
"/____v2/c";
+          url = cluster.getRandomJetty(random()).getBaseUrl().toString() + 
"/____v2/collections";
           String requestBody =
               String.format(
                   Locale.ROOT,
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestTlogReplica.java 
b/solr/core/src/test/org/apache/solr/cloud/TestTlogReplica.java
index 39a8130903d..a51b0182cb8 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestTlogReplica.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestTlogReplica.java
@@ -178,7 +178,7 @@ public class TestTlogReplica extends SolrCloudTestCase {
         break;
       case 2:
         // Sometimes use V2 API
-        url = cluster.getRandomJetty(random()).getBaseUrl().toString() + 
"/____v2/c";
+        url = cluster.getRandomJetty(random()).getBaseUrl().toString() + 
"/____v2/collections";
         String requestBody =
             String.format(
                 Locale.ROOT,
diff --git 
a/solr/core/src/test/org/apache/solr/handler/admin/TestApiFramework.java 
b/solr/core/src/test/org/apache/solr/handler/admin/TestApiFramework.java
index af2a4e0c590..984346553e7 100644
--- a/solr/core/src/test/org/apache/solr/handler/admin/TestApiFramework.java
+++ b/solr/core/src/test/org/apache/solr/handler/admin/TestApiFramework.java
@@ -57,7 +57,6 @@ import org.apache.solr.common.util.Utils;
 import org.apache.solr.common.util.ValidatingJsonMap;
 import org.apache.solr.core.CoreContainer;
 import org.apache.solr.core.PluginBag;
-import org.apache.solr.handler.CollectionsAPI;
 import org.apache.solr.handler.PingRequestHandler;
 import org.apache.solr.handler.SchemaHandler;
 import org.apache.solr.handler.SolrConfigHandler;
@@ -79,7 +78,6 @@ public class TestApiFramework extends SolrTestCaseJ4 {
     TestCollectionAPIs.MockCollectionsHandler collectionsHandler =
         new TestCollectionAPIs.MockCollectionsHandler();
     containerHandlers.put(COLLECTIONS_HANDLER_PATH, collectionsHandler);
-    containerHandlers.getApiBag().registerObject(new 
CollectionsAPI(collectionsHandler));
     for (Api api : collectionsHandler.getApis()) {
       containerHandlers.getApiBag().register(api);
     }
diff --git 
a/solr/core/src/test/org/apache/solr/handler/admin/TestCollectionAPIs.java 
b/solr/core/src/test/org/apache/solr/handler/admin/TestCollectionAPIs.java
index 35847701431..d00e8e69bd1 100644
--- a/solr/core/src/test/org/apache/solr/handler/admin/TestCollectionAPIs.java
+++ b/solr/core/src/test/org/apache/solr/handler/admin/TestCollectionAPIs.java
@@ -46,7 +46,6 @@ import org.apache.solr.common.util.Pair;
 import org.apache.solr.common.util.Utils;
 import org.apache.solr.core.CoreContainer;
 import org.apache.solr.handler.ClusterAPI;
-import org.apache.solr.handler.CollectionsAPI;
 import org.apache.solr.request.LocalSolrQueryRequest;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.response.SolrQueryResponse;
@@ -81,9 +80,6 @@ public class TestCollectionAPIs extends SolrTestCaseJ4 {
     ApiBag apiBag;
     try (MockCollectionsHandler collectionsHandler = new 
MockCollectionsHandler()) {
       apiBag = new ApiBag(false);
-      final CollectionsAPI collectionsAPI = new 
CollectionsAPI(collectionsHandler);
-      apiBag.registerObject(new CollectionsAPI(collectionsHandler));
-      apiBag.registerObject(collectionsAPI.collectionsCommands);
       for (Api api : collectionsHandler.getApis()) {
         apiBag.register(api);
       }
@@ -124,7 +120,7 @@ public class TestCollectionAPIs extends SolrTestCaseJ4 {
 
     compareOutput(
         apiBag,
-        "/collections",
+        "/aliases",
         POST,
         "{create-alias:{name: aliasName , collections:[c1,c2] }}",
         "{operation : createalias, name: aliasName, collections:\"c1,c2\" }");
diff --git 
a/solr/core/src/test/org/apache/solr/handler/admin/V2CollectionsAPIMappingTest.java
 
b/solr/core/src/test/org/apache/solr/handler/admin/V2CollectionsAPIMappingTest.java
index 439ec2b567f..68ca362ee05 100644
--- 
a/solr/core/src/test/org/apache/solr/handler/admin/V2CollectionsAPIMappingTest.java
+++ 
b/solr/core/src/test/org/apache/solr/handler/admin/V2CollectionsAPIMappingTest.java
@@ -31,11 +31,13 @@ import org.apache.solr.common.params.CoreAdminParams;
 import org.apache.solr.common.params.ShardParams;
 import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.core.backup.BackupManager;
-import org.apache.solr.handler.CollectionsAPI;
+import org.apache.solr.handler.admin.api.CreateAliasAPI;
+import org.apache.solr.handler.admin.api.CreateCollectionAPI;
+import org.apache.solr.handler.admin.api.RestoreCollectionAPI;
 import org.junit.Test;
 
 /**
- * Unit tests for the API mappings found in {@link 
org.apache.solr.handler.CollectionsAPI}.
+ * Unit tests for the "create collection", "create alias" and "restore 
collection" v2 APIs.
  *
  * <p>This test bears many similarities to {@link TestCollectionAPIs} which 
appears to test the
  * mappings indirectly by checking message sent to the ZK overseer (which is 
similar, but not
@@ -52,9 +54,9 @@ public class V2CollectionsAPIMappingTest extends 
V2ApiMappingTest<CollectionsHan
 
   @Override
   public void populateApiBag() {
-    final CollectionsAPI collectionsAPI = new 
CollectionsAPI(getRequestHandler());
-    apiBag.registerObject(collectionsAPI);
-    apiBag.registerObject(collectionsAPI.collectionsCommands);
+    apiBag.registerObject(new CreateCollectionAPI(getRequestHandler()));
+    apiBag.registerObject(new CreateAliasAPI(getRequestHandler()));
+    apiBag.registerObject(new RestoreCollectionAPI(getRequestHandler()));
   }
 
   @Override
@@ -117,7 +119,7 @@ public class V2CollectionsAPIMappingTest extends 
V2ApiMappingTest<CollectionsHan
   public void testCreateAliasAllProperties() throws Exception {
     final SolrParams v1Params =
         captureConvertedV1Params(
-            "/collections",
+            "/aliases",
             "POST",
             "{'create-alias': {"
                 + "'name': 'aliasName', "
@@ -179,10 +181,9 @@ public class V2CollectionsAPIMappingTest extends 
V2ApiMappingTest<CollectionsHan
   public void testRestoreAllProperties() throws Exception {
     final SolrParams v1Params =
         captureConvertedV1Params(
-            "/collections",
+            "/backups/backupName",
             "POST",
             "{'restore-collection': {"
-                + "'name': 'backupName', "
                 + "'collection': 'collectionName', "
                 + "'location': '/some/location/uri', "
                 + "'repository': 'someRepository', "
diff --git 
a/solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/RestoreCollectionPayload.java
 
b/solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/RestoreCollectionPayload.java
index d44a283c7f2..2f68135dee1 100644
--- 
a/solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/RestoreCollectionPayload.java
+++ 
b/solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/RestoreCollectionPayload.java
@@ -32,9 +32,6 @@ public class RestoreCollectionPayload implements 
ReflectMapWriter {
   @JsonProperty(required = true)
   public String collection;
 
-  @JsonProperty(required = true)
-  public String name;
-
   @JsonProperty public String location;
 
   @JsonProperty public String repository;


Reply via email to