You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by no...@apache.org on 2016/02/11 22:11:09 UTC

[3/3] lucene-solr git commit: SOLR-8029 renamed class/dirs and removed the 'v2' part

SOLR-8029 renamed class/dirs and removed the 'v2' part


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/3cfebd53
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/3cfebd53
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/3cfebd53

Branch: refs/heads/apiv2
Commit: 3cfebd53f66198ec1d738452a688ad4f67dc8436
Parents: 292fe4a
Author: Noble Paul <no...@gmail.com>
Authored: Thu Feb 11 13:10:44 2016 -0800
Committer: Noble Paul <no...@gmail.com>
Committed: Thu Feb 11 13:10:44 2016 -0800

----------------------------------------------------------------------
 .../org/apache/solr/core/ImplicitPlugins.java   |   4 +-
 .../java/org/apache/solr/core/PluginBag.java    |  12 +-
 .../apache/solr/handler/RequestHandlerBase.java |  10 +-
 .../org/apache/solr/handler/SchemaHandler.java  |  10 +-
 .../apache/solr/handler/SolrConfigHandler.java  |  10 +-
 .../solr/handler/UpdateRequestHandlerApi.java   |  68 +++++
 .../solr/handler/V2UpdateRequestHandler.java    |  70 ------
 .../handler/admin/BaseHandlerApiSupport.java    | 204 +++++++++++++++
 .../handler/admin/CollectionHandlerApi.java     | 248 ++++++++++++++++++
 .../solr/handler/admin/CollectionsHandler.java  |  14 +-
 .../solr/handler/admin/CoreAdminHandler.java    |  19 +-
 .../solr/handler/admin/CoreAdminHandlerApi.java | 170 +++++++++++++
 .../apache/solr/handler/admin/InfoHandler.java  |  12 +-
 .../solr/handler/admin/SecurityConfHandler.java |  11 +-
 .../solr/handler/admin/V2BaseHandler.java       | 207 ---------------
 .../solr/handler/admin/V2CollectionHandler.java | 252 -------------------
 .../solr/handler/admin/V2CoreAdminHandler.java  | 173 -------------
 .../src/java/org/apache/solr/v2api/Api.java     |  38 +++
 .../src/java/org/apache/solr/v2api/ApiBag.java  |  35 ++-
 .../java/org/apache/solr/v2api/ApiSupport.java  |  30 +++
 .../src/java/org/apache/solr/v2api/V2Api.java   |  39 ---
 .../org/apache/solr/v2api/V2ApiSupport.java     |  33 ---
 .../java/org/apache/solr/v2api/V2HttpCall.java  |  24 +-
 solr/core/src/resources/apispec/cluster.json    |  17 ++
 .../apispec/cluster.security.BasicAuth.json     |  25 ++
 ...cluster.security.RuleBasedAuthorization.json |  56 +++++
 .../cluster.security.authentication.json        |  15 ++
 .../apispec/cluster.security.authorization.json |  15 ++
 .../resources/apispec/collections.Commands.json |  82 ++++++
 .../collections.collection.Commands.json        |  19 ++
 .../collections.collection.Commands.modify.json |   6 +
 .../collections.collection.Commands.reload.json |   3 +
 .../collections.collection.shards.Commands.json |  21 ++
 ...ctions.collection.shards.shard.Commands.json |  28 +++
 ...ollection.shards.shard.replica.Commands.json |  20 ++
 ....collection.shards.shard.replica.delete.json |  23 ++
 .../src/resources/apispec/core.ConfigEdit.json  | 115 +++++++++
 .../src/resources/apispec/core.ConfigRead.json  |  19 ++
 .../src/resources/apispec/core.RealtimeGet.json |  23 ++
 .../apispec/core.SchemaEdit.addCopyField.json   |   4 +
 .../core.SchemaEdit.addDynamicField.json        |   3 +
 .../apispec/core.SchemaEdit.addField.json       |   4 +
 .../apispec/core.SchemaEdit.addFieldType.json   |   4 +
 .../core.SchemaEdit.deleteCopyField.json        |   4 +
 .../core.SchemaEdit.deleteDynamicField.json     |   3 +
 .../apispec/core.SchemaEdit.deleteField.json    |   3 +
 .../core.SchemaEdit.deleteFieldType.json        |   3 +
 .../src/resources/apispec/core.SchemaEdit.json  |  22 ++
 .../core.SchemaEdit.replaceDynamicField.json    |   3 +
 .../apispec/core.SchemaEdit.replaceField.json   |   4 +
 .../core.SchemaEdit.replaceFieldType.json       |   3 +
 .../apispec/core.SchemaRead.copyFields.json     |  23 ++
 .../apispec/core.SchemaRead.fields.json         |  31 +++
 .../src/resources/apispec/core.SchemaRead.json  |  25 ++
 .../core/src/resources/apispec/core.Update.json |  19 ++
 .../src/resources/apispec/cores.Commands.json   |  67 +++++
 .../src/resources/apispec/cores.Status.json     |  23 ++
 .../resources/apispec/cores.core.Commands.json  |  36 +++
 .../cores.core.Commands.requestRecovery.json    |   4 +
 .../apispec/cores.core.Commands.split.json      |   3 +
 solr/core/src/resources/apispec/cores.json      |  22 ++
 solr/core/src/resources/apispec/emptySpec.json  |  15 ++
 solr/core/src/resources/apispec/node.Info.json  |  14 ++
 solr/core/src/resources/v2apispec/cluster.json  |  17 --
 .../v2apispec/cluster.security.BasicAuth.json   |  25 --
 ...cluster.security.RuleBasedAuthorization.json |  56 -----
 .../cluster.security.authentication.json        |  15 --
 .../cluster.security.authorization.json         |  15 --
 .../v2apispec/collections.Commands.json         |  82 ------
 .../collections.collection.Commands.json        |  19 --
 .../collections.collection.Commands.modify.json |   6 -
 .../collections.collection.Commands.reload.json |   3 -
 .../collections.collection.shards.Commands.json |  21 --
 ...ctions.collection.shards.shard.Commands.json |  28 ---
 ...ollection.shards.shard.replica.Commands.json |  20 --
 ....collection.shards.shard.replica.delete.json |  23 --
 .../resources/v2apispec/core.ConfigEdit.json    | 115 ---------
 .../resources/v2apispec/core.ConfigRead.json    |  19 --
 .../resources/v2apispec/core.RealtimeGet.json   |  23 --
 .../v2apispec/core.SchemaEdit.addCopyField.json |   4 -
 .../core.SchemaEdit.addDynamicField.json        |   3 -
 .../v2apispec/core.SchemaEdit.addField.json     |   4 -
 .../v2apispec/core.SchemaEdit.addFieldType.json |   4 -
 .../core.SchemaEdit.deleteCopyField.json        |   4 -
 .../core.SchemaEdit.deleteDynamicField.json     |   3 -
 .../v2apispec/core.SchemaEdit.deleteField.json  |   3 -
 .../core.SchemaEdit.deleteFieldType.json        |   3 -
 .../resources/v2apispec/core.SchemaEdit.json    |  22 --
 .../core.SchemaEdit.replaceDynamicField.json    |   3 -
 .../v2apispec/core.SchemaEdit.replaceField.json |   4 -
 .../core.SchemaEdit.replaceFieldType.json       |   3 -
 .../v2apispec/core.SchemaRead.copyFields.json   |  23 --
 .../v2apispec/core.SchemaRead.fields.json       |  31 ---
 .../resources/v2apispec/core.SchemaRead.json    |  25 --
 .../src/resources/v2apispec/core.Update.json    |  19 --
 .../src/resources/v2apispec/cores.Commands.json |  67 -----
 .../src/resources/v2apispec/cores.Status.json   |  23 --
 .../v2apispec/cores.core.Commands.json          |  36 ---
 .../cores.core.Commands.requestRecovery.json    |   4 -
 .../v2apispec/cores.core.Commands.split.json    |   3 -
 solr/core/src/resources/v2apispec/cores.json    |  22 --
 .../core/src/resources/v2apispec/emptySpec.json |  15 --
 .../core/src/resources/v2apispec/node.Info.json |  14 --
 .../solr/handler/admin/TestApiFramework.java    | 184 ++++++++++++++
 .../solr/handler/admin/TestCollectionAPIs.java  | 153 +++++++++++
 .../solr/handler/admin/TestCoreAdminApis.java   | 102 ++++++++
 .../handler/admin/TestV2CollectionAPIs.java     | 160 ------------
 .../solr/handler/admin/TestV2CoreAdminAPIs.java | 104 --------
 .../solr/handler/admin/TestV2Framework.java     | 187 --------------
 109 files changed, 2100 insertions(+), 2141 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3cfebd53/solr/core/src/java/org/apache/solr/core/ImplicitPlugins.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/core/ImplicitPlugins.java b/solr/core/src/java/org/apache/solr/core/ImplicitPlugins.java
index 627e5d1..d1b44f0 100644
--- a/solr/core/src/java/org/apache/solr/core/ImplicitPlugins.java
+++ b/solr/core/src/java/org/apache/solr/core/ImplicitPlugins.java
@@ -34,7 +34,7 @@ import org.apache.solr.handler.SchemaHandler;
 import org.apache.solr.handler.SolrConfigHandler;
 import org.apache.solr.handler.StreamHandler;
 import org.apache.solr.handler.UpdateRequestHandler;
-import org.apache.solr.handler.V2UpdateRequestHandler;
+import org.apache.solr.handler.UpdateRequestHandlerApi;
 import org.apache.solr.handler.admin.LoggingHandler;
 import org.apache.solr.handler.admin.LukeRequestHandler;
 import org.apache.solr.handler.admin.PluginInfoHandler;
