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/16 21:31:05 UTC

lucene-solr git commit: SOLR-8029 removed the V2RequestContext class and folded the functionality into SolrQueryRequest

Repository: lucene-solr
Updated Branches:
  refs/heads/apiv2 346038000 -> a4b5c46ff


SOLR-8029 removed the V2RequestContext class and folded the functionality into SolrQueryRequest


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

Branch: refs/heads/apiv2
Commit: a4b5c46ff71b569a55f57c1bc5be00b17c36e755
Parents: 3460380
Author: Noble Paul <no...@gmail.com>
Authored: Tue Feb 16 12:30:42 2016 -0800
Committer: Noble Paul <no...@gmail.com>
Committed: Tue Feb 16 12:30:42 2016 -0800

----------------------------------------------------------------------
 solr/core/src/java/org/apache/solr/api/Api.java |   4 +-
 .../src/java/org/apache/solr/api/ApiBag.java    |  61 ++++++++--
 .../java/org/apache/solr/api/V2HttpCall.java    | 122 +++----------------
 .../org/apache/solr/api/V2RequestContext.java   |  45 -------
 .../org/apache/solr/handler/SchemaHandler.java  |  15 +--
 .../apache/solr/handler/SolrConfigHandler.java  |   8 +-
 .../solr/handler/UpdateRequestHandlerApi.java   |  11 +-
 .../apache/solr/handler/admin/ApiCommand.java   |  43 +++++++
 .../handler/admin/BaseHandlerApiSupport.java    |  55 ++++-----
 .../handler/admin/CollectionHandlerApi.java     |  23 ++--
 .../solr/handler/admin/CoreAdminHandlerApi.java |  26 ++--
 .../apache/solr/handler/admin/InfoHandler.java  |   6 +-
 .../apache/solr/handler/admin/V2Command.java    |  42 -------
 .../apache/solr/request/SolrQueryRequest.java   |  19 +++
 .../solr/request/SolrQueryRequestBase.java      |  31 +++++
 .../org/apache/solr/schema/SchemaManager.java   |  12 +-
 .../org/apache/solr/servlet/HttpSolrCall.java   |  27 ++++
 .../apache/solr/servlet/SolrRequestParsers.java |  15 ++-
 .../solr/handler/admin/TestApiFramework.java    |  19 ++-
 .../solr/handler/admin/TestCollectionAPIs.java  |  63 ++--------
 .../solr/servlet/SolrRequestParserTest.java     |   4 +-
 21 files changed, 307 insertions(+), 344 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a4b5c46f/solr/core/src/java/org/apache/solr/api/Api.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/api/Api.java b/solr/core/src/java/org/apache/solr/api/Api.java
