SOLR-14871 Use Annotations for v2 APIs in/cluster path (#1878)

This commit is contained in:
Noble Paul 2020-09-16 18:06:43 +10:00 committed by GitHub
parent 9b9b0a6339
commit 7b8e72e553
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 329 additions and 309 deletions

View File

@ -37,7 +37,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;
@ -267,6 +271,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;
@ -282,12 +287,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);

View File

@ -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;

View File

@ -87,6 +87,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.CollectionsHandler;
@ -719,6 +720,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

View File

@ -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;
}
}

View File

@ -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;
@ -76,7 +77,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;

View File

@ -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;
}

View File

@ -16,6 +16,24 @@
*/
package org.apache.solr.handler.admin;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.net.URI;
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.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import org.apache.commons.io.IOUtils;
@ -83,24 +101,6 @@ import org.apache.zookeeper.KeeperException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.net.URI;
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.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
import static org.apache.solr.client.solrj.response.RequestStatusState.COMPLETED;
import static org.apache.solr.client.solrj.response.RequestStatusState.FAILED;
import static org.apache.solr.client.solrj.response.RequestStatusState.NOT_FOUND;
@ -223,17 +223,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();
@ -256,6 +246,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()) {

View File

@ -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;

View File

@ -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,
@ -277,6 +282,11 @@ public class TestCollectionAPIs extends SolrTestCaseJ4 {
MockCollectionsHandler() {
}
@Override
protected CoreContainer checkErrors() {
return null;
}
@Override
protected void copyFromClusterProp(Map<String, Object> props, String prop) {

View File

@ -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,23 +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),
"set-obj-property", null),*/
BACKUP_COLLECTION(COLLECTIONS_COMMANDS,
POST,
BACKUP,
@ -218,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)
;
@ -342,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"),

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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);
}

View File

@ -871,7 +871,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

View File

@ -1,146 +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": {
"urlScheme": {
"type": "string"
},
"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"
}
}
}
}
}
}
}

View File

@ -1,10 +0,0 @@
{
"methods": [
"DELETE"
],
"url": {
"paths": [
"/cluster/command-status/{id}"
]
}
}

View File

@ -1,20 +0,0 @@
{
"methods": [
"GET"
],
"url": {
"paths": [
"/cluster/command-status"
],
"params": {
"flush": {
"type": "boolean",
"default": false
},
"id":{
"type":"string",
"description": "The command id"
}
}
}
}

View File

@ -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"
]
}
}

View File

@ -40,7 +40,7 @@ public class JsonValidatorTest extends SolrTestCaseJ4 {
checkSchema("core.config.Commands");
checkSchema("core.SchemaEdit");
checkSchema("cluster.configs.Commands");
checkSchema("cluster.Commands");
// checkSchema("cluster.Commands");
}