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 2020/09/17 00:52:25 UTC
[lucene-solr] branch branch_8x updated: SOLR-14871: Use Annotations
for v2 APIs in /cluster path
This is an automated email from the ASF dual-hosted git repository.
noble pushed a commit to branch branch_8x
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git
The following commit(s) were added to refs/heads/branch_8x by this push:
new 298dcbf SOLR-14871: Use Annotations for v2 APIs in /cluster path
298dcbf is described below
commit 298dcbf7aad00ff44434ceacc3a89f0449ec72bf
Author: noblepaul <no...@gmail.com>
AuthorDate: Thu Sep 17 10:51:56 2020 +1000
SOLR-14871: Use Annotations for v2 APIs in /cluster path
---
.../src/java/org/apache/solr/api/AnnotatedApi.java | 12 +-
.../src/java/org/apache/solr/api/PayloadObj.java | 4 +-
.../java/org/apache/solr/core/CoreContainer.java | 4 +
.../java/org/apache/solr/handler/ClusterAPI.java | 175 +++++++++++++++++++++
.../org/apache/solr/handler/SolrConfigHandler.java | 2 +-
.../solr/handler/admin/CollectionHandlerApi.java | 53 -------
.../solr/handler/admin/CollectionsHandler.java | 27 ++--
.../java/org/apache/solr/schema/IndexSchema.java | 2 +-
.../solr/handler/admin/TestCollectionAPIs.java | 10 ++
.../client/solrj/request/CollectionApiMapping.java | 36 +----
.../solrj/request/beans/ClusterPropInfo.java | 72 +++++++++
.../solr/common/params/DefaultSolrParams.java | 2 +-
.../apache/solr/common/util/JsonSchemaCreator.java | 14 +-
.../java/org/apache/solr/common/util/Utils.java | 2 +-
.../src/resources/apispec/cluster.Commands.json | 174 --------------------
.../apispec/cluster.commandstatus.delete.json | 10 --
.../resources/apispec/cluster.commandstatus.json | 20 ---
solr/solrj/src/resources/apispec/cluster.json | 14 --
.../apache/solr/common/util/JsonValidatorTest.java | 8 -
19 files changed, 310 insertions(+), 331 deletions(-)
diff --git a/solr/core/src/java/org/apache/solr/api/AnnotatedApi.java b/solr/core/src/java/org/apache/solr/api/AnnotatedApi.java
index 7b89201..75bfd1b 100644
--- a/solr/core/src/java/org/apache/solr/api/AnnotatedApi.java
+++ b/solr/core/src/java/org/apache/solr/api/AnnotatedApi.java
@@ -38,7 +38,11 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SpecProvider;
-import org.apache.solr.common.util.*;
+import org.apache.solr.common.util.CommandOperation;
+import org.apache.solr.common.util.ContentStream;
+import org.apache.solr.common.util.JsonSchemaCreator;
+import org.apache.solr.common.util.Utils;
+import org.apache.solr.common.util.ValidatingJsonMap;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.security.AuthorizationContext;
@@ -265,6 +269,7 @@ public class AnnotatedApi extends Api implements PermissionNameProvider , Closea
@SuppressWarnings({"unchecked"})
void invoke(SolrQueryRequest req, SolrQueryResponse rsp, CommandOperation cmd) {
+ Object original = null;
try {
Object o = null;
String commandName = null;
@@ -280,12 +285,13 @@ public class AnnotatedApi extends Api implements PermissionNameProvider , Closea
}
} else {
commandName = cmd.name;
- o = cmd.getCommandData();
+ original = cmd.getCommandData();
+ o = original;
if (o instanceof Map && parameterClass != null && parameterClass != Map.class) {
o = mapper.readValue(Utils.toJSONString(o), parameterClass);
}
}
- PayloadObj<Object> payloadObj = new PayloadObj<>(commandName, o, o, req, rsp);
+ PayloadObj<Object> payloadObj = new PayloadObj<>(commandName, original, o, req, rsp);
cmd = payloadObj;
method.invoke(obj, payloadObj);
checkForErrorInPayload(cmd);
diff --git a/solr/core/src/java/org/apache/solr/api/PayloadObj.java b/solr/core/src/java/org/apache/solr/api/PayloadObj.java
index 7941304..df4c1e4 100644
--- a/solr/core/src/java/org/apache/solr/api/PayloadObj.java
+++ b/solr/core/src/java/org/apache/solr/api/PayloadObj.java
@@ -31,8 +31,8 @@ public class PayloadObj<T> extends CommandOperation {
final SolrQueryRequest req;
final SolrQueryResponse rsp;
- public PayloadObj(String operationName, Object metaData, T obj, SolrQueryRequest req, SolrQueryResponse rsp) {
- super(operationName, metaData);
+ public PayloadObj(String operationName, Object originalMetadata, T obj, SolrQueryRequest req, SolrQueryResponse rsp) {
+ super(operationName, originalMetadata);
this.obj = obj;
this.req = req;
this.rsp = rsp;
diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
index f980341..df9eef9 100644
--- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java
+++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
@@ -88,6 +88,7 @@ import org.apache.solr.core.DirectoryFactory.DirContext;
import org.apache.solr.core.backup.repository.BackupRepository;
import org.apache.solr.core.backup.repository.BackupRepositoryFactory;
import org.apache.solr.filestore.PackageStoreAPI;
+import org.apache.solr.handler.ClusterAPI;
import org.apache.solr.handler.RequestHandlerBase;
import org.apache.solr.handler.SnapShooter;
import org.apache.solr.handler.admin.AutoscalingHistoryHandler;
@@ -724,6 +725,9 @@ public class CoreContainer {
createHandler(ZK_PATH, ZookeeperInfoHandler.class.getName(), ZookeeperInfoHandler.class);
createHandler(ZK_STATUS_PATH, ZookeeperStatusHandler.class.getName(), ZookeeperStatusHandler.class);
collectionsHandler = createHandler(COLLECTIONS_HANDLER_PATH, cfg.getCollectionsHandlerClass(), CollectionsHandler.class);
+ ClusterAPI clusterAPI = new ClusterAPI(collectionsHandler);
+ containerHandlers.getApiBag().registerObject(clusterAPI);
+ containerHandlers.getApiBag().registerObject(clusterAPI.commands);
/*
* HealthCheckHandler needs to be initialized before InfoHandler, since the later one will call CoreContainer.getHealthCheckHandler().
* We don't register the handler here because it'll be registered inside InfoHandler
diff --git a/solr/core/src/java/org/apache/solr/handler/ClusterAPI.java b/solr/core/src/java/org/apache/solr/handler/ClusterAPI.java
new file mode 100644
index 0000000..8d1fcae
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/handler/ClusterAPI.java
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.handler;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.solr.api.Command;
+import org.apache.solr.api.EndPoint;
+import org.apache.solr.api.PayloadObj;
+import org.apache.solr.client.solrj.request.beans.ClusterPropInfo;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.annotation.JsonProperty;
+import org.apache.solr.common.cloud.ClusterProperties;
+import org.apache.solr.common.params.DefaultSolrParams;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.util.ReflectMapWriter;
+import org.apache.solr.common.util.Utils;
+import org.apache.solr.core.CoreContainer;
+import org.apache.solr.handler.admin.CollectionsHandler;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.SolrQueryResponse;
+
+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.cloud.api.collections.OverseerCollectionMessageHandler.REQUESTID;
+import static org.apache.solr.common.params.CollectionParams.CollectionAction.ADDROLE;
+import static org.apache.solr.common.params.CollectionParams.CollectionAction.CLUSTERPROP;
+import static org.apache.solr.common.params.CollectionParams.CollectionAction.OVERSEERSTATUS;
+import static org.apache.solr.common.params.CollectionParams.CollectionAction.REMOVEROLE;
+import static org.apache.solr.security.PermissionNameProvider.Name.COLL_EDIT_PERM;
+import static org.apache.solr.security.PermissionNameProvider.Name.COLL_READ_PERM;
+
+public class ClusterAPI {
+ private final CoreContainer coreContainer;
+ private final CollectionsHandler collectionsHandler;
+
+ public final Commands commands = new Commands();
+
+ public ClusterAPI(CollectionsHandler ch) {
+ this.collectionsHandler = ch;
+ this.coreContainer = ch.getCoreContainer();
+ }
+
+
+ @EndPoint(method = GET,
+ path = "/cluster/overseer",
+ permission = COLL_READ_PERM)
+ public void getOverseerStatus(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception {
+ coreContainer.getCollectionsHandler().handleRequestBody(wrapParams(req, "action", OVERSEERSTATUS.toString()), rsp);
+ }
+
+ @EndPoint(method = GET,
+ path = "/cluster",
+ permission = COLL_READ_PERM)
+ public void getCluster(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception {
+ CollectionsHandler.CollectionOperation.LIST_OP.execute(req, rsp, coreContainer.getCollectionsHandler());
+ }
+
+ @EndPoint(method = DELETE,
+ path = "/cluster/command-status/{id}",
+ permission = COLL_EDIT_PERM)
+ public void deleteCommandStatus(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception {
+ wrapParams(req, REQUESTID, req.getPathTemplateValues().get("id"));
+ CollectionsHandler.CollectionOperation.DELETESTATUS_OP.execute(req, rsp, coreContainer.getCollectionsHandler());
+ }
+
+ @SuppressWarnings({"rawtypes"})
+ public static SolrQueryRequest wrapParams(SolrQueryRequest req, Object... def) {
+ Map m = Utils.makeMap(def);
+ return wrapParams(req, m);
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ public static SolrQueryRequest wrapParams(SolrQueryRequest req, Map m) {
+ ModifiableSolrParams solrParams = new ModifiableSolrParams();
+ m.forEach((k, v) -> {
+ if(v == null) return;
+ solrParams.add(k.toString(), String.valueOf(v));
+ });
+ DefaultSolrParams dsp = new DefaultSolrParams(req.getParams(),solrParams);
+ req.setParams(dsp);
+ return req;
+ }
+
+ @EndPoint(method = GET,
+ path = "/cluster/command-status",
+ permission = COLL_READ_PERM)
+ public void getCommandStatus(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception {
+ CollectionsHandler.CollectionOperation.REQUESTSTATUS_OP.execute(req, rsp, collectionsHandler);
+ }
+
+ @EndPoint(method = GET,
+ path = "/cluster/nodes",
+ permission = COLL_READ_PERM)
+ public void getNodes(SolrQueryRequest req, SolrQueryResponse rsp) {
+ rsp.add("nodes", coreContainer.getZkController().getClusterState().getLiveNodes());
+ }
+
+ @EndPoint(method = POST,
+ path = "/cluster",
+ permission = COLL_EDIT_PERM)
+ public class Commands {
+
+
+ @Command(name = "add-role")
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public void addRole(PayloadObj<RoleInfo> obj) throws Exception {
+ RoleInfo info = obj.get();
+ Map m = info.toMap(new HashMap<>());
+ m.put("action", ADDROLE.toString());
+ collectionsHandler.handleRequestBody(wrapParams(obj.getRequest(), m), obj.getResponse());
+ }
+
+ @Command(name = "remove-role")
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public void removeRole(PayloadObj<RoleInfo> obj) throws Exception {
+ RoleInfo info = obj.get();
+ Map m = info.toMap(new HashMap<>());
+ m.put("action", REMOVEROLE.toString());
+ collectionsHandler.handleRequestBody(wrapParams(obj.getRequest(),m), obj.getResponse());
+
+ }
+
+ @Command(name = "set-obj-property")
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public void setObjProperty(PayloadObj<ClusterPropInfo> obj) {
+ //Not using the object directly here because the API differentiate between {name:null} and {}
+ Map m = obj.getDataMap();
+ ClusterProperties clusterProperties = new ClusterProperties(coreContainer.getZkController().getZkClient());
+ try {
+ clusterProperties.setClusterProperties(m);
+ } catch (Exception e) {
+ throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Error in API", e);
+ }
+
+ }
+
+ @Command(name = "set-property")
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public void setProperty(PayloadObj<Map<String,String>> obj) throws Exception {
+ Map m = obj.get();
+ m.put("action", CLUSTERPROP.toString());
+ collectionsHandler.handleRequestBody(wrapParams(obj.getRequest(),m ), obj.getResponse());
+
+ }
+
+ }
+
+ public static class RoleInfo implements ReflectMapWriter {
+ @JsonProperty(required = true)
+ public String node;
+ @JsonProperty(required = true)
+ public String role;
+
+ }
+
+
+}
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 1c0c709..9ac6207 100644
--- a/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
@@ -60,6 +60,7 @@ import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.CommandOperation;
import org.apache.solr.common.util.ExecutorUtil;
import org.apache.solr.common.util.NamedList;
+import org.apache.solr.common.util.SolrNamedThreadFactory;
import org.apache.solr.common.util.StrUtils;
import org.apache.solr.common.util.Utils;
import org.apache.solr.core.ConfigOverlay;
@@ -77,7 +78,6 @@ import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.schema.SchemaManager;
import org.apache.solr.security.AuthorizationContext;
import org.apache.solr.security.PermissionNameProvider;
-import org.apache.solr.common.util.SolrNamedThreadFactory;
import org.apache.solr.util.RTimer;
import org.apache.solr.util.SolrPluginUtils;
import org.apache.solr.util.plugin.SolrCoreAware;
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 b63f7bd..fe856df 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
@@ -17,7 +17,6 @@
package org.apache.solr.handler.admin;
-import java.lang.invoke.MethodHandles;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumMap;
@@ -28,18 +27,11 @@ import org.apache.solr.client.solrj.request.CollectionApiMapping;
import org.apache.solr.client.solrj.request.CollectionApiMapping.CommandMeta;
import org.apache.solr.client.solrj.request.CollectionApiMapping.Meta;
import org.apache.solr.client.solrj.request.CollectionApiMapping.V2EndPoint;
-import org.apache.solr.common.Callable;
-import org.apache.solr.common.SolrException;
-import org.apache.solr.common.cloud.ClusterProperties;
-import org.apache.solr.common.util.CommandOperation;
import org.apache.solr.handler.admin.CollectionsHandler.CollectionOperation;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
public class CollectionHandlerApi extends BaseHandlerApiSupport {
- private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
final CollectionsHandler handler;
static Collection<ApiCommand> apiCommands = createCollMapping();
@@ -64,55 +56,10 @@ public class CollectionHandlerApi extends BaseHandlerApiSupport {
}
}
}
- //The following APIs have only V2 implementations
- addApi(result, Meta.GET_NODES, params -> params.rsp.add("nodes", ((CollectionHandlerApi) params.apiHandler).handler.coreContainer.getZkController().getClusterState().getLiveNodes()));
- addApi(result, Meta.SET_CLUSTER_PROPERTY_OBJ, params -> {
- List<CommandOperation> commands = params.req.getCommands(true);
- if (commands == null || commands.isEmpty()) throw new RuntimeException("Empty commands");
- ClusterProperties clusterProperties = new ClusterProperties(((CollectionHandlerApi) params.apiHandler).handler.coreContainer.getZkController().getZkClient());
-
- try {
- clusterProperties.setClusterProperties(commands.get(0).getDataMap());
- } catch (Exception e) {
- throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Error in API", e);
- }
- });
-
- for (Meta meta : Meta.values()) {
- if (result.get(meta) == null) {
- log.error("ERROR_INIT. No corresponding API implementation for : {}", meta.commandName);
- }
- }
return result.values();
}
- private static void addApi(Map<Meta, ApiCommand> result, Meta metaInfo, Callable<ApiParams> fun) {
- result.put(metaInfo, new ApiCommand() {
- @Override
- public CommandMeta meta() {
- return metaInfo;
- }
-
- @Override
- public void invoke(SolrQueryRequest req, SolrQueryResponse rsp, BaseHandlerApiSupport apiHandler) throws Exception {
- fun.call(new ApiParams(req, rsp, apiHandler));
- }
- });
- }
-
- static class ApiParams {
- final SolrQueryRequest req;
- final SolrQueryResponse rsp;
- final BaseHandlerApiSupport apiHandler;
-
- ApiParams(SolrQueryRequest req, SolrQueryResponse rsp, BaseHandlerApiSupport apiHandler) {
- this.req = req;
- this.rsp = rsp;
- this.apiHandler = apiHandler;
- }
- }
-
public CollectionHandlerApi(CollectionsHandler handler) {
this.handler = handler;
}
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 42df2e5..c753c59 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
@@ -228,17 +228,7 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
@Override
public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception {
// Make sure the cores is enabled
- CoreContainer cores = getCoreContainer();
- if (cores == null) {
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
- "Core container instance missing");
- }
-
- // Make sure that the core is ZKAware
- if (!cores.isZooKeeperAware()) {
- throw new SolrException(ErrorCode.BAD_REQUEST,
- "Solr instance is not running in SolrCloud mode.");
- }
+ CoreContainer cores = checkErrors();
// Pick the action
SolrParams params = req.getParams();
@@ -261,6 +251,21 @@ public class CollectionsHandler extends RequestHandlerBase implements Permission
rsp.setHttpCaching(false);
}
+ protected CoreContainer checkErrors() {
+ CoreContainer cores = getCoreContainer();
+ if (cores == null) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,
+ "Core container instance missing");
+ }
+
+ // Make sure that the core is ZKAware
+ if (!cores.isZooKeeperAware()) {
+ throw new SolrException(ErrorCode.BAD_REQUEST,
+ "Solr instance is not running in SolrCloud mode.");
+ }
+ return cores;
+ }
+
@SuppressWarnings({"unchecked"})
void invokeAction(SolrQueryRequest req, SolrQueryResponse rsp, CoreContainer cores, CollectionAction action, CollectionOperation operation) throws Exception {
if (!coreContainer.isZooKeeperAware()) {
diff --git a/solr/core/src/java/org/apache/solr/schema/IndexSchema.java b/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
index 83dccd5..bd4ae7e 100644
--- a/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
+++ b/solr/core/src/java/org/apache/solr/schema/IndexSchema.java
@@ -54,6 +54,7 @@ import org.apache.solr.common.MapSerializable;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
+import org.apache.solr.common.cloud.SolrClassLoader;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.MapSolrParams;
import org.apache.solr.common.params.ModifiableSolrParams;
@@ -62,7 +63,6 @@ import org.apache.solr.common.util.Cache;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.Pair;
import org.apache.solr.common.util.SimpleOrderedMap;
-import org.apache.solr.common.cloud.SolrClassLoader;
import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrResourceLoader;
import org.apache.solr.core.XmlConfigFile;
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 78bf879..2b342ec 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
@@ -40,6 +40,7 @@ import org.apache.solr.common.util.ContentStreamBase;
import org.apache.solr.common.util.Pair;
import org.apache.solr.common.util.Utils;
import org.apache.solr.core.CoreContainer;
+import org.apache.solr.handler.ClusterAPI;
import org.apache.solr.request.LocalSolrQueryRequest;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
@@ -84,6 +85,10 @@ public class TestCollectionAPIs extends SolrTestCaseJ4 {
apiBag = new ApiBag(false);
Collection<Api> apis = collectionsHandler.getApis();
for (Api api : apis) apiBag.register(api, Collections.emptyMap());
+
+ ClusterAPI clusterAPI = new ClusterAPI(collectionsHandler);
+ apiBag.registerObject(clusterAPI);
+ apiBag.registerObject(clusterAPI.commands);
}
//test a simple create collection call
compareOutput(apiBag, "/collections", POST,
@@ -278,6 +283,11 @@ public class TestCollectionAPIs extends SolrTestCaseJ4 {
}
@Override
+ protected CoreContainer checkErrors() {
+ return null;
+ }
+
+ @Override
protected void copyFromClusterProp(Map<String, Object> props, String prop) {
}
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/request/CollectionApiMapping.java b/solr/solrj/src/java/org/apache/solr/client/solrj/request/CollectionApiMapping.java
index 5df18e0..9d35e40 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/request/CollectionApiMapping.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/request/CollectionApiMapping.java
@@ -41,12 +41,7 @@ import static org.apache.solr.client.solrj.SolrRequest.METHOD.POST;
import static org.apache.solr.client.solrj.request.CollectionApiMapping.ConfigSetEndPoint.CONFIG_COMMANDS;
import static org.apache.solr.client.solrj.request.CollectionApiMapping.ConfigSetEndPoint.CONFIG_DEL;
import static org.apache.solr.client.solrj.request.CollectionApiMapping.ConfigSetEndPoint.LIST_CONFIG;
-import static org.apache.solr.client.solrj.request.CollectionApiMapping.EndPoint.CLUSTER;
import static org.apache.solr.client.solrj.request.CollectionApiMapping.EndPoint.CLUSTER_ALIASES;
-import static org.apache.solr.client.solrj.request.CollectionApiMapping.EndPoint.CLUSTER_CMD;
-import static org.apache.solr.client.solrj.request.CollectionApiMapping.EndPoint.CLUSTER_CMD_STATUS;
-import static org.apache.solr.client.solrj.request.CollectionApiMapping.EndPoint.CLUSTER_CMD_STATUS_DELETE;
-import static org.apache.solr.client.solrj.request.CollectionApiMapping.EndPoint.CLUSTER_NODES;
import static org.apache.solr.client.solrj.request.CollectionApiMapping.EndPoint.COLLECTIONS;
import static org.apache.solr.client.solrj.request.CollectionApiMapping.EndPoint.COLLECTIONS_COMMANDS;
import static org.apache.solr.client.solrj.request.CollectionApiMapping.EndPoint.COLLECTION_STATE;
@@ -66,10 +61,6 @@ public class CollectionApiMapping {
public enum Meta implements CommandMeta {
GET_COLLECTIONS(COLLECTIONS, GET, LIST),
- GET_CLUSTER(CLUSTER, GET, LIST, "/cluster", null),
- GET_CLUSTER_OVERSEER(CLUSTER, GET, OVERSEERSTATUS, "/cluster/overseer", null),
- GET_CLUSTER_STATUS_CMD(CLUSTER_CMD_STATUS, GET, REQUESTSTATUS),
- DELETE_CLUSTER_STATUS(CLUSTER_CMD_STATUS_DELETE, DELETE, DELETESTATUS),
GET_A_COLLECTION(COLLECTION_STATE, GET, CLUSTERSTATUS),
LIST_ALIASES(CLUSTER_ALIASES, GET, LISTALIASES),
CREATE_COLLECTION(COLLECTIONS_COMMANDS,
@@ -190,28 +181,23 @@ public class CollectionApiMapping {
NAME, "collection",
"propertyName", "name",
"propertyValue", "value")),
- ADD_ROLE(CLUSTER_CMD,
+/* ADD_ROLE(CLUSTER_CMD,
POST,
ADDROLE,
- "add-role",null),
- REMOVE_ROLE(CLUSTER_CMD,
+ "add-role",null),*/
+/* REMOVE_ROLE(CLUSTER_CMD,
POST,
REMOVEROLE,
- "remove-role",null),
+ "remove-role",null),*/
- SET_CLUSTER_PROPERTY(CLUSTER_CMD,
+ /* SET_CLUSTER_PROPERTY(CLUSTER_CMD,
POST,
CLUSTERPROP,
- "set-property",null),
- SET_CLUSTER_PROPERTY_OBJ(CLUSTER_CMD,
+ "set-property",null),*/
+ /* SET_CLUSTER_PROPERTY_OBJ(CLUSTER_CMD,
POST,
null,
- "set-obj-property", null),
- UTILIZE_NODE(CLUSTER_CMD,
- POST,
- UTILIZENODE,
- "utilize-node",null),
-
+ "set-obj-property", null),*/
BACKUP_COLLECTION(COLLECTIONS_COMMANDS,
POST,
BACKUP,
@@ -223,7 +209,6 @@ public class CollectionApiMapping {
"restore-collection",
null
),
- GET_NODES(CLUSTER_NODES, GET, null),
FORCE_LEADER(PER_COLLECTION_PER_SHARD_COMMANDS, POST, CollectionAction.FORCELEADER, "force-leader", null),
BALANCE_SHARD_UNIQUE(PER_COLLECTION, POST, BALANCESHARDUNIQUE,"balance-shard-unique" , null)
;
@@ -347,12 +332,7 @@ public class CollectionApiMapping {
}
public enum EndPoint implements V2EndPoint {
- CLUSTER("cluster"),
CLUSTER_ALIASES("cluster.aliases"),
- CLUSTER_CMD("cluster.Commands"),
- CLUSTER_NODES("cluster.nodes"),
- CLUSTER_CMD_STATUS("cluster.commandstatus"),
- CLUSTER_CMD_STATUS_DELETE("cluster.commandstatus.delete"),
COLLECTIONS_COMMANDS("collections.Commands"),
COLLECTIONS("collections"),
COLLECTION_STATE("collections.collection"),
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/ClusterPropInfo.java b/solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/ClusterPropInfo.java
new file mode 100644
index 0000000..fe768be
--- /dev/null
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/ClusterPropInfo.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.client.solrj.request.beans;
+
+import org.apache.solr.common.annotation.JsonProperty;
+import org.apache.solr.common.util.ReflectMapWriter;
+
+public class ClusterPropInfo implements ReflectMapWriter {
+
+ @JsonProperty
+ public String urlScheme;
+
+ @JsonProperty
+ public Integer maxCoresPerNode;
+ @JsonProperty
+ public String location;
+
+ @JsonProperty
+ public DefaultsInfo defaults;
+
+ @JsonProperty
+ public CollectionDefaults collectionDefaults;
+
+ public static class CollectionDefaults implements ReflectMapWriter {
+ @JsonProperty
+ public Integer numShards;
+ @JsonProperty
+ public Integer tlogReplicas;
+ @JsonProperty
+ public Integer pullReplicas;
+ @JsonProperty
+ public Integer nrtReplicas;
+
+ }
+
+ public static class DefaultsInfo implements ReflectMapWriter {
+
+ @JsonProperty
+ public CollectionDefaults collection;
+
+ @JsonProperty
+ public CollectionDefaults cluster;
+
+ }
+
+ public static class ClusterInfo implements ReflectMapWriter {
+ @JsonProperty
+ public Boolean useLegacyReplicaAssignment;
+
+
+ @JsonProperty
+ public CollectionDefaults collection;
+
+ }
+
+
+}
diff --git a/solr/solrj/src/java/org/apache/solr/common/params/DefaultSolrParams.java b/solr/solrj/src/java/org/apache/solr/common/params/DefaultSolrParams.java
index c8bc3b0..bec6266 100644
--- a/solr/solrj/src/java/org/apache/solr/common/params/DefaultSolrParams.java
+++ b/solr/solrj/src/java/org/apache/solr/common/params/DefaultSolrParams.java
@@ -27,7 +27,7 @@ public class DefaultSolrParams extends SolrParams {
protected final SolrParams params;
protected final SolrParams defaults;
- protected DefaultSolrParams(SolrParams params, SolrParams defaults) {
+ public DefaultSolrParams(SolrParams params, SolrParams defaults) {
assert params != null && defaults != null;
this.params = params;
this.defaults = defaults;
diff --git a/solr/solrj/src/java/org/apache/solr/common/util/JsonSchemaCreator.java b/solr/solrj/src/java/org/apache/solr/common/util/JsonSchemaCreator.java
index defd33d..e6cef30 100644
--- a/solr/solrj/src/java/org/apache/solr/common/util/JsonSchemaCreator.java
+++ b/solr/solrj/src/java/org/apache/solr/common/util/JsonSchemaCreator.java
@@ -58,10 +58,16 @@ public class JsonSchemaCreator {
private static Map<String, Object> createSchemaFromType(java.lang.reflect.Type t, Map<String, Object> map) {
if (natives.containsKey(t)) {
map.put("type", natives.get(t));
- } else if (t instanceof ParameterizedType && ((ParameterizedType) t).getRawType() == List.class) {
- Type typ = ((ParameterizedType) t).getActualTypeArguments()[0];
- map.put("type", "array");
- map.put("items", getSchema(typ));
+ } else if (t instanceof ParameterizedType) {
+ if (((ParameterizedType) t).getRawType() == List.class) {
+ Type typ = ((ParameterizedType) t).getActualTypeArguments()[0];
+ map.put("type", "array");
+ map.put("items", getSchema(typ));
+ } else if (((ParameterizedType) t).getRawType() == Map.class) {
+ Type typ = ((ParameterizedType) t).getActualTypeArguments()[0];
+ map.put("type", "object");
+ map.put("additionalProperties", true);
+ }
} else {
createObjectSchema((Class) t, map);
}
diff --git a/solr/solrj/src/java/org/apache/solr/common/util/Utils.java b/solr/solrj/src/java/org/apache/solr/common/util/Utils.java
index 1437111..08e96e5 100644
--- a/solr/solrj/src/java/org/apache/solr/common/util/Utils.java
+++ b/solr/solrj/src/java/org/apache/solr/common/util/Utils.java
@@ -877,7 +877,7 @@ public class Utils {
l.add((ew, inst) -> ew.put(fname, (float) mh.invoke(inst)));
} else {
MethodHandle mh = lookup.findGetter(c, field.getName(), field.getType());
- l.add((ew, inst) -> ew.put(fname, mh.invoke(inst)));
+ l.add((ew, inst) -> ew.putIfNotNull(fname, mh.invoke(inst)));
}
} catch (NoSuchFieldException e) {
//this is unlikely
diff --git a/solr/solrj/src/resources/apispec/cluster.Commands.json b/solr/solrj/src/resources/apispec/cluster.Commands.json
deleted file mode 100644
index 069cd1d..0000000
--- a/solr/solrj/src/resources/apispec/cluster.Commands.json
+++ /dev/null
@@ -1,174 +0,0 @@
-{
- "documentation": "https://lucene.apache.org/solr/guide/cluster-node-management.html",
- "description": "Cluster-wide commands to assign roles to nodes, remove role assignments, or add, edit or remove a cluster-wide property.",
- "methods": [
- "POST"
- ],
- "url": {
- "paths": [
- "/cluster"
- ]
- },
- "commands": {
- "add-role":{
- "type":"object",
- "documentation":"https://lucene.apache.org/solr/guide/cluster-node-management.html#addrole",
- "description":"Assign a specific role to a node in the cluster.",
- "properties": {
- "role": {
- "type": "string",
- "description": "The name of the role. The only supported role is 'overseer'."
-
- },
- "node": {
- "type": "string",
- "description": "The name of the node. It is possible to assign a role even before that node is started."
-
- }
- },
- "required": [
- "role",
- "node"
- ]
- },
- "remove-role":{
- "type":"object",
- "documentation":"https://lucene.apache.org/solr/guide/cluster-node-management.html#removerole",
- "description":"Unassign a role from a node in the cluster.",
- "properties": {
- "role": {
- "type": "string",
- "description": "The name of the role. The only supported role as of now is 'overseer'."
-
- },
- "node": {
- "type": "string",
- "description": "The name of the node where the role should be removed."
- }
- },
- "required": [
- "role",
- "node"
- ]
- },
- "set-property": {
- "type": "object",
- "documentation": "https://lucene.apache.org/solr/guide/cluster-node-management.html#clusterprop",
- "description": "Add, edit, or delete a cluster-wide property.",
- "properties": {
- "name": {
- "type": "string",
- "description": "The name of the property"
- },
- "val": {
- "type": ["string","boolean","null"],
- "description": "The value of the property. If the value is empty or null, the property is unset."
- }
- },
- "required": [
- "name",
- "val"
- ]
- },
- "set-obj-property": {
- "type": "object",
- "documentation": "https://lucene.apache.org/solr/guide/cluster-node-management.html#clusterprop",
- "description": "Add, edit, or delete a cluster-wide property.",
- "properties": {
- "legacyCloud": {
- "type": "boolean"
- },
- "urlScheme": {
- "type": "string"
- },
- "autoAddReplicas": {
- "type": "boolean"
- },
- "maxCoresPerNode": {
- "type": "boolean"
- },
- "location": {
- "type": "string"
- },
- "defaults" : {
- "type" : "object",
- "properties": {
- "cluster": {
- "type" : "object",
- "properties": {
- "useLegacyReplicaAssignment": {
- "type" : "boolean",
- "description" : "Decides wheyher to use the deprecated legacy replica assignment strategy or not"
- }
- }
- },
- "collection": {
- "type": "object",
- "properties": {
- "numShards": {
- "type": "integer",
- "description": "Default number of shards for a collection"
- },
- "tlogReplicas": {
- "type": "integer",
- "description": "Default number of TLOG replicas"
- },
- "pullReplicas": {
- "type": "integer",
- "description": "Default number of PULL replicas"
- },
- "nrtReplicas": {
- "type": "integer",
- "description": "Default number of NRT replicas"
- }
- }
- }
- }
- },
- "collectionDefaults": {
- "type": "object",
- "properties": {
- "numShards": {
- "type": "integer",
- "description": "Default number of shards for a collection"
- },
- "tlogReplicas": {
- "type": "integer",
- "description": "Default number of TLOG replicas"
- },
- "pullReplicas": {
- "type": "integer",
- "description": "Default number of PULL replicas"
- },
- "nrtReplicas": {
- "type": "integer",
- "description": "Default number of NRT replicas"
- }
- }
- }
- }
- },
- "utilize-node": {
- "type": "object",
- "documentation": "https://lucene.apache.org/solr/guide/cluster-node-management.html#utilizenode",
- "description": "use a replica to reduce load",
- "properties": {
- "node": {
- "type": "string",
- "description": "The name of the node"
- },
- "async": {
- "type": [
- "string",
- "boolean",
- "null"
- ],
- "description": "The value of the property. If the value is empty or null, the property is unset."
- }
- },
- "required": [
- "name"
- ]
- }
- }
-}
diff --git a/solr/solrj/src/resources/apispec/cluster.commandstatus.delete.json b/solr/solrj/src/resources/apispec/cluster.commandstatus.delete.json
deleted file mode 100644
index 5576c42..0000000
--- a/solr/solrj/src/resources/apispec/cluster.commandstatus.delete.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "methods": [
- "DELETE"
- ],
- "url": {
- "paths": [
- "/cluster/command-status/{id}"
- ]
- }
-}
diff --git a/solr/solrj/src/resources/apispec/cluster.commandstatus.json b/solr/solrj/src/resources/apispec/cluster.commandstatus.json
deleted file mode 100644
index a8a402b..0000000
--- a/solr/solrj/src/resources/apispec/cluster.commandstatus.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "methods": [
- "GET"
- ],
- "url": {
- "paths": [
- "/cluster/command-status"
- ],
- "params": {
- "flush": {
- "type": "boolean",
- "default": false
- },
- "id":{
- "type":"string",
- "description": "The command id"
- }
- }
- }
-}
diff --git a/solr/solrj/src/resources/apispec/cluster.json b/solr/solrj/src/resources/apispec/cluster.json
deleted file mode 100644
index 028869d..0000000
--- a/solr/solrj/src/resources/apispec/cluster.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "documentation": "https://lucene.apache.org/solr/guide/cluster-node-management.html",
- "description": "General information about the cluster, including defined collections (with the 'cluster' endpoint), status of the overseer (with the 'cluster/overseer' endpoint), and available nodes (with the 'cluster/nodes' endpoint).",
- "methods": [
- "GET"
- ],
- "url": {
- "paths": [
- "/cluster",
- "/cluster/overseer",
- "/cluster/nodes"
- ]
- }
-}
diff --git a/solr/solrj/src/test/org/apache/solr/common/util/JsonValidatorTest.java b/solr/solrj/src/test/org/apache/solr/common/util/JsonValidatorTest.java
index 404661a..b4807e3 100644
--- a/solr/solrj/src/test/org/apache/solr/common/util/JsonValidatorTest.java
+++ b/solr/solrj/src/test/org/apache/solr/common/util/JsonValidatorTest.java
@@ -40,7 +40,6 @@ public class JsonValidatorTest extends SolrTestCaseJ4 {
checkSchema("core.config.Commands");
checkSchema("core.SchemaEdit");
checkSchema("cluster.configs.Commands");
- checkSchema("cluster.Commands");
}
@@ -173,13 +172,6 @@ public class JsonValidatorTest extends SolrTestCaseJ4 {
}
- public void testNullObjectValue() {
- ValidatingJsonMap spec = Utils.getSpec("cluster.Commands").getSpec();
- JsonSchemaValidator validator = new JsonSchemaValidator((Map) Utils.getObjectByPath(spec, false, "/commands/set-obj-property"));
- List<String> object = validator.validateJson(Utils.fromJSONString("{collectionDefaults: null}"));
- assertNull(object);
- }
-
private void checkSchema(String name) {
ValidatingJsonMap spec = Utils.getSpec(name).getSpec();
@SuppressWarnings({"rawtypes"})