index d540062..206a253 100644
--- a/solr/core/src/java/org/apache/solr/api/Api.java
+++ b/solr/core/src/java/org/apache/solr/api/Api.java
@@ -19,6 +19,8 @@ package org.apache.solr.api;
 
 
 import org.apache.solr.common.util.Map2;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.SolrQueryResponse;
 
 public abstract class Api implements SpecProvider {
   protected Map2 spec;
@@ -28,7 +30,7 @@ public abstract class Api implements SpecProvider {
   }
 
 
-  public abstract void call(V2RequestContext ctx);
+  public abstract void call(SolrQueryRequest req , SolrQueryResponse rsp);
 
   @Override
   public Map2 getSpec() {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a4b5c46f/solr/core/src/java/org/apache/solr/api/ApiBag.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/api/ApiBag.java b/solr/core/src/java/org/apache/solr/api/ApiBag.java
index 71021b3..cc3539e 100644
--- a/solr/core/src/java/org/apache/solr/api/ApiBag.java
+++ b/solr/core/src/java/org/apache/solr/api/ApiBag.java
@@ -17,7 +17,9 @@ package org.apache.solr.api;
  * limitations under the License.
  */
 
+import java.io.IOException;
 import java.io.InputStream;
+import java.io.Reader;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
@@ -31,7 +33,10 @@ import org.apache.solr.common.SolrException;
 import org.apache.solr.common.util.Map2;
 import org.apache.solr.core.PluginBag;
 import org.apache.solr.core.PluginInfo;
+import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.request.SolrRequestHandler;
+import org.apache.solr.response.SolrQueryResponse;
+import org.apache.solr.util.CommandOperation;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -39,6 +44,7 @@ import static org.apache.solr.client.solrj.SolrRequest.SUPPORTED_METHODS;
 import static org.apache.solr.common.params.CommonParams.NAME;
 import static org.apache.solr.common.util.Map2.ENUM_OF;
 import static org.apache.solr.common.util.Map2.NOT_NULL;
+import static org.apache.solr.common.util.StrUtils.formatString;
 
 public class ApiBag {
   private static final Logger log = LoggerFactory.getLogger(ApiBag.class);
@@ -124,8 +130,9 @@ public class ApiBag {
       }
 
       @Override
-      public void call(V2RequestContext ctx) {
-        String cmd = ctx.getSolrRequest().getParams().get("command");
+      public void call(SolrQueryRequest req, SolrQueryResponse rsp) {
+
+        String cmd = req.getParams().get("command");
         Map2 result = null;
         if (cmd == null) {
           result = baseApi.getSpec();
@@ -138,8 +145,8 @@ public class ApiBag {
           }
           result = specCopy;
         }
-        List l = (List) ctx.getResponse().getValues().get("spec");
-        if (l == null) ctx.getResponse().getValues().add("spec", l = new ArrayList());
+        List l = (List) rsp.getValues().get("spec");
+        if (l == null) rsp.getValues().add("spec", l = new ArrayList());
         l.add(result);
       }
     };
@@ -207,8 +214,8 @@ public class ApiBag {
   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());
+      public void call(SolrQueryRequest req, SolrQueryResponse rsp) {
+        rh.handleRequest(req, rsp);
       }
 
       @Override
@@ -250,6 +257,44 @@ public class ApiBag {
     }
   }
 
+  public static List<CommandOperation> getCommandOperations(Reader reader, Map2 spec, boolean validate) {
+    List<CommandOperation> parsedCommands = null;
+    try {
+      parsedCommands = CommandOperation.parse(reader);
+    } catch (IOException e) {
+      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
+    }
+    if (spec == null || !validate) {    // no validation possible because we do not have a spec
+      return parsedCommands;
+    }
+
+    Map2 cmds = spec.getMap("commands", NOT_NULL);
+    List<CommandOperation> commandsCopy = CommandOperation.clone(parsedCommands);
+
+    for (CommandOperation cmd : commandsCopy) {
+      if (!cmds.containsKey(cmd.name)) {
+        cmd.addError(formatString("Unknown operation ''{0}'' in path ''{1}''", cmd.name,
+            spec.getMap("url", NOT_NULL).get("paths")));
+      }
+      //TODO validation
+
+    }
+    List<Map> errs = CommandOperation.captureErrors(commandsCopy);
+    if (!errs.isEmpty()) {
+      throw new ExceptionWithErrObject(SolrException.ErrorCode.BAD_REQUEST, "Error in command payload", errs);
+    }
+    return commandsCopy;
+  }
+
+  static class ExceptionWithErrObject extends SolrException {
+    private List<Map> errs;
+
+    public ExceptionWithErrObject(ErrorCode code, String msg, List<Map> errs) {
+      super(code, msg);
+      this.errs = errs;
+    }
+  }
+
   public static class LazyLoadedApi extends Api {
 
     private final PluginBag.PluginHolder<SolrRequestHandler> holder;
@@ -261,11 +306,11 @@ public class ApiBag {
     }
 
     @Override
-    public void call(V2RequestContext ctx) {
+    public void call(SolrQueryRequest req, SolrQueryResponse rsp) {
       if (!holder.isLoaded()) {
         delegate = wrapRequestHandler(holder.get(), null, null);
       }
-      delegate.call(ctx);
+      delegate.call(req, rsp);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a4b5c46f/solr/core/src/java/org/apache/solr/api/V2HttpCall.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/api/V2HttpCall.java b/solr/core/src/java/org/apache/solr/api/V2HttpCall.java
index fe5c336..e5f68d4 100644
--- a/solr/core/src/java/org/apache/solr/api/V2HttpCall.java
+++ b/solr/core/src/java/org/apache/solr/api/V2HttpCall.java
@@ -19,11 +19,8 @@ package org.apache.solr.api;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-
-import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.io.Reader;
 import java.lang.invoke.MethodHandles;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -52,16 +49,11 @@ import org.apache.solr.security.AuthorizationContext;
 import org.apache.solr.servlet.HttpSolrCall;
 import org.apache.solr.servlet.SolrDispatchFilter;
 import org.apache.solr.servlet.SolrRequestParsers;
-import org.apache.solr.util.CommandOperation;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
 import static org.apache.solr.common.params.CommonParams.JSON;
 import static org.apache.solr.common.params.CommonParams.WT;
-import static org.apache.solr.common.util.Map2.getDeepCopy;
-import static org.apache.solr.common.util.StrUtils.formatString;
-import static org.apache.solr.common.util.Map2.NOT_NULL;
 import static org.apache.solr.servlet.SolrDispatchFilter.Action.ADMIN;
 import static org.apache.solr.servlet.SolrDispatchFilter.Action.PROCESS;
 
@@ -167,9 +159,9 @@ public class V2HttpCall extends HttpSolrCall {
   }
 
   public static Api getApiInfo(PluginBag<SolrRequestHandler> requestHandlers,
-                                 String path, String method,
-                                 CoreContainer cores, String prefix, String fullPath,
-                                 Map<String, String> parts) {
+                               String path, String method,
+                               CoreContainer cores, String prefix, String fullPath,
+                               Map<String, String> parts) {
     if (fullPath == null) fullPath = path;
     Api api;
     boolean containerHandlerLookup = cores.getRequestHandlers() == requestHandlers;
@@ -211,7 +203,7 @@ public class V2HttpCall extends HttpSolrCall {
         registry.lookup(path, new HashMap<>(), subPaths);
         for (String subPath : subPaths) {
           Set<String> supportedMethods = pathsVsMethod.get(subPath);
-          if(supportedMethods == null) pathsVsMethod.put(subPath, supportedMethods = new HashSet<>());
+          if (supportedMethods == null) pathsVsMethod.put(subPath, supportedMethods = new HashSet<>());
           supportedMethods.add(m.toString());
         }
       }
@@ -219,7 +211,7 @@ public class V2HttpCall extends HttpSolrCall {
   }
 
   private static Api mergeIntrospect(PluginBag<SolrRequestHandler> requestHandlers,
-                                       String path, String method, Map<String, String> parts) {
+                                     String path, String method, Map<String, String> parts) {
     Api api;
     final Map<String, Api> apis = new LinkedHashMap<>();
     for (String m : SolrRequest.SUPPORTED_METHODS) {
@@ -228,13 +220,13 @@ public class V2HttpCall extends HttpSolrCall {
     }
     api = new Api(ApiBag.INTROSPECT_SPEC) {
       @Override
-      public void call(V2RequestContext ctx) {
-        String method = ctx.getSolrRequest().getParams().get("method");
+      public void call(SolrQueryRequest req, SolrQueryResponse rsp) {
+        String method = req.getParams().get("method");
         Set<Api> added = new HashSet<>();
         for (Map.Entry<String, Api> e : apis.entrySet()) {
-          if (method == null || e.getKey().equals(ctx.getHttpMethod())) {
+          if (method == null || e.getKey().equals(req.getHttpMethod())) {
             if (!added.contains(e.getValue())) {
-              e.getValue().call(ctx);
+              e.getValue().call(req, rsp);
               added.add(e.getValue());
             }
           }
@@ -247,27 +239,27 @@ public class V2HttpCall extends HttpSolrCall {
   private static Api getSubPathImpl(final Map<String, Set<String>> subpaths, String path) {
     return new Api(Map2.EMPTY) {
       @Override
-      public void call(V2RequestContext ctx) {
-        ctx.getResponse().add("msg", "Invalid path, try the following");
+      public void call(SolrQueryRequest req, SolrQueryResponse rsp) {
+        rsp.add("msg", "Invalid path, try the following");
         LinkedHashMap<String, Set<String>> result = new LinkedHashMap<>(subpaths.size());
         for (Map.Entry<String, Set<String>> e : subpaths.entrySet()) {
           if (e.getKey().endsWith(ApiBag.INTROSPECT)) continue;
           result.put(path + e.getKey(), e.getValue());
         }
-        ctx.getResponse().add("availableSubPaths", result);
+        rsp.add("availableSubPaths", result);
       }
     };
   }
 
   @Override
   protected void handleAdmin(SolrQueryResponse solrResp) {
-    api.call(getV2RequestCtx(solrResp));
+    api.call(this.solrReq, solrResp);
   }
 
   @Override
   protected void execute(SolrQueryResponse rsp) {
     try {
-      api.call(getV2RequestCtx(rsp));
+      api.call(solrReq, rsp);
     } catch (RuntimeException e) {
       //todo remove for debugging only
       log.error("error execute()", e);
@@ -282,88 +274,8 @@ public class V2HttpCall extends HttpSolrCall {
     return SolrCore.DEFAULT_RESPONSE_WRITERS.get(wt);
   }
 
-  public V2RequestContext getV2RequestCtx(SolrQueryResponse solrResp) {
-
-    return new V2RequestContext() {
-      List<CommandOperation> parsedCommands;
-
-      @Override
-      public SolrQueryResponse getResponse() {
-        return solrResp;
-      }
-
-      @Override
-      public CoreContainer getCoreContainer() {
-        return cores;
-      }
-
-      @Override
-      public SolrQueryRequest getSolrRequest() {
-        return solrReq;
-      }
-
-      @Override
-      public String getPath() {
-        return path;
-      }
-
-      @Override
-      public String getHttpMethod() {
-        return (String) solrReq.getContext().get("httpMethod");
-      }
-
-      @Override
-      public Map<String, String> getPathValues() {
-        return parts;
-      }
-
-      @Override
-      public List<CommandOperation> getCommands(boolean validateInput) {
-        if (parsedCommands == null) {
-          Iterable<ContentStream> contentStreams = solrReq.getContentStreams();
-          if (contentStreams == null) throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "No content stream");
-          for (ContentStream contentStream : contentStreams) {
-            parsedCommands = getCommandOperations(new InputStreamReader((InputStream) contentStream, UTF_8),
-                api.getSpec(), solrResp);
-
-          }
-
-        }
-        return CommandOperation.clone(parsedCommands);
-
-      }
-
-
-    };
-  }
-
-  public static List<CommandOperation> getCommandOperations(Reader reader, Map2 spec, SolrQueryResponse rsp) {
-    List<CommandOperation> parsedCommands = null;
-    try {
-      parsedCommands = CommandOperation.parse(reader);
-    } catch (IOException e) {
-      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
-    }
-
-    Map2 cmds = spec.getMap("commands", NOT_NULL);
-    List<CommandOperation> commandsCopy = CommandOperation.clone(parsedCommands);
-
-    for (CommandOperation cmd : commandsCopy) {
-      if (!cmds.containsKey(cmd.name)) {
-        cmd.addError(formatString("Unknown operation ''{0}'' in path ''{1}''", cmd.name,
-            spec.getMap("url", NOT_NULL).get("paths")));
-      }
-      //TODO validation
-
-    }
-    List<Map> errs = CommandOperation.captureErrors(commandsCopy);
-    if (!errs.isEmpty()) {
-      rsp.add(CommandOperation.ERR_MSGS, errs);
-      SolrException exp = new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Errors in commands");
-      rsp.setException(exp);
-      throw exp;
-    }
-    return commandsCopy;
+  @Override
+  protected Map2 getSpec() {
+    return api == null ? null : api.getSpec();
   }
-
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a4b5c46f/solr/core/src/java/org/apache/solr/api/V2RequestContext.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/api/V2RequestContext.java b/solr/core/src/java/org/apache/solr/api/V2RequestContext.java
deleted file mode 100644
index 02782b6..0000000
--- a/solr/core/src/java/org/apache/solr/api/V2RequestContext.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package org.apache.solr.api;
-
-/*
- * 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.List;
-import java.util.Map;
-
-import org.apache.solr.core.CoreContainer;
-import org.apache.solr.request.SolrQueryRequest;
-import org.apache.solr.response.SolrQueryResponse;
-import org.apache.solr.util.CommandOperation;
-
-public interface V2RequestContext {
-
-  SolrQueryResponse getResponse();
-
-  CoreContainer getCoreContainer();
-
-  SolrQueryRequest getSolrRequest();
-
-  String getPath();
-
-
-  Map<String, String> getPathValues();
-
-  List<CommandOperation> getCommands(boolean validateInput);
-
-  String getHttpMethod();
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a4b5c46f/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 0fba1df..1f8ef7f 100644
--- a/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/SchemaHandler.java
@@ -75,15 +75,12 @@ public class SchemaHandler extends RequestHandlerBase implements ApiSupport {
         return;
       }
 
-      for (ContentStream stream : req.getContentStreams()) {
-        try {
-          List errs = new SchemaManager(req).performOperations(stream.getReader());
-          if (!errs.isEmpty()) rsp.add("errors", errs);
-        } catch (IOException e) {
-          rsp.add("errors", Collections.singletonList("Error reading input String " + e.getMessage()));
-          rsp.setException(e);
-        }
-        break;
+      try {
+        List errs = new SchemaManager(req).performOperations();
+        if (!errs.isEmpty()) rsp.add("errors", errs);
+      } catch (IOException e) {
+        rsp.add("errors", Collections.singletonList("Error reading input String " + e.getMessage()));
+        rsp.setException(e);
       }
     } else {
       handleGET(req, rsp);

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a4b5c46f/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 50e3fba..9edade2 100644
--- a/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
@@ -251,12 +251,10 @@ public class SolrConfigHandler extends RequestHandlerBase implements ApiSupport
 
 
     private void handlePOST() throws IOException {
-      List<CommandOperation> ops = CommandOperation.readCommands(req.getContentStreams(), resp);
-      if (ops == null) return;
       try {
         for (; ; ) {
-          ArrayList<CommandOperation> opsCopy = new ArrayList<>(ops.size());
-          for (CommandOperation op : ops) opsCopy.add(op.getCopy());
+          List<CommandOperation> opsCopy = req.getCommands(false);
+          if(opsCopy == null) return;
           try {
             if (parts.size() > 1 && RequestParams.NAME.equals(parts.get(1))) {
               RequestParams params = RequestParams.getFreshRequestParams(req.getCore().getResourceLoader(), req.getCore().getSolrConfig().getRequestParams());
@@ -279,7 +277,7 @@ public class SolrConfigHandler extends RequestHandlerBase implements ApiSupport
     }
 
 
-    private void handleParams(ArrayList<CommandOperation> ops, RequestParams params) {
+    private void handleParams(List<CommandOperation> ops, RequestParams params) {
       for (CommandOperation op : ops) {
         switch (op.name) {
           case SET:

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a4b5c46f/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
index 6109ceb..1292cde 100644
--- a/solr/core/src/java/org/apache/solr/handler/UpdateRequestHandlerApi.java
+++ b/solr/core/src/java/org/apache/solr/handler/UpdateRequestHandlerApi.java
@@ -26,7 +26,8 @@ import com.google.common.collect.ImmutableMap;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.api.Api;
 import org.apache.solr.api.ApiBag;
-import org.apache.solr.api.V2RequestContext;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.SolrQueryResponse;
 
 
 public class UpdateRequestHandlerApi extends UpdateRequestHandler  {
@@ -45,12 +46,12 @@ public class UpdateRequestHandlerApi extends UpdateRequestHandler  {
   private Api getApiImpl() {
     return new Api(ApiBag.getSpec("core.Update")) {
       @Override
-      public void call(V2RequestContext ctx) {
-        String path = ctx.getPath();
+      public void call(SolrQueryRequest req, SolrQueryResponse rsp) {
+        String path = req.getPath();
         String target =  mapping.get(path);
-        if(target != null) ctx.getSolrRequest().getContext().put("path", target);
+        if(target != null) req.getContext().put("path", target);
         try {
-          handleRequest(ctx.getSolrRequest(), ctx.getResponse());
+          handleRequest(req, rsp);
         } catch (RuntimeException e) {
           throw e;
         } catch (Exception e){

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a4b5c46f/solr/core/src/java/org/apache/solr/handler/admin/ApiCommand.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/ApiCommand.java b/solr/core/src/java/org/apache/solr/handler/admin/ApiCommand.java
new file mode 100644
index 0000000..cce86fb
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/handler/admin/ApiCommand.java
@@ -0,0 +1,43 @@
+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.Collection;
+
+import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.SolrQueryResponse;
+import org.apache.solr.util.CommandOperation;
+
+public interface ApiCommand<T> {
+  String getName();
+
+  SolrRequest.METHOD getHttpMethod();
+
+  V2EndPoint getEndPoint();
+
+
+  void command(SolrQueryRequest req, SolrQueryResponse rsp, CommandOperation c, T handler) throws Exception;
+
+  void GET(SolrQueryRequest req, SolrQueryResponse rsp, T handler) throws Exception;
+
+  Collection<String> getParamNames(CommandOperation op);
+
+  String getParamSubstitute(String name);
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a4b5c46f/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
index 6112491..0b61db3 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/BaseHandlerApiSupport.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/BaseHandlerApiSupport.java
@@ -33,25 +33,26 @@ 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.request.SolrQueryRequest;
+import org.apache.solr.response.SolrQueryResponse;
 import org.apache.solr.util.CommandOperation;
 import org.apache.solr.api.Api;
 import org.apache.solr.api.ApiBag;
 import org.apache.solr.api.ApiSupport;
-import org.apache.solr.api.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 final Map<SolrRequest.METHOD, Map<V2EndPoint, List<ApiCommand>>> commandsMapping;
 
   protected BaseHandlerApiSupport() {
     commandsMapping = new HashMap<>();
-    for (V2Command cmd : getCommands()) {
-      Map<V2EndPoint, List<V2Command>> m = commandsMapping.get(cmd.getHttpMethod());
+    for (ApiCommand cmd : getCommands()) {
+      Map<V2EndPoint, List<ApiCommand>> m = commandsMapping.get(cmd.getHttpMethod());
       if (m == null) commandsMapping.put(cmd.getHttpMethod(), m = new HashMap<>());
-      List<V2Command> list = m.get(cmd.getEndPoint());
+      List<ApiCommand> list = m.get(cmd.getEndPoint());
       if (list == null) m.put(cmd.getEndPoint(), list = new ArrayList<>());
       list.add(cmd);
     }
@@ -69,21 +70,19 @@ public abstract class BaseHandlerApiSupport implements ApiSupport {
     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);
+      public void call(SolrQueryRequest req, SolrQueryResponse rsp) {
+        SolrParams params = req.getParams();
+        SolrRequest.METHOD method = SolrRequest.METHOD.valueOf(req.getHttpMethod());
+        List<ApiCommand> commands = commandsMapping.get(method).get(op);
         try {
           if (method == POST) {
-            List<CommandOperation> cmds = ctx.getCommands(true);
+            List<CommandOperation> cmds = req.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;
+            ApiCommand command = null;
             String commandName = c == null ? null : c.name;
-            for (V2Command cmd : commands) {
+            for (ApiCommand cmd : commands) {
               if (Objects.equals(cmd.getName(), commandName)) {
                 command = cmd;
                 break;
@@ -93,16 +92,16 @@ public abstract class BaseHandlerApiSupport implements ApiSupport {
             if (command == null) {
               throw new SolrException(BAD_REQUEST, " no such command " + c);
             }
-            wrapParams(ctx, c, command, false);
-            invokeCommand(ctx, command, c);
+            wrapParams(req, c, command, false);
+            invokeCommand(req, rsp,command, c);
 
           } else {
             if (commands == null || commands.isEmpty()) {
-              ctx.getResponse().add("error", "No support for : " + method + " at :" + ctx.getPath());
+              rsp.add("error", "No support for : " + method + " at :" + req.getPath());
               return;
             }
-            wrapParams(ctx, new CommandOperation("", Collections.EMPTY_MAP), commands.get(0), true);
-            invokeUrl(commands.get(0), ctx);
+            wrapParams(req, new CommandOperation("", Collections.EMPTY_MAP), commands.get(0), true);
+            invokeUrl(commands.get(0), req, rsp);
           }
 
         } catch (SolrException e) {
@@ -110,7 +109,7 @@ public abstract class BaseHandlerApiSupport implements ApiSupport {
         } catch (Exception e) {
           throw new SolrException(BAD_REQUEST, e);
         } finally {
-          ctx.getSolrRequest().setParams(params);
+          req.setParams(params);
         }
 
       }
@@ -118,13 +117,13 @@ public abstract class BaseHandlerApiSupport implements ApiSupport {
 
   }
 
-  private static void wrapParams(final V2RequestContext ctx, final CommandOperation co, final V2Command cmd, final boolean useRequestParams) {
-    final Map<String, String> pathValues = ctx.getPathValues();
+  private static void wrapParams(final SolrQueryRequest req, final CommandOperation co, final ApiCommand cmd, final boolean useRequestParams) {
+    final Map<String, String> pathValues = req.getPathValues();
     final Map<String, Object> map = co == null || !(co.getCommandData() instanceof Map) ?
         Collections.emptyMap() : co.getDataMap();
-    final SolrParams origParams = ctx.getSolrRequest().getParams();
+    final SolrParams origParams = req.getParams();
 
-    ctx.getSolrRequest().setParams(
+    req.setParams(
         new SolrParams() {
           @Override
           public String get(String param) {
@@ -170,7 +169,7 @@ public abstract class BaseHandlerApiSupport implements ApiSupport {
   }
 
 
-  public static Collection<String> getParamNames(CommandOperation op, V2Command command) {
+  public static Collection<String> getParamNames(CommandOperation op, ApiCommand command) {
     List<String> result = new ArrayList<>();
     Object o = op.getCommandData();
     if (o instanceof Map) {
@@ -192,11 +191,11 @@ public abstract class BaseHandlerApiSupport implements ApiSupport {
   }
 
 
-  protected abstract void invokeCommand(V2RequestContext ctx, V2Command command, CommandOperation c) throws Exception;
+  protected abstract void invokeCommand(SolrQueryRequest  req, SolrQueryResponse rsp, ApiCommand command, CommandOperation c) throws Exception;
 
-  protected abstract void invokeUrl(V2Command command, V2RequestContext ctx) throws Exception;
+  protected abstract void invokeUrl(ApiCommand command, SolrQueryRequest req, SolrQueryResponse rsp) throws Exception;
 
-  protected abstract List<V2Command> getCommands();
+  protected abstract List<ApiCommand> getCommands();
 
   protected abstract List<V2EndPoint> getEndPoints();
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a4b5c46f/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
index 60f6bd2..fb93d4f 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/CollectionHandlerApi.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/CollectionHandlerApi.java
@@ -28,8 +28,9 @@ 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.request.SolrQueryRequest;
+import org.apache.solr.response.SolrQueryResponse;
 import org.apache.solr.util.CommandOperation;
-import org.apache.solr.api.V2RequestContext;
 
 import static org.apache.solr.client.solrj.SolrRequest.METHOD.DELETE;
 import static org.apache.solr.client.solrj.SolrRequest.METHOD.GET;
@@ -46,18 +47,18 @@ public class CollectionHandlerApi extends BaseHandlerApiSupport {
   }
 
   @Override
-  protected List<V2Command> getCommands() {
+  protected List<ApiCommand> getCommands() {
     return Arrays.asList(Cmd.values());
   }
 
   @Override
-  protected void invokeCommand(V2RequestContext ctx, V2Command command, CommandOperation c) throws Exception {
-    ((Cmd) command).command(ctx, c, this);
+  protected void invokeCommand(SolrQueryRequest req, SolrQueryResponse rsp, ApiCommand command, CommandOperation c) throws Exception {
+    ((Cmd) command).command(req, rsp,c, this);
   }
 
   @Override
-  protected void invokeUrl(V2Command command, V2RequestContext ctx) throws Exception {
-    ((Cmd) command).GET(ctx, this);
+  protected void invokeUrl(ApiCommand command, SolrQueryRequest req, SolrQueryResponse rsp) throws Exception {
+    ((Cmd) command).GET(req,rsp, this);
   }
 
   @Override
@@ -67,7 +68,7 @@ public class CollectionHandlerApi extends BaseHandlerApiSupport {
 
 
 
-  enum Cmd implements V2Command<CollectionHandlerApi> {
+  enum Cmd implements ApiCommand<CollectionHandlerApi> {
     GET_COLLECTIONS(EndPoint.COLLECTIONS, GET, LIST_OP),
     GET_A_COLLECTION(EndPoint.PER_COLLECTION, GET, LIST_OP),
     CREATE_COLLECTION(EndPoint.COLLECTIONS,
@@ -201,13 +202,13 @@ public class CollectionHandlerApi extends BaseHandlerApiSupport {
 
 
     @Override
-    public void command(V2RequestContext ctx, CommandOperation c, CollectionHandlerApi handler) throws Exception {
-      handler.handler.invokeAction(ctx.getSolrRequest(),ctx.getResponse(),target);
+    public void command(SolrQueryRequest req, SolrQueryResponse rsp, CommandOperation c, CollectionHandlerApi handler) throws Exception {
+      handler.handler.invokeAction(req,rsp,target);
     }
 
     @Override
-    public void GET(V2RequestContext ctx, CollectionHandlerApi handler) throws Exception {
-      handler.handler.invokeAction(ctx.getSolrRequest(), ctx.getResponse(), target);
+    public void GET(SolrQueryRequest req, SolrQueryResponse rsp, CollectionHandlerApi handler) throws Exception {
+      handler.handler.invokeAction(req, rsp, target);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a4b5c46f/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
index 493908d..492caaa 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandlerApi.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandlerApi.java
@@ -26,8 +26,9 @@ import java.util.Locale;
 import java.util.Map;
 
 import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.SolrQueryResponse;
 import org.apache.solr.util.CommandOperation;
-import org.apache.solr.api.V2RequestContext;
 
 import static org.apache.solr.client.solrj.SolrRequest.METHOD.*;
 import static org.apache.solr.handler.admin.CoreAdminOperation.*;
@@ -42,7 +43,7 @@ public class CoreAdminHandlerApi extends BaseHandlerApiSupport {
     this.handler = handler;
   }
 
-  enum Cmd implements V2Command<CoreAdminHandlerApi> {
+  enum Cmd implements ApiCommand<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),
@@ -103,16 +104,15 @@ public class CoreAdminHandlerApi extends BaseHandlerApiSupport {
       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 ));
+    public void command(SolrQueryRequest req, SolrQueryResponse rsp, CommandOperation c, CoreAdminHandlerApi handler) throws Exception {
+      target.call(new CoreAdminHandler.CallInfo(handler.handler,req,rsp,target ));
 
     }
 
     @Override
-    public void GET(V2RequestContext ctx, CoreAdminHandlerApi handler) throws Exception {
-      target.call(new CoreAdminHandler.CallInfo(handler.handler,ctx.getSolrRequest(),ctx.getResponse(),target ));
+    public void GET(SolrQueryRequest req, SolrQueryResponse rsp, CoreAdminHandlerApi handler) throws Exception {
+      target.call(new CoreAdminHandler.CallInfo(handler.handler,req,rsp,target ));
 
     }
 
@@ -146,18 +146,20 @@ public class CoreAdminHandlerApi extends BaseHandlerApiSupport {
     }
   }
 
+
   @Override
-  protected void invokeCommand(V2RequestContext ctx, V2Command command, CommandOperation c) throws Exception {
-    ((Cmd) command).command(ctx, c, this);
+  protected void invokeCommand(SolrQueryRequest req, SolrQueryResponse rsp, ApiCommand command,
+                               CommandOperation c) throws Exception {
+    ((Cmd) command).command(req,rsp, c, this);
   }
 
   @Override
-  protected void invokeUrl(V2Command command, V2RequestContext ctx) throws Exception {
-    command.GET(ctx, this);
+  protected void invokeUrl(ApiCommand command, SolrQueryRequest req, SolrQueryResponse rsp) throws Exception {
+    command.GET(req,rsp, this);
   }
 
   @Override
-  protected List<V2Command> getCommands() {
+  protected List<ApiCommand> getCommands() {
     return Arrays.asList(Cmd.values());
   }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a4b5c46f/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 a40579c..e69ca5d 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
@@ -33,7 +33,6 @@ import org.apache.solr.response.SolrQueryResponse;
 import org.apache.solr.api.Api;
 import org.apache.solr.api.ApiBag;
 import org.apache.solr.api.ApiSupport;
-import org.apache.solr.api.V2RequestContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -148,8 +147,9 @@ public class InfoHandler extends RequestHandlerBase implements ApiSupport {
   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());
+      public void call(SolrQueryRequest req, SolrQueryResponse rsp) {
+        handle(req, rsp, req.getPath());
+
       }
     });
   }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a4b5c46f/solr/core/src/java/org/apache/solr/handler/admin/V2Command.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/V2Command.java b/solr/core/src/java/org/apache/solr/handler/admin/V2Command.java
deleted file mode 100644
index cd66653..0000000
--- a/solr/core/src/java/org/apache/solr/handler/admin/V2Command.java
+++ /dev/null
@@ -1,42 +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.Collection;
-
-import org.apache.solr.client.solrj.SolrRequest;
-import org.apache.solr.util.CommandOperation;
-import org.apache.solr.api.V2RequestContext;
-
-public interface V2Command<T> {
-  String getName();
-
-  SolrRequest.METHOD getHttpMethod();
-
-  V2EndPoint getEndPoint();
-
-
-  void command(V2RequestContext ctx, CommandOperation c, T handler) throws Exception;
-
-  void GET(V2RequestContext ctx, T handler) throws Exception;
-
-  Collection<String> getParamNames(CommandOperation op);
-
-  String getParamSubstitute(String name);
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a4b5c46f/solr/core/src/java/org/apache/solr/request/SolrQueryRequest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/request/SolrQueryRequest.java b/solr/core/src/java/org/apache/solr/request/SolrQueryRequest.java
index ee3a18d..84148ef 100644
--- a/solr/core/src/java/org/apache/solr/request/SolrQueryRequest.java
+++ b/solr/core/src/java/org/apache/solr/request/SolrQueryRequest.java
@@ -22,9 +22,12 @@ import org.apache.solr.schema.IndexSchema;
 import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.common.util.ContentStream;
 import org.apache.solr.core.SolrCore;
+import org.apache.solr.util.CommandOperation;
 import org.apache.solr.util.RTimerTree;
 
 import java.security.Principal;
+import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -99,6 +102,22 @@ public interface SolrQueryRequest extends AutoCloseable {
   public void setJSON(Map<String,Object> json);
 
   public Principal getUserPrincipal();
+
+  default String getPath() {
+    return (String) getContext().get("path");
+  }
+
+  default Map<String, String> getPathValues() {
+    return Collections.emptyMap();
+  }
+
+  default List<CommandOperation> getCommands(boolean validateInput) {
+    return Collections.emptyList();
+  }
+
+  default String getHttpMethod() {
+    return (String) getContext().get("httpMethod");
+  }
 }
 
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a4b5c46f/solr/core/src/java/org/apache/solr/request/SolrQueryRequestBase.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/request/SolrQueryRequestBase.java b/solr/core/src/java/org/apache/solr/request/SolrQueryRequestBase.java
index 558cb87..7778654 100644
--- a/solr/core/src/java/org/apache/solr/request/SolrQueryRequestBase.java
+++ b/solr/core/src/java/org/apache/solr/request/SolrQueryRequestBase.java
@@ -17,8 +17,14 @@
 
 package org.apache.solr.request;
 
+import org.apache.solr.api.ApiBag;
+import org.apache.solr.api.V2HttpCall;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.util.Map2;
 import org.apache.solr.common.util.SuppressForbidden;
 import org.apache.solr.search.SolrIndexSearcher;
+import org.apache.solr.servlet.HttpSolrCall;
+import org.apache.solr.util.CommandOperation;
 import org.apache.solr.util.RTimerTree;
 import org.apache.solr.util.RefCounted;
 import org.apache.solr.schema.IndexSchema;
@@ -27,10 +33,15 @@ import org.apache.solr.common.util.ContentStream;
 import org.apache.solr.core.SolrCore;
 
 import java.io.Closeable;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.security.Principal;
+import java.util.List;
 import java.util.Map;
 import java.util.HashMap;
 
+import static java.nio.charset.StandardCharsets.UTF_8;
+
 /**
  * Base implementation of <code>SolrQueryRequest</code> that provides some
  * convenience methods for accessing parameters, and manages an IndexSearcher
@@ -184,4 +195,24 @@ public abstract class SolrQueryRequestBase implements SolrQueryRequest, Closeabl
   public Principal getUserPrincipal() {
     return null;
   }
+
+  List<CommandOperation> parsedCommands;
+
+  public List<CommandOperation> getCommands(boolean validateInput) {
+    if (parsedCommands == null) {
+      Iterable<ContentStream> contentStreams = getContentStreams();
+      if (contentStreams == null) throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "No content stream");
+      for (ContentStream contentStream : contentStreams) {
+        parsedCommands = ApiBag.getCommandOperations(new InputStreamReader((InputStream) contentStream, UTF_8),
+            getSpec(), validateInput);
+      }
+
+    }
+    return CommandOperation.clone(parsedCommands);
+
+  }
+
+  protected Map2 getSpec() {
+    return null;
+  }
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a4b5c46f/solr/core/src/java/org/apache/solr/schema/SchemaManager.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/schema/SchemaManager.java b/solr/core/src/java/org/apache/solr/schema/SchemaManager.java
index 1c93deb..f116890 100644
--- a/solr/core/src/java/org/apache/solr/schema/SchemaManager.java
+++ b/solr/core/src/java/org/apache/solr/schema/SchemaManager.java
@@ -72,18 +72,10 @@ public class SchemaManager {
   /**
    * Take in a JSON command set and execute them. It tries to capture as many errors
    * as possible instead of failing at the first error it encounters
-   * @param reader The input as a Reader
    * @return List of errors. If the List is empty then the operation was successful.
    */
-  public List performOperations(Reader reader) throws Exception {
-    List<CommandOperation> ops;
-    try {
-      ops = CommandOperation.parse(reader);
-    } catch (Exception e) {
-      String msg = "Error parsing schema operations ";
-      log.warn(msg, e);
-      return Collections.singletonList(singletonMap(CommandOperation.ERR_MSGS, msg + ":" + e.getMessage()));
-    }
+  public List performOperations() throws Exception {
+    List<CommandOperation> ops = req.getCommands(false);
     List errs = CommandOperation.captureErrors(ops);
     if (!errs.isEmpty()) return errs;
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a4b5c46f/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java b/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
index 5073f93..d3519dd 100644
--- a/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
+++ b/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
@@ -24,6 +24,7 @@ import javax.servlet.http.HttpServletResponse;
 import java.io.EOFException;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -59,6 +60,7 @@ import org.apache.http.client.methods.HttpPut;
 import org.apache.http.client.methods.HttpRequestBase;
 import org.apache.http.entity.InputStreamEntity;
 import org.apache.http.util.EntityUtils;
+import org.apache.solr.api.ApiBag;
 import org.apache.solr.client.solrj.impl.CloudSolrClient;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.SolrException.ErrorCode;
@@ -72,6 +74,8 @@ import org.apache.solr.common.params.CommonParams;
 import org.apache.solr.common.params.MapSolrParams;
 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.Map2;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SimpleOrderedMap;
 import org.apache.solr.common.util.StrUtils;
@@ -98,11 +102,13 @@ import org.apache.solr.servlet.SolrDispatchFilter.Action;
 import org.apache.solr.servlet.cache.HttpCacheHeaderUtil;
 import org.apache.solr.servlet.cache.Method;
 import org.apache.solr.update.processor.DistributingUpdateProcessorFactory;
+import org.apache.solr.util.CommandOperation;
 import org.apache.solr.util.RTimerTree;
 import org.apache.zookeeper.KeeperException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static java.nio.charset.StandardCharsets.UTF_8;
 import static org.apache.solr.common.cloud.ZkStateReader.BASE_URL_PROP;
 import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_PROP;
 import static org.apache.solr.common.cloud.ZkStateReader.CORE_NAME_PROP;
@@ -187,6 +193,7 @@ public class HttpSolrCall {
       // this lets you handle /update/commit when /update is a servlet
       path += req.getPathInfo();
     }
+    req.setAttribute(HttpSolrCall.class.getName(), this);
   }
 
   public String getPath() {
@@ -1071,4 +1078,24 @@ public class HttpSolrCall {
   static final String CONNECTION_HEADER = "Connection";
   static final String TRANSFER_ENCODING_HEADER = "Transfer-Encoding";
   static final String CONTENT_LENGTH_HEADER = "Content-Length";
+  List<CommandOperation> parsedCommands;
+
+  public List<CommandOperation> getCommands(boolean validateInput) {
+    if (parsedCommands == null) {
+      Iterable<ContentStream> contentStreams = solrReq.getContentStreams();
+      if (contentStreams == null) throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "No content stream");
+      for (ContentStream contentStream : contentStreams) {
+        try {
+          parsedCommands = ApiBag.getCommandOperations(contentStream.getReader(), getSpec(), validateInput);
+        } catch (IOException e) {
+          throw new SolrException(ErrorCode.BAD_REQUEST, "Error reading commands");
+        }
+        break;
+      }
+    }
+    return CommandOperation.clone(parsedCommands);
+  }
+  protected Map2 getSpec() {
+    return null;
+  }
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a4b5c46f/solr/core/src/java/org/apache/solr/servlet/SolrRequestParsers.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/servlet/SolrRequestParsers.java b/solr/core/src/java/org/apache/solr/servlet/SolrRequestParsers.java
index d8f9134..0782e8f 100644
--- a/solr/core/src/java/org/apache/solr/servlet/SolrRequestParsers.java
+++ b/solr/core/src/java/org/apache/solr/servlet/SolrRequestParsers.java
@@ -33,6 +33,7 @@ import java.security.Principal;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
@@ -43,6 +44,8 @@ import org.apache.commons.fileupload.FileItem;
 import org.apache.commons.fileupload.disk.DiskFileItemFactory;
 import org.apache.commons.fileupload.servlet.ServletFileUpload;
 import org.apache.lucene.util.IOUtils;
+import org.apache.solr.api.ApiBag;
+import org.apache.solr.api.V2HttpCall;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.SolrException.ErrorCode;
 import org.apache.solr.common.params.CommonParams;
@@ -56,6 +59,7 @@ import org.apache.solr.core.SolrConfig;
 import org.apache.solr.core.SolrCore;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.request.SolrQueryRequestBase;
+import org.apache.solr.util.CommandOperation;
 import org.apache.solr.util.RTimer;
 import org.apache.solr.util.RTimerTree;
 
@@ -177,7 +181,7 @@ public class SolrRequestParsers
                                             RTimerTree requestTimer, final HttpServletRequest req) throws Exception {
     // The content type will be applied to all streaming content
     String contentType = params.get( CommonParams.STREAM_CONTENTTYPE );
-      
+
     // Handle anything with a remoteURL
     String[] strs = params.getParams( CommonParams.STREAM_URL );
     if( strs != null ) {
@@ -220,11 +224,20 @@ public class SolrRequestParsers
       }
     }
 
+    final HttpSolrCall httpSolrCall = req == null ? null : (HttpSolrCall) req.getAttribute(HttpSolrCall.class.getName());
     SolrQueryRequestBase q = new SolrQueryRequestBase(core, params, requestTimer) {
       @Override
       public Principal getUserPrincipal() {
         return req == null ? null : req.getUserPrincipal();
       }
+
+      @Override
+      public List<CommandOperation> getCommands(boolean validateInput) {
+        if (httpSolrCall != null) {
+          return httpSolrCall.getCommands(validateInput);
+        }
+        return Collections.emptyList();
+      }
     };
     if( streams != null && streams.size() > 0 ) {
       q.setContentStreams( streams );

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a4b5c46f/solr/core/src/test/org/apache/solr/handler/admin/TestApiFramework.java
----------------------------------------------------------------------
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 496d5df..4d20475 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
@@ -17,6 +17,8 @@ package org.apache.solr.handler.admin;
  * limitations under the License.
  */
 
+import java.io.StringReader;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -37,13 +39,12 @@ import org.apache.solr.request.SolrRequestHandler;
 import org.apache.solr.response.SolrQueryResponse;
 import org.apache.solr.api.Api;
 import org.apache.solr.api.V2HttpCall;
-import org.apache.solr.api.V2RequestContext;
+import org.apache.solr.util.CommandOperation;
 
 import static org.apache.solr.client.solrj.SolrRequest.METHOD.GET;
 import static org.apache.solr.common.params.CommonParams.COLLECTIONS_HANDLER_PATH;
 import static org.apache.solr.common.params.CommonParams.CORES_HANDLER_PATH;
 import static org.apache.solr.common.util.Map2.NOT_NULL;
-import static org.apache.solr.handler.admin.TestCollectionAPIs.getV2RequestContext;
 
 public class TestApiFramework extends SolrTestCaseJ4 {
 
@@ -151,10 +152,16 @@ public class TestApiFramework extends SolrTestCaseJ4 {
     }
 
     Api api = V2HttpCall.getApiInfo(reqHandlers, path, "GET", mockCC, prefix, fullPath, parts);
-    LocalSolrQueryRequest req = new LocalSolrQueryRequest(null, new MapSolrParams(new HashMap<>()));
-    V2RequestContext ctx = getV2RequestContext( path, method, null, mockCC, parts, api, req);
-    api.call(ctx);
-    return ctx.getResponse();
+    SolrQueryResponse rsp = new SolrQueryResponse();
+    LocalSolrQueryRequest req = new LocalSolrQueryRequest(null, new MapSolrParams(new HashMap<>())){
+      @Override
+      public List<CommandOperation> getCommands(boolean validateInput) {
+        return Collections.emptyList();
+      }
+    };
+
+    api.call(req,rsp);
+    return rsp;
 
   }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a4b5c46f/solr/core/src/test/org/apache/solr/handler/admin/TestCollectionAPIs.java
----------------------------------------------------------------------
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 45d4e96..3d0c625 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
@@ -29,6 +29,7 @@ import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.client.solrj.SolrRequest;
 import org.apache.solr.common.cloud.ZkNodeProps;
 import org.apache.solr.common.params.MapSolrParams;
+import org.apache.solr.common.util.Pair;
 import org.apache.solr.common.util.Utils;
 import org.apache.solr.core.CoreContainer;
 import org.apache.solr.request.LocalSolrQueryRequest;
@@ -37,8 +38,6 @@ import org.apache.solr.response.SolrQueryResponse;
 import org.apache.solr.util.CommandOperation;
 import org.apache.solr.api.Api;
 import org.apache.solr.api.ApiBag;
-import org.apache.solr.api.V2HttpCall;
-import org.apache.solr.api.V2RequestContext;
 
 import static org.apache.solr.cloud.Overseer.QUEUE_OPERATION;
 
@@ -50,10 +49,10 @@ public class TestCollectionAPIs extends SolrTestCaseJ4 {
     Collection<Api> apis = collectionsHandler.getApis();
     for (Api api : apis) apiBag.register(api, Collections.EMPTY_MAP);
     //test a simple create collection call
-    V2RequestContext ctx = makeCall(apiBag, "/collections", SolrRequest.METHOD.POST,
+    Pair<SolrQueryRequest,SolrQueryResponse> ctx = makeCall(apiBag, "/collections", SolrRequest.METHOD.POST,
         "{create:{name:'newcoll', config:'schemaless', numShards:2, replicationFactor:2 }}", null);
     assertMapEqual((Map) Utils.fromJSONString("{name:newcoll, fromApi:'true', replicationFactor:'2', collection.configName:schemaless, numShards:'2', stateFormat:'2', operation:create}"),
-        (ZkNodeProps) ctx.getSolrRequest().getContext().get(ZkNodeProps.class.getName()));
+        (ZkNodeProps) ctx.getKey().getContext().get(ZkNodeProps.class.getName()));
 
     //test a create collection with custom properties
     ctx = makeCall(apiBag, "/collections", SolrRequest.METHOD.POST,
@@ -61,59 +60,20 @@ public class TestCollectionAPIs extends SolrTestCaseJ4 {
 
     assertMapEqual(
         (Map) Utils.fromJSONString("{name:newcoll, fromApi:'true', replicationFactor:'2', collection.configName:schemaless, numShards:'2', stateFormat:'2', operation:create, property.prop1:prop1val, property.prop2:prop2val}"),
-        (ZkNodeProps) ctx.getSolrRequest().getContext().get(ZkNodeProps.class.getName()));
+        (ZkNodeProps) ctx.getKey().getContext().get(ZkNodeProps.class.getName()));
 
   }
 
-  public static V2RequestContext makeCall(final ApiBag apiBag, final String path, final SolrRequest.METHOD method,
+  public static Pair<SolrQueryRequest, SolrQueryResponse> makeCall(final ApiBag apiBag, final String path, final SolrRequest.METHOD method,
                                     final String payload, final CoreContainer cc) throws Exception {
     final HashMap<String, String> parts = new HashMap<>();
     Api api = apiBag.lookup(path, method.toString(), parts);
     if (api == null) throw new RuntimeException("No handler at path :" + path);
-    LocalSolrQueryRequest req = new LocalSolrQueryRequest(null, new MapSolrParams(new HashMap<>()));
-    V2RequestContext ctx = getV2RequestContext(path, method, payload, cc, parts, api, req);
-    api.call(ctx);
-    return ctx;
-  }
-
-  public static V2RequestContext getV2RequestContext(final String path,
-                                                     final SolrRequest.METHOD method,
-                                                     final String payload,
-                                                     final CoreContainer cc,
-                                                     final HashMap<String, String> parts,
-                                                     final Api api,
-                                                     final LocalSolrQueryRequest req) {
-    return new V2RequestContext() {
-      SolrQueryResponse rsp = new SolrQueryResponse();
-
-      @Override
-      public SolrQueryResponse getResponse() {
-        return rsp;
-      }
-
-      @Override
-      public CoreContainer getCoreContainer() {
-        return cc;
-      }
-
-      @Override
-      public SolrQueryRequest getSolrRequest() {
-        return req;
-      }
-
-      @Override
-      public String getPath() {
-        return path;
-      }
-
-      @Override
-      public Map<String, String> getPathValues() {
-        return parts;
-      }
-
+    SolrQueryResponse rsp = new SolrQueryResponse();
+    LocalSolrQueryRequest req = new LocalSolrQueryRequest(null, new MapSolrParams(new HashMap<>())){
       @Override
       public List<CommandOperation> getCommands(boolean validateInput) {
-        return V2HttpCall.getCommandOperations(new StringReader(payload), api.getSpec(), rsp);
+        return ApiBag.getCommandOperations(new StringReader(payload), api.getSpec(),true);
       }
 
       @Override
@@ -121,6 +81,8 @@ public class TestCollectionAPIs extends SolrTestCaseJ4 {
         return method.toString();
       }
     };
+    api.call(req, rsp);
+    return new Pair<>(req,rsp);
   }
 
   private void assertMapEqual(Map expected, ZkNodeProps actual) {
@@ -134,10 +96,7 @@ public class TestCollectionAPIs extends SolrTestCaseJ4 {
   static class MockCollectionsHandler extends CollectionsHandler {
     LocalSolrQueryRequest req;
 
-    MockCollectionsHandler() {
-
-    }
-
+    MockCollectionsHandler() { }
 
     @Override
     protected void invokeAction(SolrQueryRequest req, SolrQueryResponse rsp, CollectionOperation operation) throws Exception {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a4b5c46f/solr/core/src/test/org/apache/solr/servlet/SolrRequestParserTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/servlet/SolrRequestParserTest.java b/solr/core/src/test/org/apache/solr/servlet/SolrRequestParserTest.java
index f22fe5d..79b7641 100644
--- a/solr/core/src/test/org/apache/solr/servlet/SolrRequestParserTest.java
+++ b/solr/core/src/test/org/apache/solr/servlet/SolrRequestParserTest.java
@@ -55,6 +55,7 @@ import org.apache.solr.servlet.SolrRequestParsers.MultipartRequestParser;
 import org.apache.solr.servlet.SolrRequestParsers.FormDataRequestParser;
 import org.apache.solr.servlet.SolrRequestParsers.RawRequestParser;
 import org.apache.solr.servlet.SolrRequestParsers.StandardRequestParser;
+import org.easymock.EasyMock;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -479,6 +480,7 @@ public class SolrRequestParserTest extends SolrTestCaseJ4 {
     // we dont pass a content-length to let the security mechanism limit it:
     expect(request.getQueryString()).andReturn("foo=1&bar=2").anyTimes();
     expect(request.getInputStream()).andReturn(new ByteServletInputStream(body.getBytes(StandardCharsets.US_ASCII)));
+    expect(request.getAttribute(EasyMock.anyObject(String.class))).andReturn(null).anyTimes();
     replay(request);
 
     SolrRequestParsers parsers = new SolrRequestParsers(h.getCore().getSolrConfig());
@@ -516,7 +518,7 @@ public class SolrRequestParserTest extends SolrTestCaseJ4 {
     expect(request.getRequestURI()).andReturn(uri).anyTimes();
     expect(request.getContentType()).andReturn(contentType).anyTimes();
     expect(request.getContentLength()).andReturn(contentLength).anyTimes();
-    expect(request.getAttribute(SolrRequestParsers.REQUEST_TIMER_SERVLET_ATTRIBUTE)).andReturn(null).anyTimes();
+    expect(request.getAttribute(EasyMock.anyObject(String.class))).andReturn(null).anyTimes();
     return request;
   }