@@ -67,7 +67,7 @@ public class ImplicitPlugins {
     implicits.add(createPluginInfoWithDefaults(UpdateRequestHandler.CSV_PATH, UpdateRequestHandler.class, singletonMap("update.contentType", "application/csv")));
     implicits.add(createPluginInfoWithDefaults(UpdateRequestHandler.DOC_PATH, UpdateRequestHandler.class, makeMap("update.contentType", "application/json", "json.command", "false")));
 
-    Map attrs = Utils.makeMap("legacy", "false", NAME, "/update/v2", "class", V2UpdateRequestHandler.class.getName());
+    Map attrs = Utils.makeMap("legacy", "false", NAME, "/update/v2", "class", UpdateRequestHandlerApi.class.getName());
     implicits.add(new PluginInfo(SolrRequestHandler.TYPE, attrs, new NamedList(), null));
 
     //solrconfighandler

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3cfebd53/solr/core/src/java/org/apache/solr/core/PluginBag.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/core/PluginBag.java b/solr/core/src/java/org/apache/solr/core/PluginBag.java
index cec8b9d..5d627c0 100644
--- a/solr/core/src/java/org/apache/solr/core/PluginBag.java
+++ b/solr/core/src/java/org/apache/solr/core/PluginBag.java
@@ -43,9 +43,9 @@ import org.apache.solr.util.CryptoKeys;
 import org.apache.solr.util.plugin.NamedListInitializedPlugin;
 import org.apache.solr.util.plugin.PluginInfoInitialized;
 import org.apache.solr.util.plugin.SolrCoreAware;
+import org.apache.solr.v2api.Api;
 import org.apache.solr.v2api.ApiBag;
-import org.apache.solr.v2api.V2Api;
-import org.apache.solr.v2api.V2ApiSupport;
+import org.apache.solr.v2api.ApiSupport;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -193,11 +193,11 @@ public class PluginBag<T> implements AutoCloseable {
     if (apiBag != null) {
       if (plugin.isLoaded()) {
         T inst = plugin.get();
-        if (inst instanceof V2ApiSupport && ((V2ApiSupport) inst).registerAutomatically()) {
-          Collection<V2Api> apis = ((V2ApiSupport) inst).getApis();
+        if (inst instanceof ApiSupport && ((ApiSupport) inst).registerAutomatically()) {
+          Collection<Api> apis = ((ApiSupport) inst).getApis();
           if (apis != null) {
             Map<String, String> nameSubstitutes = singletonMap(HANDLER_NAME, name);
-            for (V2Api api : apis) {
+            for (Api api : apis) {
               apiBag.register(api, nameSubstitutes);
             }
           }
@@ -515,7 +515,7 @@ public class PluginBag<T> implements AutoCloseable {
   }
 
 
-  public V2Api v2lookup(String path, String method, Map<String, String> parts) {
+  public Api v2lookup(String path, String method, Map<String, String> parts) {
     if (apiBag == null) {
       throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "this should not happen, looking up for v2 API at the wrong place");
     }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3cfebd53/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java b/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java
index c16e02f..0883100 100644
--- a/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java
+++ b/solr/core/src/java/org/apache/solr/handler/RequestHandlerBase.java
@@ -25,8 +25,6 @@ import java.util.concurrent.atomic.AtomicLong;
 import com.google.common.collect.ImmutableList;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.params.SolrParams;
-import org.apache.solr.common.util.Lookup;
-import org.apache.solr.common.util.Map2;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SimpleOrderedMap;
 import org.apache.solr.common.util.SuppressForbidden;
@@ -41,9 +39,9 @@ import org.apache.solr.util.SolrPluginUtils;
 import org.apache.solr.util.stats.Snapshot;
 import org.apache.solr.util.stats.Timer;
 import org.apache.solr.util.stats.TimerContext;
+import org.apache.solr.v2api.Api;
 import org.apache.solr.v2api.ApiBag;
-import org.apache.solr.v2api.V2Api;
-import org.apache.solr.v2api.V2ApiSupport;
+import org.apache.solr.v2api.ApiSupport;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -53,7 +51,7 @@ import static org.apache.solr.v2api.ApiBag.wrapRequestHandler;
 /**
  *
  */
-public abstract class RequestHandlerBase implements SolrRequestHandler, SolrInfoMBean, NestedRequestHandler, V2ApiSupport {
+public abstract class RequestHandlerBase implements SolrRequestHandler, SolrInfoMBean, NestedRequestHandler, ApiSupport {
 
   protected NamedList initArgs = null;
   protected SolrParams defaults;
@@ -286,7 +284,7 @@ public abstract class RequestHandlerBase implements SolrRequestHandler, SolrInfo
   }
 
   @Override
-  public Collection<V2Api> getApis() {
+  public Collection<Api> getApis() {
     return ImmutableList.of(
         wrapRequestHandler(this, ApiBag.constructSpec(pluginInfo), null)
     );

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3cfebd53/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java b/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
index 94d8276..4e06297 100644
--- a/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
@@ -31,8 +31,6 @@ import com.google.common.collect.ImmutableList;
 import org.apache.solr.cloud.ZkSolrResourceLoader;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.util.ContentStream;
-import org.apache.solr.common.util.Lookup;
-import org.apache.solr.common.util.Map2;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SimpleOrderedMap;
 import org.apache.solr.request.SolrQueryRequest;
@@ -42,9 +40,9 @@ import org.apache.solr.schema.IndexSchema;
 import org.apache.solr.schema.ManagedIndexSchema;
 import org.apache.solr.schema.SchemaManager;
 import org.apache.solr.schema.ZkIndexSchemaReader;
+import org.apache.solr.v2api.Api;
 import org.apache.solr.v2api.ApiBag;
-import org.apache.solr.v2api.V2Api;
-import org.apache.solr.v2api.V2ApiSupport;
+import org.apache.solr.v2api.ApiSupport;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -52,7 +50,7 @@ import static org.apache.solr.common.params.CommonParams.JSON;
 import static org.apache.solr.core.ConfigSetProperties.IMMUTABLE_CONFIGSET_ARG;
 import static org.apache.solr.v2api.ApiBag.wrapRequestHandler;
 
-public class SchemaHandler extends RequestHandlerBase implements V2ApiSupport {
+public class SchemaHandler extends RequestHandlerBase implements ApiSupport {
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
   private boolean isImmutableConfigSet = false;
 
@@ -192,7 +190,7 @@ public class SchemaHandler extends RequestHandlerBase implements V2ApiSupport {
   }
 
   @Override
-  public Collection<V2Api> getApis() {
+  public Collection<Api> getApis() {
     return ImmutableList.of(
         wrapRequestHandler(this, ApiBag.getSpec("core.SchemaRead"), null) ,
         wrapRequestHandler(this, ApiBag.getSpec("core.SchemaEdit"), null));

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3cfebd53/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java b/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
index b7b2145..7f6bd85 100644
--- a/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
@@ -57,8 +57,6 @@ import org.apache.solr.common.params.ModifiableSolrParams;
 import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.common.util.ContentStream;
 import org.apache.solr.common.util.ExecutorUtil;
-import org.apache.solr.common.util.Lookup;
-import org.apache.solr.common.util.Map2;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.StrUtils;
 import org.apache.solr.common.util.Utils;
@@ -76,9 +74,9 @@ import org.apache.solr.schema.SchemaManager;
 import org.apache.solr.util.CommandOperation;
 import org.apache.solr.util.DefaultSolrThreadFactory;
 import org.apache.solr.util.RTimer;
+import org.apache.solr.v2api.Api;
 import org.apache.solr.v2api.ApiBag;
-import org.apache.solr.v2api.V2Api;
-import org.apache.solr.v2api.V2ApiSupport;
+import org.apache.solr.v2api.ApiSupport;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -95,7 +93,7 @@ import static org.apache.solr.core.SolrConfig.PluginOpts.REQUIRE_NAME_IN_OVERLAY
 import static org.apache.solr.schema.FieldType.CLASS_NAME;
 import static org.apache.solr.v2api.ApiBag.wrapRequestHandler;
 
-public class SolrConfigHandler extends RequestHandlerBase implements V2ApiSupport {
+public class SolrConfigHandler extends RequestHandlerBase implements ApiSupport {
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
   public static final String CONFIGSET_EDITING_DISABLED_ARG = "disable.configEdit";
   public static final boolean configEditing_disabled = Boolean.getBoolean(CONFIGSET_EDITING_DISABLED_ARG);
@@ -813,7 +811,7 @@ public class SolrConfigHandler extends RequestHandlerBase implements V2ApiSuppor
   }
 
   @Override
-  public Collection<V2Api> getApis() {
+  public Collection<Api> getApis() {
     return ImmutableList.of(
         wrapRequestHandler(this, ApiBag.getSpec("core.ConfigRead"), null),
         wrapRequestHandler(this, ApiBag.getSpec("core.ConfigEdit"), null)

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3cfebd53/solr/core/src/java/org/apache/solr/handler/UpdateRequestHandlerApi.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/UpdateRequestHandlerApi.java b/solr/core/src/java/org/apache/solr/handler/UpdateRequestHandlerApi.java
new file mode 100644
index 0000000..bf43163
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/handler/UpdateRequestHandlerApi.java
@@ -0,0 +1,68 @@
+package org.apache.solr.handler;
+
+/*
+ * 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.
+ */
+
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.v2api.Api;
+import org.apache.solr.v2api.ApiBag;
+import org.apache.solr.v2api.V2RequestContext;
+
+
+public class UpdateRequestHandlerApi extends UpdateRequestHandler  {
+
+
+  @Override
+  public boolean registerAutomatically() {
+    return true;
+  }
+
+  @Override
+  public Collection<Api> getApis() {
+    return Collections.singleton(getApiImpl());
+  }
+
+  private Api getApiImpl() {
+    return new Api(ApiBag.getSpec("core.Update")) {
+      @Override
+      public void call(V2RequestContext ctx) {
+        String path = ctx.getPath();
+        String target =  mapping.get(path);
+        if(target != null) ctx.getSolrRequest().getContext().put("path", target);
+        try {
+          handleRequest(ctx.getSolrRequest(), ctx.getResponse());
+        } catch (RuntimeException e) {
+          throw e;
+        } catch (Exception e){
+          throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,e );
+        }
+      }
+    };
+  }
+
+  private static final Map<String, String> mapping = ImmutableMap.<String,String>builder()
+      .put("/update", DOC_PATH)
+      .put(JSON_PATH, DOC_PATH)
+      .put("/update/json/commands", JSON_PATH)
+      .build();
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3cfebd53/solr/core/src/java/org/apache/solr/handler/V2UpdateRequestHandler.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/V2UpdateRequestHandler.java b/solr/core/src/java/org/apache/solr/handler/V2UpdateRequestHandler.java
deleted file mode 100644
index 2f89647..0000000
--- a/solr/core/src/java/org/apache/solr/handler/V2UpdateRequestHandler.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package org.apache.solr.handler;
-
-/*
- * 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.
- */
-
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
-
-import com.google.common.collect.ImmutableMap;
-import org.apache.solr.common.SolrException;
-import org.apache.solr.common.util.Lookup;
-import org.apache.solr.common.util.Map2;
-import org.apache.solr.v2api.ApiBag;
-import org.apache.solr.v2api.V2Api;
-import org.apache.solr.v2api.V2RequestContext;
-
-
-public class V2UpdateRequestHandler extends UpdateRequestHandler  {
-
-
-  @Override
-  public boolean registerAutomatically() {
-    return true;
-  }
-
-  @Override
-  public Collection<V2Api> getApis() {
-    return Collections.singleton(getApiImpl());
-  }
-
-  private V2Api getApiImpl() {
-    return new V2Api(ApiBag.getSpec("core.Update")) {
-      @Override
-      public void call(V2RequestContext ctx) {
-        String path = ctx.getPath();
-        String target =  mapping.get(path);
-        if(target != null) ctx.getSolrRequest().getContext().put("path", target);
-        try {
-          handleRequest(ctx.getSolrRequest(), ctx.getResponse());
-        } catch (RuntimeException e) {
-          throw e;
-        } catch (Exception e){
-          throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,e );
-        }
-      }
-    };
-  }
-
-  private static final Map<String, String> mapping = ImmutableMap.<String,String>builder()
-      .put("/update", DOC_PATH)
-      .put(JSON_PATH, DOC_PATH)
-      .put("/update/json/commands", JSON_PATH)
-      .build();
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3cfebd53/solr/core/src/java/org/apache/solr/handler/admin/BaseHandlerApiSupport.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/BaseHandlerApiSupport.java b/solr/core/src/java/org/apache/solr/handler/admin/BaseHandlerApiSupport.java
new file mode 100644
index 0000000..9a575ed
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/handler/admin/BaseHandlerApiSupport.java
@@ -0,0 +1,204 @@
+package org.apache.solr.handler.admin;
+
+/*
+ * 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.
+ */
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.common.util.Map2;
+import org.apache.solr.common.util.Utils;
+import org.apache.solr.util.CommandOperation;
+import org.apache.solr.v2api.Api;
+import org.apache.solr.v2api.ApiBag;
+import org.apache.solr.v2api.ApiSupport;
+import org.apache.solr.v2api.V2RequestContext;
+
+import static org.apache.solr.client.solrj.SolrRequest.METHOD.POST;
+import static org.apache.solr.common.SolrException.ErrorCode.BAD_REQUEST;
+import static org.apache.solr.common.util.StrUtils.splitSmart;
+
+public abstract class BaseHandlerApiSupport implements ApiSupport {
+  protected final Map<SolrRequest.METHOD, Map<V2EndPoint, List<V2Command>>> commandsMapping;
+
+  protected BaseHandlerApiSupport() {
+    commandsMapping = new HashMap<>();
+    for (V2Command cmd : getCommands()) {
+      Map<V2EndPoint, List<V2Command>> m = commandsMapping.get(cmd.getHttpMethod());
+      if (m == null) commandsMapping.put(cmd.getHttpMethod(), m = new HashMap<>());
+      List<V2Command> list = m.get(cmd.getEndPoint());
+      if (list == null) m.put(cmd.getEndPoint(), list = new ArrayList<>());
+      list.add(cmd);
+    }
+  }
+
+  @Override
+  public synchronized Collection<Api> getApis() {
+    ImmutableList.Builder<Api> l = ImmutableList.builder();
+    for (V2EndPoint op : getEndPoints()) l.add(getApi(op));
+    return l.build();
+  }
+
+
+  private Api getApi(final V2EndPoint op) {
+    final Map2 spec = ApiBag.getSpec(op.getSpecName());
+    return new Api(spec) {
+      @Override
+      public void call(V2RequestContext ctx) {
+        SolrParams params = ctx.getSolrRequest().getParams();
+        SolrRequest.METHOD method = SolrRequest.METHOD.valueOf(ctx.getHttpMethod());
+        List<V2Command> commands = commandsMapping.get(method).get(op);
+        try {
+          if (method == POST) {
+            List<CommandOperation> cmds = ctx.getCommands(true);
+            if (cmds.size() > 1)
+              throw new SolrException(BAD_REQUEST, "Only one command is allowed");
+
+
+            CommandOperation c = cmds.size() == 0 ? null : cmds.get(0);
+            V2Command command = null;
+            String commandName = c == null ? null : c.name;
+            for (V2Command cmd : commands) {
+              if (Objects.equals(cmd.getName(), commandName)) {
+                command = cmd;
+                break;
+              }
+            }
+
+            if (command == null) {
+              throw new SolrException(BAD_REQUEST, " no such command " + c);
+            }
+            wrapParams(ctx, c, command, false);
+            invokeCommand(ctx, command, c);
+
+          } else {
+            if (commands == null || commands.isEmpty()) {
+              ctx.getResponse().add("error", "No support for : " + method + " at :" + ctx.getPath());
+              return;
+            }
+            wrapParams(ctx, new CommandOperation("", Collections.EMPTY_MAP), commands.get(0), true);
+            invokeUrl(commands.get(0), ctx);
+          }
+
+        } catch (SolrException e) {
+          throw e;
+        } catch (Exception e) {
+          throw new SolrException(BAD_REQUEST, e);
+        } finally {
+          ctx.getSolrRequest().setParams(params);
+        }
+
+      }
+    };
+
+  }
+
+  private static void wrapParams(final V2RequestContext ctx, final CommandOperation co, final V2Command cmd, final boolean useRequestParams) {
+    final Map<String, String> pathValues = ctx.getPathValues();
+    final Map<String, Object> map = co == null || !(co.getCommandData() instanceof Map) ?
+        Collections.emptyMap() : co.getDataMap();
+    final SolrParams origParams = ctx.getSolrRequest().getParams();
+
+    ctx.getSolrRequest().setParams(
+        new SolrParams() {
+          @Override
+          public String get(String param) {
+            Object vals = getParams0(param);
+            if (vals == null) return null;
+            if (vals instanceof String) return (String) vals;
+            if (vals instanceof String[] && ((String[]) vals).length > 0) return ((String[]) vals)[0];
+            return null;
+          }
+
+          private Object getParams0(String param) {
+            param = cmd.getParamSubstitute(param);
+            Object o = param.indexOf('.') > 0 ?
+                Utils.getObjectByPath(map, true, splitSmart(param, '.')) :
+                map.get(param);
+            if (o == null) o = pathValues.get(param);
+            if (o == null && useRequestParams) o = origParams.getParams(param);
+            if (o instanceof List) {
+              List l = (List) o;
+              return l.toArray(new String[l.size()]);
+            }
+
+            return o;
+          }
+
+          @Override
+          public String[] getParams(String param) {
+            Object vals = getParams0(param);
+            return vals == null || vals instanceof String[] ?
+                (String[]) vals :
+                new String[]{vals.toString()};
+          }
+
+          @Override
+          public Iterator<String> getParameterNamesIterator() {
+            return cmd.getParamNames(co).iterator();
+
+          }
+
+
+        });
+
+  }
+
+
+  public static Collection<String> getParamNames(CommandOperation op, V2Command command) {
+    List<String> result = new ArrayList<>();
+    Object o = op.getCommandData();
+    if (o instanceof Map) {
+      Map map = (Map) o;
+      collectKeyNames(map, result, "");
+    }
+    return result;
+
+  }
+
+  public static void collectKeyNames(Map<String, Object> map, List<String> result, String prefix) {
+    for (Map.Entry<String, Object> e : map.entrySet()) {
+      if (e.getValue() instanceof Map) {
+        collectKeyNames((Map) e.getValue(), result, prefix + e.getKey() + ".");
+      } else {
+        result.add(prefix + e.getKey());
+      }
+    }
+  }
+
+
+  protected abstract void invokeCommand(V2RequestContext ctx, V2Command command, CommandOperation c) throws Exception;
+
+  protected abstract void invokeUrl(V2Command command, V2RequestContext ctx) throws Exception;
+
+  protected abstract List<V2Command> getCommands();
+
+  protected abstract List<V2EndPoint> getEndPoints();
+
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3cfebd53/solr/core/src/java/org/apache/solr/handler/admin/CollectionHandlerApi.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/CollectionHandlerApi.java b/solr/core/src/java/org/apache/solr/handler/admin/CollectionHandlerApi.java
new file mode 100644
index 0000000..1c1f213
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/handler/admin/CollectionHandlerApi.java
@@ -0,0 +1,248 @@
+package org.apache.solr.handler.admin;
+
+/*
+ * 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.
+ */
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.cloud.OverseerCollectionMessageHandler;
+import org.apache.solr.handler.admin.CollectionsHandler.CollectionOperation;
+import org.apache.solr.util.CommandOperation;
+import org.apache.solr.v2api.V2RequestContext;
+
+import static org.apache.solr.client.solrj.SolrRequest.METHOD.DELETE;
+import static org.apache.solr.client.solrj.SolrRequest.METHOD.GET;
+import static org.apache.solr.client.solrj.SolrRequest.METHOD.POST;
+import static org.apache.solr.common.params.CommonParams.NAME;
+import static org.apache.solr.handler.admin.CollectionsHandler.CollectionOperation.*;
+
+
+public class CollectionHandlerApi extends BaseHandlerApiSupport {
+  private final CollectionsHandler handler;
+
+  public CollectionHandlerApi(CollectionsHandler handler) {
+    this.handler = handler;
+  }
+
+  @Override
+  protected List<V2Command> getCommands() {
+    return Arrays.asList(Cmd.values());
+  }
+
+  @Override
+  protected void invokeCommand(V2RequestContext ctx, V2Command command, CommandOperation c) throws Exception {
+    ((Cmd) command).command(ctx, c, this);
+  }
+
+  @Override
+  protected void invokeUrl(V2Command command, V2RequestContext ctx) throws Exception {
+    ((Cmd) command).GET(ctx, this);
+  }
+
+  @Override
+  protected List<V2EndPoint> getEndPoints() {
+    return Arrays.asList(EndPoint.values());
+  }
+
+
+
+  enum Cmd implements V2Command<CollectionHandlerApi> {
+    GET_COLLECTIONS(EndPoint.COLLECTIONS, GET, LIST_OP),
+    GET_A_COLLECTION(EndPoint.PER_COLLECTION, GET, LIST_OP),
+    CREATE_COLLECTION(EndPoint.COLLECTIONS,
+        POST,
+        CREATE_OP,
+        CREATE_OP.action.toLower(),
+        ImmutableMap.of(
+            OverseerCollectionMessageHandler.COLL_CONF, "config")){
+      @Override
+      public Collection<String> getParamNames(CommandOperation op) {
+        Collection<String> names = super.getParamNames(op);
+        Collection<String> result = new ArrayList<>(names.size());
+        for (String paramName : names) {
+          if(paramName.startsWith("properties.")){
+            result.add(paramName.replace("properties.", "property."));
+          } else {
+            result.add(paramName);
+          }
+        }
+        return result;
+      }
+
+      @Override
+      public String getParamSubstitute(String param) {
+        return param.startsWith("property.")? param.replace("property.", "properties.") : super.getParamSubstitute(param);
+      }
+    },
+
+    DELETE_COLL(EndPoint.PER_COLLECTION,
+        DELETE,
+        DELETE_OP,
+        DELETE_OP.action.toLower(),
+        ImmutableMap.of(NAME, "collection")),
+
+    RELOAD_COLL(EndPoint.PER_COLLECTION,
+        POST,
+        RELOAD_OP,
+        RELOAD_OP.action.toLower(),
+        ImmutableMap.of(NAME, "collection")),
+
+    MIGRATE_DOCS(EndPoint.PER_COLLECTION,
+        POST,
+        MIGRATE_OP,
+        "migrate-docs",
+        ImmutableMap.of("split.key", "splitKey",
+            "target.collection", "target",
+            "forward.timeout", "forwardTimeout"
+        )),
+    CREATE_ALIAS(EndPoint.COLLECTIONS,
+        POST,
+        CREATEALIAS_OP,
+        "create-alias",
+        null),
+
+    DELETE_ALIAS(EndPoint.COLLECTIONS,
+        POST,
+        CREATEALIAS_OP,
+        "delete-alias",
+        ImmutableMap.of(NAME, "")),
+    CREATE_SHARD(EndPoint.PER_COLLECTION_SHARDS,
+        POST,
+        CREATESHARD_OP,
+        "create",
+        null),
+
+    SPLIT_SHARD(EndPoint.PER_COLLECTION_PER_SHARD,
+        POST,
+        SPLITSHARD_OP,
+        "split",
+        ImmutableMap.of(
+            "split.key", "splitKey")),
+    DELETE_SHARD(EndPoint.PER_COLLECTION_PER_SHARD,
+        DELETE,
+        DELETESHARD_OP),
+
+
+    CREATE_REPLICA(EndPoint.PER_COLLECTION_PER_SHARD,
+        POST,
+        ADDREPLICA_OP,
+        "create-replica",
+        null),
+
+    DELETE_REPLICA(EndPoint.PER_COLLECTION_PER_SHARD_PER_REPLICA_DELETE,
+        DELETE,
+        DELETEREPLICA_OP),
+
+    SYNC_SHARD(EndPoint.PER_COLLECTION_PER_SHARD,
+        POST,
+        SYNCSHARD_OP,
+        "synch-shard",
+        null),;
+    public final String commandName;
+    public final EndPoint endPoint;
+    public final SolrRequest.METHOD method;
+    public final CollectionOperation target;
+    public final Map<String, String> paramstoAttr;
+
+    public SolrRequest.METHOD getMethod() {
+      return method;
+    }
+
+
+    Cmd(EndPoint endPoint, SolrRequest.METHOD method, CollectionOperation target) {
+      this(endPoint, method, target, null, null);
+    }
+
+    Cmd(EndPoint endPoint, SolrRequest.METHOD method, CollectionOperation target,
+        String commandName, Map<String, String> paramstoAttr) {
+      this.commandName = commandName;
+      this.endPoint = endPoint;
+      this.method = method;
+      this.target = target;
+      this.paramstoAttr = paramstoAttr == null ? Collections.EMPTY_MAP : paramstoAttr;
+    }
+
+
+    @Override
+    public String getName() {
+      return commandName;
+    }
+
+    @Override
+    public SolrRequest.METHOD getHttpMethod() {
+      return method;
+    }
+
+    @Override
+    public V2EndPoint getEndPoint() {
+      return endPoint;
+    }
+
+
+    @Override
+    public void command(V2RequestContext ctx, CommandOperation c, CollectionHandlerApi handler) throws Exception {
+      handler.handler.invokeAction(ctx.getSolrRequest(),ctx.getResponse(),target);
+    }
+
+    @Override
+    public void GET(V2RequestContext ctx, CollectionHandlerApi handler) throws Exception {
+      handler.handler.invokeAction(ctx.getSolrRequest(), ctx.getResponse(), target);
+    }
+
+    @Override
+    public Collection<String> getParamNames(CommandOperation op) {
+      return BaseHandlerApiSupport.getParamNames(op, this);
+    }
+
+    @Override
+    public String getParamSubstitute(String param) {
+      return paramstoAttr.containsKey(param) ? paramstoAttr.get(param) : param;
+    }
+
+
+  }
+
+  enum EndPoint implements V2EndPoint {
+    CLUSTER("collections.Commands"),
+    COLLECTIONS("collections.Commands"),
+    PER_COLLECTION("collections.collection.Commands"),
+    PER_COLLECTION_SHARDS("collections.collection.shards.Commands"),
+    PER_COLLECTION_PER_SHARD("collections.collection.shards.Commands"),
+    PER_COLLECTION_PER_SHARD_REPLICAS("collections.collection.shards.shard.Commands"),
+    PER_COLLECTION_PER_SHARD_PER_REPLICA("collections.collection.shards.shard.replica.Commands"),
+    PER_COLLECTION_PER_SHARD_PER_REPLICA_DELETE("collections.collection.shards.shard.replica.delete");
+    final String specName;
+
+
+    EndPoint(String specName) {
+      this.specName = specName;
+    }
+
+    @Override
+    public String getSpecName() {
+      return specName;
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3cfebd53/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java
----------------------------------------------------------------------
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 d0f74c0..8e8279e 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
@@ -133,8 +133,8 @@ import org.apache.solr.handler.RequestHandlerBase;
 import org.apache.solr.handler.component.ShardHandler;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.response.SolrQueryResponse;
-import org.apache.solr.v2api.V2Api;
-import org.apache.solr.v2api.V2ApiSupport;
+import org.apache.solr.v2api.Api;
+import org.apache.solr.v2api.ApiSupport;
 import org.apache.zookeeper.CreateMode;
 import org.apache.zookeeper.KeeperException;
 import org.slf4j.Logger;
@@ -143,17 +143,17 @@ import org.slf4j.LoggerFactory;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 
-public class CollectionsHandler extends RequestHandlerBase implements V2ApiSupport {
+public class CollectionsHandler extends RequestHandlerBase implements ApiSupport {
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
   protected final CoreContainer coreContainer;
-  private final V2CollectionHandler v2Handler ;
+  private final CollectionHandlerApi v2Handler ;
 
   public CollectionsHandler() {
     super();
     // Unlike most request handlers, CoreContainer initialization
     // should happen in the constructor...
     this.coreContainer = null;
-    v2Handler = new V2CollectionHandler(this);
+    v2Handler = new CollectionHandlerApi(this);
   }
 
 
@@ -164,7 +164,7 @@ public class CollectionsHandler extends RequestHandlerBase implements V2ApiSuppo
    */
   public CollectionsHandler(final CoreContainer coreContainer) {
     this.coreContainer = coreContainer;
-    v2Handler = new V2CollectionHandler(this);
+    v2Handler = new CollectionHandlerApi(this);
   }
 
 
@@ -897,7 +897,7 @@ public class CollectionsHandler extends RequestHandlerBase implements V2ApiSuppo
 
 
   @Override
-  public Collection<V2Api> getApis() {
+  public Collection<Api> getApis() {
     return v2Handler.getApis();
   }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3cfebd53/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
index 276658d..8fbc519 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
@@ -37,12 +37,9 @@ import org.apache.solr.common.SolrException.ErrorCode;
 import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.common.params.CommonAdminParams;
 import org.apache.solr.common.params.CoreAdminParams;
-import org.apache.solr.common.params.CoreAdminParams.CoreAdminAction;
 import org.apache.solr.common.params.ModifiableSolrParams;
 import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.common.util.ExecutorUtil;
-import org.apache.solr.common.util.Lookup;
-import org.apache.solr.common.util.Map2;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.core.CoreContainer;
 import org.apache.solr.core.CoreDescriptor;
@@ -50,8 +47,8 @@ import org.apache.solr.handler.RequestHandlerBase;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.response.SolrQueryResponse;
 import org.apache.solr.util.DefaultSolrThreadFactory;
-import org.apache.solr.v2api.V2Api;
-import org.apache.solr.v2api.V2ApiSupport;
+import org.apache.solr.v2api.Api;
+import org.apache.solr.v2api.ApiSupport;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.MDC;
@@ -63,11 +60,11 @@ import static org.apache.solr.common.params.CoreAdminParams.CoreAdminAction.STAT
  *
  * @since solr 1.3
  */
-public class CoreAdminHandler extends RequestHandlerBase implements V2ApiSupport {
+public class CoreAdminHandler extends RequestHandlerBase implements ApiSupport {
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
   protected final CoreContainer coreContainer;
   protected final Map<String, Map<String, TaskObject>> requestStatusMap;
-  private final V2CoreAdminHandler v2CoreAdminHandler;
+  private final CoreAdminHandlerApi coreAdminHandlerApi;
 
   protected final ExecutorService parallelExecutor = ExecutorUtil.newMDCAwareFixedThreadPool(50,
       new DefaultSolrThreadFactory("parallelCoreAdminExecutor"));
@@ -90,7 +87,7 @@ public class CoreAdminHandler extends RequestHandlerBase implements V2ApiSupport
     map.put(COMPLETED, Collections.synchronizedMap(new LinkedHashMap<>()));
     map.put(FAILED, Collections.synchronizedMap(new LinkedHashMap<>()));
     requestStatusMap = Collections.unmodifiableMap(map);
-    v2CoreAdminHandler = new V2CoreAdminHandler(this);
+    coreAdminHandlerApi = new CoreAdminHandlerApi(this);
   }
 
 
@@ -106,7 +103,7 @@ public class CoreAdminHandler extends RequestHandlerBase implements V2ApiSupport
     map.put(COMPLETED, Collections.synchronizedMap(new LinkedHashMap<String, TaskObject>()));
     map.put(FAILED, Collections.synchronizedMap(new LinkedHashMap<String, TaskObject>()));
     requestStatusMap = Collections.unmodifiableMap(map);
-    v2CoreAdminHandler = new V2CoreAdminHandler(this);
+    coreAdminHandlerApi = new CoreAdminHandlerApi(this);
   }
 
 
@@ -366,8 +363,8 @@ public class CoreAdminHandler extends RequestHandlerBase implements V2ApiSupport
   }
 
   @Override
-  public Collection<V2Api> getApis() {
-    return v2CoreAdminHandler.getApis();
+  public Collection<Api> getApis() {
+    return coreAdminHandlerApi.getApis();
   }
 
   static {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3cfebd53/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandlerApi.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandlerApi.java b/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandlerApi.java
new file mode 100644
index 0000000..ae3eff0
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandlerApi.java
@@ -0,0 +1,170 @@
+package org.apache.solr.handler.admin;
+
+/*
+ * 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.
+ */
+
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.util.CommandOperation;
+import org.apache.solr.v2api.V2RequestContext;
+
+import static org.apache.solr.client.solrj.SolrRequest.METHOD.*;
+import static org.apache.solr.handler.admin.CoreAdminOperation.*;
+import static org.apache.solr.handler.admin.CoreAdminHandlerApi.EndPoint.CORES_COMMANDS;
+import static org.apache.solr.handler.admin.CoreAdminHandlerApi.EndPoint.CORES_STATUS;
+import static org.apache.solr.handler.admin.CoreAdminHandlerApi.EndPoint.PER_CORE_COMMANDS;
+
+public class CoreAdminHandlerApi extends BaseHandlerApiSupport {
+  private final CoreAdminHandler handler;
+
+  public CoreAdminHandlerApi(CoreAdminHandler handler) {
+    this.handler = handler;
+  }
+
+  enum Cmd implements V2Command<CoreAdminHandlerApi> {
+    CREATE(CORES_COMMANDS, POST, CREATE_OP, null, null),
+    UNLOAD(PER_CORE_COMMANDS, POST, UNLOAD_OP, null, null),
+    RELOAD(PER_CORE_COMMANDS, POST, RELOAD_OP, null, null),
+    STATUS(CORES_STATUS, GET, STATUS_OP),
+    SWAP(PER_CORE_COMMANDS, POST, SWAP_OP, null, null),
+    RENAME(PER_CORE_COMMANDS, POST, RENAME_OP, null, null),
+    MERGEINDEXES(PER_CORE_COMMANDS, POST, RENAME_OP, null, null),
+    SPLIT(PER_CORE_COMMANDS, POST, SPLIT_OP, null, null),
+    PREPRECOVERY(PER_CORE_COMMANDS, POST, PREPRECOVERY_OP, null, null),
+    REQUESTRECOVERY(PER_CORE_COMMANDS, POST, REQUESTRECOVERY_OP, null, null),
+    REQUESTSYNCSHARD(PER_CORE_COMMANDS, POST, REQUESTRECOVERY_OP, null, null),
+    REQUESTBUFFERUPDATES(PER_CORE_COMMANDS, POST, REQUESTBUFFERUPDATES_OP, null, null),
+    REQUESTAPPLYUPDATES(PER_CORE_COMMANDS, POST, REQUESTAPPLYUPDATES_OP, null, null),
+    REQUESTSTATUS(PER_CORE_COMMANDS, POST, REQUESTSTATUS_OP, null, null),
+    OVERSEEROP(PER_CORE_COMMANDS, POST, OVERSEEROP_OP, null, null),
+    REJOINLEADERELECTION(PER_CORE_COMMANDS, POST, REJOINLEADERELECTION_OP, null, null),
+    INVOKE(PER_CORE_COMMANDS, POST, INVOKE_OP, null, null),
+    FORCEPREPAREFORLEADERSHIP(PER_CORE_COMMANDS, POST, FORCEPREPAREFORLEADERSHIP_OP, null, null);
+
+    public final String commandName;
+    public final EndPoint endPoint;
+    public final SolrRequest.METHOD method;
+    public final Map<String, String> paramstoAttr;
+    final CoreAdminOperation target;
+
+
+    Cmd(EndPoint endPoint, SolrRequest.METHOD method, CoreAdminOperation target) {
+      this.endPoint = endPoint;
+      this.method = method;
+      this.target = target;
+      commandName = null;
+      paramstoAttr = Collections.EMPTY_MAP;
+
+    }
+
+
+    Cmd(EndPoint endPoint, SolrRequest.METHOD method, CoreAdminOperation target, String commandName,
+        Map<String, String> paramstoAttr) {
+      this.commandName = commandName == null ? target.action.toString().toLowerCase(Locale.ROOT) : commandName;
+      this.endPoint = endPoint;
+      this.method = method;
+      this.target = target;
+      this.paramstoAttr = paramstoAttr == null ? Collections.EMPTY_MAP : paramstoAttr;
+    }
+
+    @Override
+    public String getName() {
+      return commandName;
+    }
+
+    @Override
+    public SolrRequest.METHOD getHttpMethod() {
+      return method;
+    }
+
+    @Override
+    public V2EndPoint getEndPoint() {
+      return endPoint;
+    }
+
+
+    @Override
+    public void command(V2RequestContext ctx, CommandOperation c, CoreAdminHandlerApi coreAdminHandlerApi) throws Exception {
+      target.call(new CoreAdminHandler.CallInfo(coreAdminHandlerApi.handler,ctx.getSolrRequest(),ctx.getResponse(),target ));
+
+    }
+
+    @Override
+    public void GET(V2RequestContext ctx, CoreAdminHandlerApi handler) throws Exception {
+      target.call(new CoreAdminHandler.CallInfo(handler.handler,ctx.getSolrRequest(),ctx.getResponse(),target ));
+
+    }
+
+    @Override
+    public Collection<String> getParamNames(CommandOperation op) {
+      return BaseHandlerApiSupport.getParamNames(op, this);
+    }
+
+    @Override
+    public String getParamSubstitute(String param) {
+      return paramstoAttr.containsKey(param) ? paramstoAttr.get(param) : param;
+    }
+  }
+
+
+
+  enum EndPoint implements V2EndPoint {
+    CORES_STATUS("cores.Status"),
+    CORES_COMMANDS("cores.Commands"),
+    PER_CORE_COMMANDS("cores.core.Commands");
+
+    final String specName;
+
+    EndPoint(String specName) {
+      this.specName = specName;
+    }
+
+    @Override
+    public String getSpecName() {
+      return specName;
+    }
+  }
+
+  @Override
+  protected void invokeCommand(V2RequestContext ctx, V2Command command, CommandOperation c) throws Exception {
+    ((Cmd) command).command(ctx, c, this);
+  }
+
+  @Override
+  protected void invokeUrl(V2Command command, V2RequestContext ctx) throws Exception {
+    command.GET(ctx, this);
+  }
+
+  @Override
+  protected List<V2Command> getCommands() {
+    return Arrays.asList(Cmd.values());
+  }
+
+  @Override
+  protected List<V2EndPoint> getEndPoints() {
+    return Arrays.asList(EndPoint.values());
+  }
+
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3cfebd53/solr/core/src/java/org/apache/solr/handler/admin/InfoHandler.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/InfoHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/InfoHandler.java
index a06e3d5..4186eb2 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/InfoHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/InfoHandler.java
@@ -24,24 +24,22 @@ import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.solr.common.SolrException;
-import org.apache.solr.common.util.Lookup;
-import org.apache.solr.common.util.Map2;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.core.CoreContainer;
 import org.apache.solr.handler.RequestHandlerBase;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.request.SolrRequestHandler;
 import org.apache.solr.response.SolrQueryResponse;
+import org.apache.solr.v2api.Api;
 import org.apache.solr.v2api.ApiBag;
-import org.apache.solr.v2api.V2Api;
-import org.apache.solr.v2api.V2ApiSupport;
+import org.apache.solr.v2api.ApiSupport;
 import org.apache.solr.v2api.V2RequestContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import static org.apache.solr.common.params.CommonParams.PATH;
 
-public class InfoHandler extends RequestHandlerBase implements V2ApiSupport {
+public class InfoHandler extends RequestHandlerBase implements ApiSupport {
   protected static Logger log = LoggerFactory.getLogger(InfoHandler.class);
   protected final CoreContainer coreContainer;
 
@@ -147,8 +145,8 @@ public class InfoHandler extends RequestHandlerBase implements V2ApiSupport {
   private Map<String, RequestHandlerBase> handlers = new ConcurrentHashMap<>();
 
   @Override
-  public Collection<V2Api> getApis() {
-    return Collections.singletonList(new V2Api(ApiBag.getSpec("node.Info")) {
+  public Collection<Api> getApis() {
+    return Collections.singletonList(new Api(ApiBag.getSpec("node.Info")) {
       @Override
       public void call(V2RequestContext ctx) {
         handle(ctx.getSolrRequest(), ctx.getResponse(), ctx.getPath());

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3cfebd53/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandler.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandler.java
index ea2c9ef..8d7c42d 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandler.java
@@ -30,7 +30,6 @@ import com.google.common.collect.ImmutableList;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.cloud.ZkStateReader.ConfigData;
 import org.apache.solr.common.params.CommonParams;
-import org.apache.solr.common.util.Lookup;
 import org.apache.solr.common.util.Map2;
 import org.apache.solr.common.util.Utils;
 import org.apache.solr.core.CoreContainer;
@@ -42,13 +41,13 @@ import org.apache.solr.security.AuthenticationPlugin;
 import org.apache.solr.security.AuthorizationPlugin;
 import org.apache.solr.security.ConfigEditablePlugin;
 import org.apache.solr.util.CommandOperation;
+import org.apache.solr.v2api.Api;
 import org.apache.solr.v2api.ApiBag;
+import org.apache.solr.v2api.ApiSupport;
 import org.apache.solr.v2api.SpecProvider;
-import org.apache.solr.v2api.V2Api;
-import org.apache.solr.v2api.V2ApiSupport;
 import org.apache.zookeeper.KeeperException;
 
-public class SecurityConfHandler extends RequestHandlerBase implements V2ApiSupport {
+public class SecurityConfHandler extends RequestHandlerBase implements ApiSupport {
   private CoreContainer cores;
 
   public SecurityConfHandler(CoreContainer coreContainer) {
@@ -174,14 +173,14 @@ public class SecurityConfHandler extends RequestHandlerBase implements V2ApiSupp
 
 
   @Override
-  public Collection<V2Api> getApis() {
+  public Collection<Api> getApis() {
     return
     ImmutableList.of(
         getApi("authentication"),
         getApi("authorization"));
   }
 
-  private V2Api getApi( String type) {
+  private Api getApi( String type) {
     return ApiBag.wrapRequestHandler(this, null, new SpecProvider() {
       @Override
       public Map2 getSpec() {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3cfebd53/solr/core/src/java/org/apache/solr/handler/admin/V2BaseHandler.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/V2BaseHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/V2BaseHandler.java
deleted file mode 100644
index 3b28c80..0000000
--- a/solr/core/src/java/org/apache/solr/handler/admin/V2BaseHandler.java
+++ /dev/null
@@ -1,207 +0,0 @@
-package org.apache.solr.handler.admin;
-
-/*
- * 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.
- */
-
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
-import com.google.common.collect.ImmutableList;
-import org.apache.solr.client.solrj.SolrRequest;
-import org.apache.solr.common.SolrException;
-import org.apache.solr.common.params.SolrParams;
-import org.apache.solr.common.util.Lookup;
-import org.apache.solr.common.util.Map2;
-import org.apache.solr.common.util.StrUtils;
-import org.apache.solr.common.util.Utils;
-import org.apache.solr.core.CoreContainer;
-import org.apache.solr.util.CommandOperation;
-import org.apache.solr.v2api.ApiBag;
-import org.apache.solr.v2api.V2Api;
-import org.apache.solr.v2api.V2ApiSupport;
-import org.apache.solr.v2api.V2RequestContext;
-
-import static org.apache.solr.client.solrj.SolrRequest.METHOD.POST;
-import static org.apache.solr.common.SolrException.ErrorCode.BAD_REQUEST;
-import static org.apache.solr.common.util.StrUtils.splitSmart;
-
-public abstract class V2BaseHandler implements V2ApiSupport {
-  protected final Map<SolrRequest.METHOD, Map<V2EndPoint, List<V2Command>>> commandsMapping;
-
-  protected V2BaseHandler() {
-    commandsMapping = new HashMap<>();
-    for (V2Command cmd : getCommands()) {
-      Map<V2EndPoint, List<V2Command>> m = commandsMapping.get(cmd.getHttpMethod());
-      if (m == null) commandsMapping.put(cmd.getHttpMethod(), m = new HashMap<>());
-      List<V2Command> list = m.get(cmd.getEndPoint());
-      if (list == null) m.put(cmd.getEndPoint(), list = new ArrayList<>());
-      list.add(cmd);
-    }
-  }
-
-  @Override
-  public synchronized Collection<V2Api> getApis() {
-    ImmutableList.Builder<V2Api> l = ImmutableList.builder();
-    for (V2EndPoint op : getEndPoints()) l.add(getApi(op));
-    return l.build();
-  }
-
-
-  private V2Api getApi(final V2EndPoint op) {
-    final Map2 spec = ApiBag.getSpec(op.getSpecName());
-    return new V2Api(spec) {
-      @Override
-      public void call(V2RequestContext ctx) {
-        SolrParams params = ctx.getSolrRequest().getParams();
-        SolrRequest.METHOD method = SolrRequest.METHOD.valueOf(ctx.getHttpMethod());
-        List<V2Command> commands = commandsMapping.get(method).get(op);
-        try {
-          if (method == POST) {
-            List<CommandOperation> cmds = ctx.getCommands(true);
-            if (cmds.size() > 1)
-              throw new SolrException(BAD_REQUEST, "Only one command is allowed");
-
-
-            CommandOperation c = cmds.size() == 0 ? null : cmds.get(0);
-            V2Command command = null;
-            String commandName = c == null ? null : c.name;
-            for (V2Command cmd : commands) {
-              if (Objects.equals(cmd.getName(), commandName)) {
-                command = cmd;
-                break;
-              }
-            }
-
-            if (command == null) {
-              throw new SolrException(BAD_REQUEST, " no such command " + c);
-            }
-            wrapParams(ctx, c, command, false);
-            invokeCommand(ctx, command, c);
-
-          } else {
-            if (commands == null || commands.isEmpty()) {
-              ctx.getResponse().add("error", "No support for : " + method + " at :" + ctx.getPath());
-              return;
-            }
-            wrapParams(ctx, new CommandOperation("", Collections.EMPTY_MAP), commands.get(0), true);
-            invokeUrl(commands.get(0), ctx);
-          }
-
-        } catch (SolrException e) {
-          throw e;
-        } catch (Exception e) {
-          throw new SolrException(BAD_REQUEST, e);
-        } finally {
-          ctx.getSolrRequest().setParams(params);
-        }
-
-      }
-    };
-
-  }
-
-  private static void wrapParams(final V2RequestContext ctx, final CommandOperation co, final V2Command cmd, final boolean useRequestParams) {
-    final Map<String, String> pathValues = ctx.getPathValues();
-    final Map<String, Object> map = co == null || !(co.getCommandData() instanceof Map) ?
-        Collections.emptyMap() : co.getDataMap();
-    final SolrParams origParams = ctx.getSolrRequest().getParams();
-
-    ctx.getSolrRequest().setParams(
-        new SolrParams() {
-          @Override
-          public String get(String param) {
-            Object vals = getParams0(param);
-            if (vals == null) return null;
-            if (vals instanceof String) return (String) vals;
-            if (vals instanceof String[] && ((String[]) vals).length > 0) return ((String[]) vals)[0];
-            return null;
-          }
-
-          private Object getParams0(String param) {
-            param = cmd.getParamSubstitute(param);
-            Object o = param.indexOf('.') > 0 ?
-                Utils.getObjectByPath(map, true, splitSmart(param, '.')) :
-                map.get(param);
-            if (o == null) o = pathValues.get(param);
-            if (o == null && useRequestParams) o = origParams.getParams(param);
-            if (o instanceof List) {
-              List l = (List) o;
-              return l.toArray(new String[l.size()]);
-            }
-
-            return o;
-          }
-
-          @Override
-          public String[] getParams(String param) {
-            Object vals = getParams0(param);
-            return vals == null || vals instanceof String[] ?
-                (String[]) vals :
-                new String[]{vals.toString()};
-          }
-
-          @Override
-          public Iterator<String> getParameterNamesIterator() {
-            return cmd.getParamNames(co).iterator();
-
-          }
-
-
-        });
-
-  }
-
-
-  public static Collection<String> getParamNames(CommandOperation op, V2Command command) {
-    List<String> result = new ArrayList<>();
-    Object o = op.getCommandData();
-    if (o instanceof Map) {
-      Map map = (Map) o;
-      collectKeyNames(map, result, "");
-    }
-    return result;
-
-  }
-
-  public static void collectKeyNames(Map<String, Object> map, List<String> result, String prefix) {
-    for (Map.Entry<String, Object> e : map.entrySet()) {
-      if (e.getValue() instanceof Map) {
-        collectKeyNames((Map) e.getValue(), result, prefix + e.getKey() + ".");
-      } else {
-        result.add(prefix + e.getKey());
-      }
-    }
-  }
-
-
-  protected abstract void invokeCommand(V2RequestContext ctx, V2Command command, CommandOperation c) throws Exception;
-
-  protected abstract void invokeUrl(V2Command command, V2RequestContext ctx) throws Exception;
-
-  protected abstract List<V2Command> getCommands();
-
-  protected abstract List<V2EndPoint> getEndPoints();
-
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3cfebd53/solr/core/src/java/org/apache/solr/handler/admin/V2CollectionHandler.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/V2CollectionHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/V2CollectionHandler.java
deleted file mode 100644
index d89bf5a..0000000
--- a/solr/core/src/java/org/apache/solr/handler/admin/V2CollectionHandler.java
+++ /dev/null
@@ -1,252 +0,0 @@
-package org.apache.solr.handler.admin;
-
-/*
- * 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.
- */
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
-import com.google.common.collect.ImmutableMap;
-import org.apache.solr.client.solrj.SolrRequest;
-import org.apache.solr.cloud.OverseerCollectionMessageHandler;
-import org.apache.solr.common.SolrException;
-import org.apache.solr.common.params.CollectionParams.CollectionAction;
-import org.apache.solr.handler.admin.CollectionsHandler.CollectionOperation;
-import org.apache.solr.util.CommandOperation;
-import org.apache.solr.v2api.V2RequestContext;
-
-import static org.apache.solr.client.solrj.SolrRequest.METHOD.DELETE;
-import static org.apache.solr.client.solrj.SolrRequest.METHOD.GET;
-import static org.apache.solr.client.solrj.SolrRequest.METHOD.POST;
-import static org.apache.solr.common.params.CollectionParams.CollectionAction.CREATE;
-import static org.apache.solr.common.params.CommonParams.NAME;
-import static org.apache.solr.handler.admin.CollectionsHandler.CollectionOperation.*;
-
-
-public class V2CollectionHandler extends V2BaseHandler {
-  private final CollectionsHandler handler;
-
-  public V2CollectionHandler(CollectionsHandler handler) {
-    this.handler = handler;
-  }
-
-  @Override
-  protected List<V2Command> getCommands() {
-    return Arrays.asList(Cmd.values());
-  }
-
-  @Override
-  protected void invokeCommand(V2RequestContext ctx, V2Command command, CommandOperation c) throws Exception {
-    ((Cmd) command).command(ctx, c, this);
-  }
-
-  @Override
-  protected void invokeUrl(V2Command command, V2RequestContext ctx) throws Exception {
-    ((Cmd) command).GET(ctx, this);
-  }
-
-  @Override
-  protected List<V2EndPoint> getEndPoints() {
-    return Arrays.asList(EndPoint.values());
-  }
-
-
-
-  enum Cmd implements V2Command<V2CollectionHandler> {
-    GET_COLLECTIONS(EndPoint.COLLECTIONS, GET, LIST_OP),
-    GET_A_COLLECTION(EndPoint.PER_COLLECTION, GET, LIST_OP),
-    CREATE_COLLECTION(EndPoint.COLLECTIONS,
-        POST,
-        CREATE_OP,
-        CREATE_OP.action.toLower(),
-        ImmutableMap.of(
-            OverseerCollectionMessageHandler.COLL_CONF, "config")){
-      @Override
-      public Collection<String> getParamNames(CommandOperation op) {
-        Collection<String> names = super.getParamNames(op);
-        Collection<String> result = new ArrayList<>(names.size());
-        for (String paramName : names) {
-          if(paramName.startsWith("properties.")){
-            result.add(paramName.replace("properties.", "property."));
-          } else {
-            result.add(paramName);
-          }
-        }
-        return result;
-      }
-
-      @Override
-      public String getParamSubstitute(String param) {
-        return param.startsWith("property.")? param.replace("property.", "properties.") : super.getParamSubstitute(param);
-      }
-    },
-
-    DELETE_COLL(EndPoint.PER_COLLECTION,
-        DELETE,
-        DELETE_OP,
-        DELETE_OP.action.toLower(),
-        ImmutableMap.of(NAME, "collection")),
-
-    RELOAD_COLL(EndPoint.PER_COLLECTION,
-        POST,
-        RELOAD_OP,
-        RELOAD_OP.action.toLower(),
-        ImmutableMap.of(NAME, "collection")),
-
-    MIGRATE_DOCS(EndPoint.PER_COLLECTION,
-        POST,
-        MIGRATE_OP,
-        "migrate-docs",
-        ImmutableMap.of("split.key", "splitKey",
-            "target.collection", "target",
-            "forward.timeout", "forwardTimeout"
-        )),
-    CREATE_ALIAS(EndPoint.COLLECTIONS,
-        POST,
-        CREATEALIAS_OP,
-        "create-alias",
-        null),
-
-    DELETE_ALIAS(EndPoint.COLLECTIONS,
-        POST,
-        CREATEALIAS_OP,
-        "delete-alias",
-        ImmutableMap.of(NAME, "")),
-    CREATE_SHARD(EndPoint.PER_COLLECTION_SHARDS,
-        POST,
-        CREATESHARD_OP,
-        "create",
-        null),
-
-    SPLIT_SHARD(EndPoint.PER_COLLECTION_PER_SHARD,
-        POST,
-        SPLITSHARD_OP,
-        "split",
-        ImmutableMap.of(
-            "split.key", "splitKey")),
-    DELETE_SHARD(EndPoint.PER_COLLECTION_PER_SHARD,
-        DELETE,
-        DELETESHARD_OP),
-
-
-    CREATE_REPLICA(EndPoint.PER_COLLECTION_PER_SHARD,
-        POST,
-        ADDREPLICA_OP,
-        "create-replica",
-        null),
-
-    DELETE_REPLICA(EndPoint.PER_COLLECTION_PER_SHARD_PER_REPLICA_DELETE,
-        DELETE,
-        DELETEREPLICA_OP),
-
-    SYNC_SHARD(EndPoint.PER_COLLECTION_PER_SHARD,
-        POST,
-        SYNCSHARD_OP,
-        "synch-shard",
-        null),;
-    public final String commandName;
-    public final EndPoint endPoint;
-    public final SolrRequest.METHOD method;
-    public final CollectionOperation target;
-    public final Map<String, String> paramstoAttr;
-
-    public SolrRequest.METHOD getMethod() {
-      return method;
-    }
-
-
-    Cmd(EndPoint endPoint, SolrRequest.METHOD method, CollectionOperation target) {
-      this(endPoint, method, target, null, null);
-    }
-
-    Cmd(EndPoint endPoint, SolrRequest.METHOD method, CollectionOperation target,
-        String commandName, Map<String, String> paramstoAttr) {
-      this.commandName = commandName;
-      this.endPoint = endPoint;
-      this.method = method;
-      this.target = target;
-      this.paramstoAttr = paramstoAttr == null ? Collections.EMPTY_MAP : paramstoAttr;
-    }
-
-
-    @Override
-    public String getName() {
-      return commandName;
-    }
-
-    @Override
-    public SolrRequest.METHOD getHttpMethod() {
-      return method;
-    }
-
-    @Override
-    public V2EndPoint getEndPoint() {
-      return endPoint;
-    }
-
-
-    @Override
-    public void command(V2RequestContext ctx, CommandOperation c, V2CollectionHandler handler) throws Exception {
-      handler.handler.invokeAction(ctx.getSolrRequest(),ctx.getResponse(),target);
-    }
-
-    @Override
-    public void GET(V2RequestContext ctx, V2CollectionHandler handler) throws Exception {
-      handler.handler.invokeAction(ctx.getSolrRequest(), ctx.getResponse(), target);
-    }
-
-    @Override
-    public Collection<String> getParamNames(CommandOperation op) {
-      return V2BaseHandler.getParamNames(op,this);
-    }
-
-    @Override
-    public String getParamSubstitute(String param) {
-      return paramstoAttr.containsKey(param) ? paramstoAttr.get(param) : param;
-    }
-
-
-  }
-
-  enum EndPoint implements V2EndPoint {
-    CLUSTER("collections.Commands"),
-    COLLECTIONS("collections.Commands"),
-    PER_COLLECTION("collections.collection.Commands"),
-    PER_COLLECTION_SHARDS("collections.collection.shards.Commands"),
-    PER_COLLECTION_PER_SHARD("collections.collection.shards.Commands"),
-    PER_COLLECTION_PER_SHARD_REPLICAS("collections.collection.shards.shard.Commands"),
-    PER_COLLECTION_PER_SHARD_PER_REPLICA("collections.collection.shards.shard.replica.Commands"),
-    PER_COLLECTION_PER_SHARD_PER_REPLICA_DELETE("collections.collection.shards.shard.replica.delete");
-    final String specName;
-
-
-    EndPoint(String specName) {
-      this.specName = specName;
-    }
-
-    @Override
-    public String getSpecName() {
-      return specName;
-    }
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3cfebd53/solr/core/src/java/org/apache/solr/handler/admin/V2CoreAdminHandler.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/V2CoreAdminHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/V2CoreAdminHandler.java
deleted file mode 100644
index 9c9523a..0000000
--- a/solr/core/src/java/org/apache/solr/handler/admin/V2CoreAdminHandler.java
+++ /dev/null
@@ -1,173 +0,0 @@
-package org.apache.solr.handler.admin;
-
-/*
- * 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.
- */
-
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
-import org.apache.solr.client.solrj.SolrRequest;
-import org.apache.solr.common.SolrException;
-import org.apache.solr.util.CommandOperation;
-import org.apache.solr.v2api.V2Api;
-import org.apache.solr.v2api.V2RequestContext;
-
-import static org.apache.solr.client.solrj.SolrRequest.METHOD.*;
-import static org.apache.solr.common.SolrException.ErrorCode.BAD_REQUEST;
-import static org.apache.solr.handler.admin.CoreAdminOperation.*;
-import static org.apache.solr.handler.admin.V2CoreAdminHandler.EndPoint.CORES_COMMANDS;
-import static org.apache.solr.handler.admin.V2CoreAdminHandler.EndPoint.CORES_STATUS;
-import static org.apache.solr.handler.admin.V2CoreAdminHandler.EndPoint.PER_CORE_COMMANDS;
-
-public class V2CoreAdminHandler extends V2BaseHandler {
-  private final CoreAdminHandler handler;
-
-  public V2CoreAdminHandler(CoreAdminHandler handler) {
-    this.handler = handler;
-  }
-
-  enum Cmd implements V2Command<V2CoreAdminHandler> {
-    CREATE(CORES_COMMANDS, POST, CREATE_OP, null, null),
-    UNLOAD(PER_CORE_COMMANDS, POST, UNLOAD_OP, null, null),
-    RELOAD(PER_CORE_COMMANDS, POST, RELOAD_OP, null, null),
-    STATUS(CORES_STATUS, GET, STATUS_OP),
-    SWAP(PER_CORE_COMMANDS, POST, SWAP_OP, null, null),
-    RENAME(PER_CORE_COMMANDS, POST, RENAME_OP, null, null),
-    MERGEINDEXES(PER_CORE_COMMANDS, POST, RENAME_OP, null, null),
-    SPLIT(PER_CORE_COMMANDS, POST, SPLIT_OP, null, null),
-    PREPRECOVERY(PER_CORE_COMMANDS, POST, PREPRECOVERY_OP, null, null),
-    REQUESTRECOVERY(PER_CORE_COMMANDS, POST, REQUESTRECOVERY_OP, null, null),
-    REQUESTSYNCSHARD(PER_CORE_COMMANDS, POST, REQUESTRECOVERY_OP, null, null),
-    REQUESTBUFFERUPDATES(PER_CORE_COMMANDS, POST, REQUESTBUFFERUPDATES_OP, null, null),
-    REQUESTAPPLYUPDATES(PER_CORE_COMMANDS, POST, REQUESTAPPLYUPDATES_OP, null, null),
-    REQUESTSTATUS(PER_CORE_COMMANDS, POST, REQUESTSTATUS_OP, null, null),
-    OVERSEEROP(PER_CORE_COMMANDS, POST, OVERSEEROP_OP, null, null),
-    REJOINLEADERELECTION(PER_CORE_COMMANDS, POST, REJOINLEADERELECTION_OP, null, null),
-    INVOKE(PER_CORE_COMMANDS, POST, INVOKE_OP, null, null),
-    FORCEPREPAREFORLEADERSHIP(PER_CORE_COMMANDS, POST, FORCEPREPAREFORLEADERSHIP_OP, null, null);
-
-    public final String commandName;
-    public final EndPoint endPoint;
-    public final SolrRequest.METHOD method;
-    public final Map<String, String> paramstoAttr;
-    final CoreAdminOperation target;
-
-
-    Cmd(EndPoint endPoint, SolrRequest.METHOD method, CoreAdminOperation target) {
-      this.endPoint = endPoint;
-      this.method = method;
-      this.target = target;
-      commandName = null;
-      paramstoAttr = Collections.EMPTY_MAP;
-
-    }
-
-
-    Cmd(EndPoint endPoint, SolrRequest.METHOD method, CoreAdminOperation target, String commandName,
-        Map<String, String> paramstoAttr) {
-      this.commandName = commandName == null ? target.action.toString().toLowerCase(Locale.ROOT) : commandName;
-      this.endPoint = endPoint;
-      this.method = method;
-      this.target = target;
-      this.paramstoAttr = paramstoAttr == null ? Collections.EMPTY_MAP : paramstoAttr;
-    }
-
-    @Override
-    public String getName() {
-      return commandName;
-    }
-
-    @Override
-    public SolrRequest.METHOD getHttpMethod() {
-      return method;
-    }
-
-    @Override
-    public V2EndPoint getEndPoint() {
-      return endPoint;
-    }
-
-
-    @Override
-    public void command(V2RequestContext ctx, CommandOperation c, V2CoreAdminHandler v2CoreAdminHandler) throws Exception {
-      target.call(new CoreAdminHandler.CallInfo(v2CoreAdminHandler.handler,ctx.getSolrRequest(),ctx.getResponse(),target ));
-
-    }
-
-    @Override
-    public void GET(V2RequestContext ctx, V2CoreAdminHandler handler) throws Exception {
-      target.call(new CoreAdminHandler.CallInfo(handler.handler,ctx.getSolrRequest(),ctx.getResponse(),target ));
-
-    }
-
-    @Override
-    public Collection<String> getParamNames(CommandOperation op) {
-      return V2BaseHandler.getParamNames(op,this);
-    }
-
-    @Override
-    public String getParamSubstitute(String param) {
-      return paramstoAttr.containsKey(param) ? paramstoAttr.get(param) : param;
-    }
-  }
-
-
-
-  enum EndPoint implements V2EndPoint {
-    CORES_STATUS("cores.Status"),
-    CORES_COMMANDS("cores.Commands"),
-    PER_CORE_COMMANDS("cores.core.Commands");
-
-    final String specName;
-
-    EndPoint(String specName) {
-      this.specName = specName;
-    }
-
-    @Override
-    public String getSpecName() {
-      return specName;
-    }
-  }
-
-  @Override
-  protected void invokeCommand(V2RequestContext ctx, V2Command command, CommandOperation c) throws Exception {
-    ((Cmd) command).command(ctx, c, this);
-  }
-
-  @Override
-  protected void invokeUrl(V2Command command, V2RequestContext ctx) throws Exception {
-    command.GET(ctx, this);
-  }
-
-  @Override
-  protected List<V2Command> getCommands() {
-    return Arrays.asList(Cmd.values());
-  }
-
-  @Override
-  protected List<V2EndPoint> getEndPoints() {
-    return Arrays.asList(EndPoint.values());
-  }
-
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3cfebd53/solr/core/src/java/org/apache/solr/v2api/Api.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/v2api/Api.java b/solr/core/src/java/org/apache/solr/v2api/Api.java
new file mode 100644
index 0000000..48109ce
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/v2api/Api.java
@@ -0,0 +1,38 @@
+package org.apache.solr.v2api;
+
+/*
+ * 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.
+ */
+
+
+import org.apache.solr.common.util.Map2;
+
+public abstract class Api implements SpecProvider {
+  protected Map2 spec;
+
+  protected Api(Map2 spec) {
+    this.spec = spec;
+  }
+
+
+  public abstract void call(V2RequestContext ctx);
+
+  @Override
+  public Map2 getSpec() {
+    return spec;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3cfebd53/solr/core/src/java/org/apache/solr/v2api/ApiBag.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/v2api/ApiBag.java b/solr/core/src/java/org/apache/solr/v2api/ApiBag.java
index 9967999..239c197 100644
--- a/solr/core/src/java/org/apache/solr/v2api/ApiBag.java
+++ b/solr/core/src/java/org/apache/solr/v2api/ApiBag.java
@@ -28,7 +28,6 @@ import java.util.concurrent.ConcurrentHashMap;
 
 import com.google.common.collect.ImmutableSet;
 import org.apache.solr.common.SolrException;
-import org.apache.solr.common.util.Lookup;
 import org.apache.solr.common.util.Map2;
 import org.apache.solr.core.PluginBag;
 import org.apache.solr.core.PluginInfo;
@@ -44,7 +43,7 @@ import static org.apache.solr.common.util.Map2.NOT_NULL;
 public class ApiBag {
   private static final Logger log = LoggerFactory.getLogger(ApiBag.class);
 
-  private final Map<String, PathTrie<V2Api>> apis = new ConcurrentHashMap<>();
+  private final Map<String, PathTrie<Api>> apis = new ConcurrentHashMap<>();
 
   public static Map2 getResource(String name) {
     InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(name);
@@ -67,7 +66,7 @@ public class ApiBag {
 
 
 
-  public synchronized void register(V2Api api, Map<String, String> nameSubstitutes) {
+  public synchronized void register(Api api, Map<String, String> nameSubstitutes) {
     try {
       validateAndRegister(api, nameSubstitutes);
     } catch (Exception e) {
@@ -81,12 +80,12 @@ public class ApiBag {
     }
   }
 
-  private void validateAndRegister(V2Api api, Map<String, String> nameSubstitutes) {
+  private void validateAndRegister(Api api, Map<String, String> nameSubstitutes) {
     Map2 spec = api.getSpec();
-    V2Api introspect = getIntrospect(api);
+    Api introspect = getIntrospect(api);
     List<String> methods = spec.getList("methods", ENUM_OF, SUPPORTED_METHODS);
     for (String method : methods) {
-      PathTrie<V2Api> registry = apis.get(method);
+      PathTrie<Api> registry = apis.get(method);
       if (registry == null) apis.put(method, registry = new PathTrie<>());
       Map2 url = spec.getMap("url", NOT_NULL);
       Map2 params = url.getMap("params", null);
@@ -116,8 +115,8 @@ public class ApiBag {
     }
   }
 
-  private V2Api getIntrospect(final V2Api baseApi) {
-    return new V2Api(Map2.EMPTY) {
+  private Api getIntrospect(final Api baseApi) {
+    return new Api(Map2.EMPTY) {
 
       @Override
       public Map2 getSpec() {
@@ -166,15 +165,15 @@ public class ApiBag {
   }
 
 
-  public V2Api lookup(String path, String httpMethod, Map<String, String> parts) {
+  public Api lookup(String path, String httpMethod, Map<String, String> parts) {
     if (httpMethod == null) {
-      for (PathTrie<V2Api> trie : apis.values()) {
-        V2Api api = trie.lookup(path, parts);
+      for (PathTrie<Api> trie : apis.values()) {
+        Api api = trie.lookup(path, parts);
         if (api != null) return api;
       }
       return null;
     } else {
-      PathTrie<V2Api> registry = apis.get(httpMethod);
+      PathTrie<Api> registry = apis.get(httpMethod);
       if (registry == null) return null;
       return registry.lookup(path, parts);
     }
@@ -205,8 +204,8 @@ public class ApiBag {
     return result;
   }
 
-  public static V2Api wrapRequestHandler(final SolrRequestHandler rh, final Map2 spec, SpecProvider specProvider) {
-    return new V2Api(spec) {
+  public static Api wrapRequestHandler(final SolrRequestHandler rh, final Map2 spec, SpecProvider specProvider) {
+    return new Api(spec) {
       @Override
       public void call(V2RequestContext ctx) {
         rh.handleRequest(ctx.getSolrRequest(), ctx.getResponse());
@@ -221,7 +220,7 @@ public class ApiBag {
     };
   }
 
-  public static final String APISPEC_LOCATION = "v2apispec/";
+  public static final String APISPEC_LOCATION = "apispec/";
   public static final String INTROSPECT = "/_introspect";
 
 
@@ -229,7 +228,7 @@ public class ApiBag {
   public static final String HANDLER_NAME = "handlerName";
   public static final Set<String> KNOWN_TYPES = ImmutableSet.of("string", "boolean", "list", "int", "double");
 
-  public PathTrie<V2Api> getRegistry(String method) {
+  public PathTrie<Api> getRegistry(String method) {
     return apis.get(method);
   }
 
@@ -251,10 +250,10 @@ public class ApiBag {
     }
   }
 
-  public static class LazyLoadedApi extends V2Api {
+  public static class LazyLoadedApi extends Api {
 
     private final PluginBag.PluginHolder<SolrRequestHandler> holder;
-    private V2Api delegate;
+    private Api delegate;
 
     protected LazyLoadedApi(Map2 spec, PluginBag.PluginHolder<SolrRequestHandler> lazyPluginHolder) {
       super(spec);

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/3cfebd53/solr/core/src/java/org/apache/solr/v2api/ApiSupport.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/v2api/ApiSupport.java b/solr/core/src/java/org/apache/solr/v2api/ApiSupport.java
new file mode 100644
index 0000000..e11cb4b
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/v2api/ApiSupport.java
@@ -0,0 +1,30 @@
+package org.apache.solr.v2api;
+
+/*
+ * 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.
+ */
+
+import java.util.Collection;
+
+public interface ApiSupport {
+
+  Collection<Api> getApis();
+
+
+  default boolean registerAutomatically() {
+    return true;
+  }
+}