From c1277cda1116a44b3371a3fa8364cc2032e14273 Mon Sep 17 00:00:00 2001 From: Alan Woodward Date: Mon, 7 Mar 2016 19:53:09 +0000 Subject: [PATCH] SOLR-8765: Enforce required parameters in SolrJ Collections API --- solr/CHANGES.txt | 4 + .../org/apache/solr/core/CoreContainer.java | 9 +- .../handler/admin/CollectionsHandler.java | 101 ++-- .../apache/solr/cloud/DeleteStatusTest.java | 156 +++-- .../solrj/request/CollectionAdminRequest.java | 546 ++++++++++++++++-- .../solrj/request/CoreAdminRequest.java | 23 +- .../solrj/util/SolrIdentifierValidator.java | 26 +- 7 files changed, 666 insertions(+), 199 deletions(-) diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index 5ee5b979aa0..feb0e10dc2e 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -24,6 +24,10 @@ Detailed Change List .processAndWait() to wait for a call to finish without holding HTTP collections open. (Alan Woodward) +* SOLR-8765: Enforce required parameters at query construction time in the SolrJ + Collections API, add static factory methods, and deprecate old setter methods. + (Alan Woodward, Jason Gerlowski) + New Features ---------------------- 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 9ff45eaf1c2..1d614e343dc 100644 --- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java +++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java @@ -804,9 +804,7 @@ public class CoreContainer { SolrCore core = null; try { MDCLoggingContext.setCore(core); - if (!SolrIdentifierValidator.validateCoreName(dcore.getName())) { - throw new SolrException(ErrorCode.BAD_REQUEST, SolrIdentifierValidator.getIdentifierMessage(SolrIdentifierValidator.IdentifierType.CORE, dcore.getName())); - } + SolrIdentifierValidator.validateCoreName(dcore.getName()); if (zkSys.getZkController() != null) { zkSys.getZkController().preRegister(dcore); } @@ -1009,10 +1007,7 @@ public class CoreContainer { } public void rename(String name, String toName) { - if (!SolrIdentifierValidator.validateCoreName(toName)) { - throw new SolrException(ErrorCode.BAD_REQUEST, SolrIdentifierValidator.getIdentifierMessage(SolrIdentifierValidator.IdentifierType.CORE, - toName)); - } + SolrIdentifierValidator.validateCoreName(toName); try (SolrCore core = getCore(name)) { if (core != null) { registerCore(toName, core, true); 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 593dac81bcc..06968c38148 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 @@ -16,45 +16,8 @@ */ package org.apache.solr.handler.admin; -import static org.apache.solr.client.solrj.response.RequestStatusState.*; -import static org.apache.solr.cloud.Overseer.QUEUE_OPERATION; -import static org.apache.solr.cloud.OverseerCollectionMessageHandler.COLL_CONF; -import static org.apache.solr.cloud.OverseerCollectionMessageHandler.COLL_PROP_PREFIX; -import static org.apache.solr.cloud.OverseerCollectionMessageHandler.CREATE_NODE_SET; -import static org.apache.solr.cloud.OverseerCollectionMessageHandler.CREATE_NODE_SET_SHUFFLE; -import static org.apache.solr.cloud.OverseerCollectionMessageHandler.NUM_SLICES; -import static org.apache.solr.cloud.OverseerCollectionMessageHandler.ONLY_ACTIVE_NODES; -import static org.apache.solr.cloud.OverseerCollectionMessageHandler.ONLY_IF_DOWN; -import static org.apache.solr.cloud.OverseerCollectionMessageHandler.REQUESTID; -import static org.apache.solr.cloud.OverseerCollectionMessageHandler.SHARDS_PROP; -import static org.apache.solr.cloud.OverseerCollectionMessageHandler.SHARD_UNIQUE; -import static org.apache.solr.common.cloud.DocCollection.DOC_ROUTER; -import static org.apache.solr.common.cloud.DocCollection.RULE; -import static org.apache.solr.common.cloud.DocCollection.SNITCH; -import static org.apache.solr.common.cloud.DocCollection.STATE_FORMAT; -import static org.apache.solr.common.cloud.ZkStateReader.AUTO_ADD_REPLICAS; -import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_PROP; -import static org.apache.solr.common.cloud.ZkStateReader.MAX_SHARDS_PER_NODE; -import static org.apache.solr.common.cloud.ZkStateReader.PROPERTY_PROP; -import static org.apache.solr.common.cloud.ZkStateReader.PROPERTY_VALUE_PROP; -import static org.apache.solr.common.cloud.ZkStateReader.REPLICATION_FACTOR; -import static org.apache.solr.common.cloud.ZkStateReader.REPLICA_PROP; -import static org.apache.solr.common.cloud.ZkStateReader.SHARD_ID_PROP; -import static org.apache.solr.common.params.CollectionParams.CollectionAction.*; -import static org.apache.solr.common.params.CommonAdminParams.ASYNC; -import static org.apache.solr.common.params.CommonParams.NAME; -import static org.apache.solr.common.params.CommonParams.VALUE_LONG; -import static org.apache.solr.common.params.CoreAdminParams.DATA_DIR; -import static org.apache.solr.common.params.CoreAdminParams.DELETE_DATA_DIR; -import static org.apache.solr.common.params.CoreAdminParams.DELETE_INDEX; -import static org.apache.solr.common.params.CoreAdminParams.DELETE_INSTANCE_DIR; -import static org.apache.solr.common.params.CoreAdminParams.INSTANCE_DIR; -import static org.apache.solr.common.params.ShardParams._ROUTE_; -import static org.apache.solr.common.util.StrUtils.formatString; - import java.io.IOException; import java.lang.invoke.MethodHandles; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -66,6 +29,8 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.solr.client.solrj.SolrResponse; @@ -117,8 +82,45 @@ import org.apache.zookeeper.KeeperException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; +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; +import static org.apache.solr.client.solrj.response.RequestStatusState.RUNNING; +import static org.apache.solr.client.solrj.response.RequestStatusState.SUBMITTED; +import static org.apache.solr.cloud.Overseer.QUEUE_OPERATION; +import static org.apache.solr.cloud.OverseerCollectionMessageHandler.COLL_CONF; +import static org.apache.solr.cloud.OverseerCollectionMessageHandler.COLL_PROP_PREFIX; +import static org.apache.solr.cloud.OverseerCollectionMessageHandler.CREATE_NODE_SET; +import static org.apache.solr.cloud.OverseerCollectionMessageHandler.CREATE_NODE_SET_SHUFFLE; +import static org.apache.solr.cloud.OverseerCollectionMessageHandler.NUM_SLICES; +import static org.apache.solr.cloud.OverseerCollectionMessageHandler.ONLY_ACTIVE_NODES; +import static org.apache.solr.cloud.OverseerCollectionMessageHandler.ONLY_IF_DOWN; +import static org.apache.solr.cloud.OverseerCollectionMessageHandler.REQUESTID; +import static org.apache.solr.cloud.OverseerCollectionMessageHandler.SHARDS_PROP; +import static org.apache.solr.cloud.OverseerCollectionMessageHandler.SHARD_UNIQUE; +import static org.apache.solr.common.cloud.DocCollection.DOC_ROUTER; +import static org.apache.solr.common.cloud.DocCollection.RULE; +import static org.apache.solr.common.cloud.DocCollection.SNITCH; +import static org.apache.solr.common.cloud.DocCollection.STATE_FORMAT; +import static org.apache.solr.common.cloud.ZkStateReader.AUTO_ADD_REPLICAS; +import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_PROP; +import static org.apache.solr.common.cloud.ZkStateReader.MAX_SHARDS_PER_NODE; +import static org.apache.solr.common.cloud.ZkStateReader.PROPERTY_PROP; +import static org.apache.solr.common.cloud.ZkStateReader.PROPERTY_VALUE_PROP; +import static org.apache.solr.common.cloud.ZkStateReader.REPLICATION_FACTOR; +import static org.apache.solr.common.cloud.ZkStateReader.REPLICA_PROP; +import static org.apache.solr.common.cloud.ZkStateReader.SHARD_ID_PROP; +import static org.apache.solr.common.params.CollectionParams.CollectionAction.*; +import static org.apache.solr.common.params.CommonAdminParams.ASYNC; +import static org.apache.solr.common.params.CommonParams.NAME; +import static org.apache.solr.common.params.CommonParams.VALUE_LONG; +import static org.apache.solr.common.params.CoreAdminParams.DATA_DIR; +import static org.apache.solr.common.params.CoreAdminParams.DELETE_DATA_DIR; +import static org.apache.solr.common.params.CoreAdminParams.DELETE_INDEX; +import static org.apache.solr.common.params.CoreAdminParams.DELETE_INSTANCE_DIR; +import static org.apache.solr.common.params.CoreAdminParams.INSTANCE_DIR; +import static org.apache.solr.common.params.ShardParams._ROUTE_; +import static org.apache.solr.common.util.StrUtils.formatString; public class CollectionsHandler extends RequestHandlerBase { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); @@ -348,11 +350,7 @@ public class CollectionsHandler extends RequestHandlerBase { addMapObject(props, RULE); addMapObject(props, SNITCH); verifyRuleParams(h.coreContainer, props); - final String collectionName = (String) props.get(NAME); - if (!SolrIdentifierValidator.validateCollectionName(collectionName)) { - throw new SolrException(ErrorCode.BAD_REQUEST, - SolrIdentifierValidator.getIdentifierMessage(SolrIdentifierValidator.IdentifierType.COLLECTION, collectionName)); - } + final String collectionName = SolrIdentifierValidator.validateCollectionName((String)props.get(NAME)); final String shardsParam = (String) props.get(SHARDS_PROP); if (StringUtils.isNotEmpty(shardsParam)) { verifyShardsParam(shardsParam); @@ -433,10 +431,7 @@ public class CollectionsHandler extends RequestHandlerBase { @Override Map call(SolrQueryRequest req, SolrQueryResponse rsp, CollectionsHandler handler) throws Exception { - final String aliasName = req.getParams().get(NAME); - if (!SolrIdentifierValidator.validateCollectionName(aliasName)) { - throw new SolrException(ErrorCode.BAD_REQUEST, SolrIdentifierValidator.getIdentifierMessage(SolrIdentifierValidator.IdentifierType.ALIAS, aliasName)); - } + final String aliasName = SolrIdentifierValidator.validateAliasName(req.getParams().get(NAME)); return req.getParams().required().getAll(null, NAME, "collections"); } }, @@ -505,11 +500,7 @@ public class CollectionsHandler extends RequestHandlerBase { COLLECTION_PROP, SHARD_ID_PROP); ClusterState clusterState = handler.coreContainer.getZkController().getClusterState(); - final String newShardName = req.getParams().get(SHARD_ID_PROP); - if (!SolrIdentifierValidator.validateShardName(newShardName)) { - throw new SolrException(ErrorCode.BAD_REQUEST, SolrIdentifierValidator.getIdentifierMessage(SolrIdentifierValidator.IdentifierType.SHARD, - newShardName)); - } + final String newShardName = SolrIdentifierValidator.validateShardName(req.getParams().get(SHARD_ID_PROP)); if (!ImplicitDocRouter.NAME.equals(((Map) clusterState.getCollection(req.getParams().get(COLLECTION_PROP)).get(DOC_ROUTER)).get(NAME))) throw new SolrException(ErrorCode.BAD_REQUEST, "shards can be added only to 'implicit' collections"); req.getParams().getAll(map, @@ -997,9 +988,7 @@ public class CollectionsHandler extends RequestHandlerBase { private static void verifyShardsParam(String shardsParam) { for (String shard : shardsParam.split(",")) { - if (!SolrIdentifierValidator.validateShardName(shard)) - throw new SolrException(ErrorCode.BAD_REQUEST, SolrIdentifierValidator.getIdentifierMessage(SolrIdentifierValidator.IdentifierType.SHARD, - shard)); + SolrIdentifierValidator.validateShardName(shard); } } diff --git a/solr/core/src/test/org/apache/solr/cloud/DeleteStatusTest.java b/solr/core/src/test/org/apache/solr/cloud/DeleteStatusTest.java index 16ca35a0865..3b8e014c0a7 100644 --- a/solr/core/src/test/org/apache/solr/cloud/DeleteStatusTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/DeleteStatusTest.java @@ -17,101 +17,129 @@ package org.apache.solr.cloud; import java.io.IOException; +import java.util.concurrent.TimeUnit; +import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.impl.HttpSolrClient; +import org.apache.solr.client.solrj.impl.CloudSolrClient; import org.apache.solr.client.solrj.request.CollectionAdminRequest; import org.apache.solr.client.solrj.response.CollectionAdminResponse; import org.apache.solr.client.solrj.response.RequestStatusState; +import org.junit.BeforeClass; import org.junit.Test; -public class DeleteStatusTest extends AbstractFullDistribZkTestBase { +public class DeleteStatusTest extends SolrCloudTestCase { + + public static final int MAX_WAIT_TIMEOUT = 30; + + @BeforeClass + public static void createCluster() throws Exception { + configureCluster(2) + .addConfig("conf1", TEST_PATH().resolve("configsets").resolve("cloud-minimal").resolve("conf")) + .configure(); + } + + // Basically equivalent to RequestStatus.waitFor(), but doesn't delete the id from the queue + private static RequestStatusState waitForRequestState(String id, SolrClient client, int timeout) + throws IOException, SolrServerException, InterruptedException { + RequestStatusState state = RequestStatusState.SUBMITTED; + long endTime = System.nanoTime() + TimeUnit.SECONDS.toNanos(MAX_WAIT_TIMEOUT); + while (System.nanoTime() < endTime) { + state = CollectionAdminRequest.requestStatus(id).process(client).getRequestStatus(); + if (state == RequestStatusState.COMPLETED) + break; + assumeTrue("Error creating collection - skipping test", state != RequestStatusState.FAILED); + TimeUnit.SECONDS.sleep(1); + } + assumeTrue("Timed out creating collection - skipping test", state == RequestStatusState.COMPLETED); + return state; + } @Test - public void testDeleteStatus() throws IOException, SolrServerException { - CollectionAdminRequest.Create create = new CollectionAdminRequest.Create(); - create.setCollectionName("requeststatus") - .setConfigName("conf1") - .setReplicationFactor(1) - .setNumShards(1) - .setAsyncId("collectioncreate") - .process(cloudClient); + public void testAsyncIdsMayBeDeleted() throws Exception { - RequestStatusState state = getRequestStateAfterCompletion("collectioncreate", 30, cloudClient); + final CloudSolrClient client = cluster.getSolrClient(); + + final String collection = "deletestatus"; + final String asyncId = CollectionAdminRequest.createCollection(collection, "conf1", 1, 1).processAsync(client); + + waitForRequestState(asyncId, client, MAX_WAIT_TIMEOUT); + + assertEquals(RequestStatusState.COMPLETED, + CollectionAdminRequest.requestStatus(asyncId).process(client).getRequestStatus()); + + CollectionAdminResponse rsp = CollectionAdminRequest.deleteAsyncId(asyncId).process(client); + assertEquals("successfully removed stored response for [" + asyncId + "]", rsp.getResponse().get("status")); + + assertEquals(RequestStatusState.NOT_FOUND, + CollectionAdminRequest.requestStatus(asyncId).process(client).getRequestStatus()); + + } + + @Test + public void testDeletingNonExistentRequests() throws Exception { + + final CloudSolrClient client = cluster.getSolrClient(); + + CollectionAdminResponse rsp = CollectionAdminRequest.deleteAsyncId("foo").process(client); + assertEquals("[foo] not found in stored responses", rsp.getResponse().get("status")); + + } + + @Test + public void testProcessAndWaitDeletesAsyncIds() throws IOException, SolrServerException, InterruptedException { + + final CloudSolrClient client = cluster.getSolrClient(); + + RequestStatusState state = CollectionAdminRequest.createCollection("requeststatus", "conf1", 1, 1) + .processAndWait("request1", client, MAX_WAIT_TIMEOUT); assertSame(RequestStatusState.COMPLETED, state); - // Let's delete the stored response now - CollectionAdminRequest.DeleteStatus deleteStatus = new CollectionAdminRequest.DeleteStatus(); - CollectionAdminResponse rsp = deleteStatus - .setRequestId("collectioncreate") - .process(cloudClient); - assertEquals("successfully removed stored response for [collectioncreate]", rsp.getResponse().get("status")); + // using processAndWait deletes the requestid + state = CollectionAdminRequest.requestStatus("request1").process(client).getRequestStatus(); + assertSame("Request id was not deleted by processAndWait call", RequestStatusState.NOT_FOUND, state); - // Make sure that the response was deleted from zk - state = getRequestState("collectioncreate", cloudClient); - assertSame(RequestStatusState.NOT_FOUND, state); - - // Try deleting the same requestid again - deleteStatus = new CollectionAdminRequest.DeleteStatus(); - rsp = deleteStatus - .setRequestId("collectioncreate") - .process(cloudClient); - assertEquals("[collectioncreate] not found in stored responses", rsp.getResponse().get("status")); - - // Let's try deleting a non-existent status - deleteStatus = new CollectionAdminRequest.DeleteStatus(); - rsp = deleteStatus - .setRequestId("foo") - .process(cloudClient); - assertEquals("[foo] not found in stored responses", rsp.getResponse().get("status")); } @Test public void testDeleteStatusFlush() throws Exception { - CollectionAdminRequest.Create create = new CollectionAdminRequest.Create(); - create.setConfigName("conf1") - .setCollectionName("foo") - .setAsyncId("foo") - .setNumShards(1) - .setReplicationFactor(1) - .process(cloudClient); - create = new CollectionAdminRequest.Create(); - create.setConfigName("conf1") - .setCollectionName("bar") - .setAsyncId("bar") - .setNumShards(1) - .setReplicationFactor(1) - .process(cloudClient); + final CloudSolrClient client = cluster.getSolrClient(); - RequestStatusState state = getRequestStateAfterCompletion("foo", 30, cloudClient); - assertEquals(RequestStatusState.COMPLETED, state); + String id1 = CollectionAdminRequest.createCollection("flush1", "conf1", 1, 1).processAsync(client); + String id2 = CollectionAdminRequest.createCollection("flush2", "conf1", 1, 1).processAsync(client); - state = getRequestStateAfterCompletion("bar", 30, cloudClient); - assertEquals(RequestStatusState.COMPLETED, state); + assertEquals(RequestStatusState.COMPLETED, waitForRequestState(id1, client, MAX_WAIT_TIMEOUT)); + assertEquals(RequestStatusState.COMPLETED, waitForRequestState(id2, client, MAX_WAIT_TIMEOUT)); - CollectionAdminRequest.DeleteStatus deleteStatus = new CollectionAdminRequest.DeleteStatus(); - deleteStatus.setFlush(true) - .process(cloudClient); + CollectionAdminRequest.deleteAllAsyncIds().process(client); - assertEquals(RequestStatusState.NOT_FOUND, getRequestState("foo", cloudClient)); - assertEquals(RequestStatusState.NOT_FOUND, getRequestState("bar", cloudClient)); + assertEquals(RequestStatusState.NOT_FOUND, + CollectionAdminRequest.requestStatus(id1).process(client).getRequestStatus()); + assertEquals(RequestStatusState.NOT_FOUND, + CollectionAdminRequest.requestStatus(id2).process(client).getRequestStatus()); + + } + + @Test + @SuppressWarnings("deprecation") + public void testDeprecatedConstructorValidation() throws Exception { + + final CloudSolrClient client = cluster.getSolrClient(); - deleteStatus = new CollectionAdminRequest.DeleteStatus(); try { - deleteStatus.process(cloudClient); + new CollectionAdminRequest.DeleteStatus().process(client); fail("delete status should have failed"); - } catch (HttpSolrClient.RemoteSolrException e) { + } catch (IllegalArgumentException e) { assertTrue(e.getMessage().contains("Either requestid or flush parameter must be specified.")); } - deleteStatus = new CollectionAdminRequest.DeleteStatus(); try { - deleteStatus.setFlush(true) + new CollectionAdminRequest.DeleteStatus().setFlush(true) .setRequestId("foo") - .process(cloudClient); + .process(client); fail("delete status should have failed"); - } catch (HttpSolrClient.RemoteSolrException e) { + } catch (IllegalArgumentException e) { assertTrue(e.getMessage().contains("Both requestid and flush parameters can not be specified together.")); } } diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/request/CollectionAdminRequest.java b/solr/solrj/src/java/org/apache/solr/client/solrj/request/CollectionAdminRequest.java index c9c8c3989df..4f28408ce21 100644 --- a/solr/solrj/src/java/org/apache/solr/client/solrj/request/CollectionAdminRequest.java +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/request/CollectionAdminRequest.java @@ -18,8 +18,6 @@ package org.apache.solr.client.solrj.request; import java.io.IOException; import java.util.Collection; -import java.util.Iterator; -import java.util.Map; import java.util.Properties; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -80,16 +78,15 @@ public abstract class CollectionAdminRequest } protected void addProperties(ModifiableSolrParams params, Properties props) { - Iterator> iter = props.entrySet().iterator(); - while(iter.hasNext()) { - Map.Entry prop = iter.next(); - String key = (String) prop.getKey(); - String value = (String) prop.getValue(); - params.set(PROPERTY_PREFIX + key, value); + for (String propertyName : props.stringPropertyNames()) { + params.set(PROPERTY_PREFIX + propertyName, props.getProperty(propertyName)); } } - protected abstract static class AsyncCollectionAdminRequest extends CollectionAdminRequest { + /** + * Base class for asynchronous collection admin requests + */ + public abstract static class AsyncCollectionAdminRequest extends CollectionAdminRequest { public AsyncCollectionAdminRequest(CollectionAction action) { super(action); @@ -164,7 +161,7 @@ public abstract class CollectionAdminRequest public RequestStatusState processAndWait(String asyncId, SolrClient client, long timeoutSeconds) throws IOException, SolrServerException, InterruptedException { processAsync(asyncId, client); - return new RequestStatus().setRequestId(asyncId).waitFor(client, timeoutSeconds); + return requestStatus(asyncId).waitFor(client, timeoutSeconds); } @Override @@ -181,10 +178,12 @@ public abstract class CollectionAdminRequest protected String collection; - public AsyncCollectionSpecificAdminRequest(CollectionAction action) { + public AsyncCollectionSpecificAdminRequest(CollectionAction action, String collection) { super(action); + this.collection = collection; } + @Deprecated public abstract AsyncCollectionSpecificAdminRequest setCollectionName(String collection); @Override @@ -202,12 +201,14 @@ public abstract class CollectionAdminRequest protected String collection; protected String shard; - public AsyncShardSpecificAdminRequest(CollectionAction action) { + public AsyncShardSpecificAdminRequest(CollectionAction action, String collection, String shard) { super(action); } + @Deprecated public abstract AsyncShardSpecificAdminRequest setCollectionName(String collection); + @Deprecated public abstract AsyncShardSpecificAdminRequest setShardName(String shard); @Override @@ -228,12 +229,14 @@ public abstract class CollectionAdminRequest protected String collection; protected String shard; - public ShardSpecificAdminRequest(CollectionAction action) { + public ShardSpecificAdminRequest(CollectionAction action, String collection, String shard) { super(action); } + @Deprecated public abstract ShardSpecificAdminRequest setCollectionName(String collection); + @Deprecated public abstract ShardSpecificAdminRequest setShardName(String shard); @Override @@ -264,7 +267,7 @@ public abstract class CollectionAdminRequest protected String node; protected String role; - public CollectionAdminRoleRequest(CollectionAction action) { + public CollectionAdminRoleRequest(CollectionAction action, String node, String role) { super(action); } @@ -274,12 +277,14 @@ public abstract class CollectionAdminRequest return this; } + @Deprecated public abstract CollectionAdminRoleRequest setNode(String node); public String getNode() { return this.node; } + @Deprecated public abstract CollectionAdminRoleRequest setRole(String role); public String getRole() { @@ -298,6 +303,17 @@ public abstract class CollectionAdminRequest /** Specific Collection API call implementations **/ + /** + * Returns a SolrRequest for creating a collection + * @param collection the collection name + * @param config the collection config + * @param numShards the number of shards in the collection + * @param numReplicas the replication factor of the collection + */ + public static Create createCollection(String collection, String config, int numShards, int numReplicas) { + return new Create(collection, config, numShards, numReplicas); + } + // CREATE request public static class Create extends AsyncCollectionSpecificAdminRequest { @@ -315,17 +331,31 @@ public abstract class CollectionAdminRequest protected Integer stateFormat; private String[] rule , snitch; + /** + * @deprecated Use {@link #createCollection(String, String, int, int)} + */ + @Deprecated public Create() { - super(CollectionAction.CREATE); + super(CollectionAction.CREATE, null); } + private Create(String collection, String config, int numShards, int numReplicas) { + super(CollectionAction.CREATE, SolrIdentifierValidator.validateCollectionName(collection)); + this.configName = config; + this.numShards = numShards; + this.replicationFactor = numReplicas; + } + + @Deprecated public Create setConfigName(String config) { this.configName = config; return this; } public Create setCreateNodeSet(String nodeSet) { this.createNodeSet = nodeSet; return this; } public Create setRouterName(String routerName) { this.routerName = routerName; return this; } public Create setRouterField(String routerField) { this.routerField = routerField; return this; } + @Deprecated public Create setNumShards(Integer numShards) {this.numShards = numShards; return this; } public Create setMaxShardsPerNode(Integer numShards) { this.maxShardsPerNode = numShards; return this; } public Create setAutoAddReplicas(boolean autoAddReplicas) { this.autoAddReplicas = autoAddReplicas; return this; } + @Deprecated public Create setReplicationFactor(Integer repl) { this.replicationFactor = repl; return this; } public Create setStateFormat(Integer stateFormat) { this.stateFormat = stateFormat; return this; } public Create setRule(String... s){ this.rule = s; return this; } @@ -350,10 +380,7 @@ public abstract class CollectionAdminRequest */ public Create setShards(String shards) { for (String shard : shards.split(",")) { - if (!SolrIdentifierValidator.validateShardName(shard)) { - throw new IllegalArgumentException(SolrIdentifierValidator.getIdentifierMessage(SolrIdentifierValidator.IdentifierType.SHARD, - shard)); - } + SolrIdentifierValidator.validateShardName(shard); } this.shards = shards; return this; @@ -366,16 +393,14 @@ public abstract class CollectionAdminRequest * * @throws IllegalArgumentException if the collection name contains invalid characters. */ + @Deprecated public Create setCollectionName(String collectionName) throws SolrException { - if (!SolrIdentifierValidator.validateCollectionName(collectionName)) { - throw new IllegalArgumentException(SolrIdentifierValidator.getIdentifierMessage(SolrIdentifierValidator.IdentifierType.COLLECTION, - collectionName)); - } - this.collection = collectionName; + this.collection = SolrIdentifierValidator.validateCollectionName(collectionName); return this; } @Override + @Deprecated public Create setAsyncId(String id) { this.asyncId = id; return this; @@ -426,46 +451,87 @@ public abstract class CollectionAdminRequest } + /** + * Returns a SolrRequest to reload a collection + */ + public static Reload reloadCollection(String collection) { + return new Reload(collection); + } + // RELOAD request public static class Reload extends AsyncCollectionSpecificAdminRequest { + /** + * @deprecated use {@link #reloadCollection(String)} + */ + @Deprecated public Reload() { - super(CollectionAction.RELOAD); + super(CollectionAction.RELOAD, null); + } + + private Reload(String collection) { + super(CollectionAction.RELOAD, collection); } @Override + @Deprecated public Reload setCollectionName(String collection) { this.collection = collection; return this; } @Override + @Deprecated public Reload setAsyncId(String id) { this.asyncId = id; return this; } } + /** + * Returns a SolrRequest to delete a collection + */ + public static Delete deleteCollection(String collection) { + return new Delete(collection); + } + // DELETE request public static class Delete extends AsyncCollectionSpecificAdminRequest { + /** + * @deprecated Use {@link #deleteCollection(String)} + */ + @Deprecated public Delete() { - super(CollectionAction.DELETE); + super(CollectionAction.DELETE, null); + } + + private Delete(String collection) { + super(CollectionAction.DELETE, collection); } @Override + @Deprecated public Delete setCollectionName(String collection) { this.collection = collection; return this; } @Override + @Deprecated public Delete setAsyncId(String id) { this.asyncId = id; return this; } } + /** + * Returns a SolrRequest to create a new shard in a collection + */ + public static CreateShard createShard(String collection, String shard) { + return new CreateShard(collection, shard); + } + // CREATESHARD request public static class CreateShard extends AsyncShardSpecificAdminRequest { @@ -490,11 +556,20 @@ public abstract class CollectionAdminRequest return this; } + /** + * @deprecated use {@link #createShard(String, String)} + */ + @Deprecated public CreateShard() { - super(CollectionAction.CREATESHARD); + super(CollectionAction.CREATESHARD, null, null); + } + + private CreateShard(String collection, String shard) { + super(CollectionAction.CREATESHARD, collection, SolrIdentifierValidator.validateShardName(shard)); } @Override + @Deprecated public CreateShard setCollectionName(String collection) { this.collection = collection; return this; @@ -508,16 +583,14 @@ public abstract class CollectionAdminRequest * @throws IllegalArgumentException if the shard name contains invalid characters. */ @Override + @Deprecated public CreateShard setShardName(String shardName) { - if (!SolrIdentifierValidator.validateShardName(shardName)) { - throw new IllegalArgumentException(SolrIdentifierValidator.getIdentifierMessage(SolrIdentifierValidator.IdentifierType.SHARD, - shardName)); - } - this.shard = shardName; + this.shard = SolrIdentifierValidator.validateShardName(shardName); return this; } @Override + @Deprecated public CreateShard setAsyncId(String id) { this.asyncId = id; return this; @@ -538,6 +611,13 @@ public abstract class CollectionAdminRequest } + /** + * Returns a SolrRequest to split a shard in a collection + */ + public static SplitShard splitShard(String collection, String shard) { + return new SplitShard(collection, shard); + } + // SPLITSHARD request public static class SplitShard extends AsyncShardSpecificAdminRequest { protected String ranges; @@ -545,8 +625,16 @@ public abstract class CollectionAdminRequest private Properties properties; + private SplitShard(String collection, String shard) { + super(CollectionAction.SPLITSHARD, collection, shard); + } + + /** + * @deprecated Use {@link #splitShard(String, String)} + */ + @Deprecated public SplitShard() { - super(CollectionAction.SPLITSHARD); + super(CollectionAction.SPLITSHARD, null, null); } public SplitShard setRanges(String ranges) { this.ranges = ranges; return this; } @@ -571,18 +659,21 @@ public abstract class CollectionAdminRequest } @Override + @Deprecated public SplitShard setCollectionName(String collection) { this.collection = collection; return this; } @Override + @Deprecated public SplitShard setShardName(String shard) { this.shard = shard; return this; } @Override + @Deprecated public SplitShard setAsyncId(String id) { this.asyncId = id; return this; @@ -604,14 +695,29 @@ public abstract class CollectionAdminRequest } + /** + * Returns a SolrRequest to delete a shard from a collection + */ + public static DeleteShard deleteShard(String collection, String shard) { + return new DeleteShard(collection, shard); + } + // DELETESHARD request public static class DeleteShard extends AsyncShardSpecificAdminRequest { private Boolean deleteInstanceDir; private Boolean deleteDataDir; + /** + * @deprecated Use {@link #deleteShard(String, String)} + */ + @Deprecated public DeleteShard() { - super(CollectionAction.DELETESHARD); + super(CollectionAction.DELETESHARD, null, null); + } + + private DeleteShard(String collection, String shard) { + super(CollectionAction.DELETESHARD, collection, shard); } public Boolean getDeleteInstanceDir() { @@ -633,18 +739,21 @@ public abstract class CollectionAdminRequest } @Override + @Deprecated public DeleteShard setCollectionName(String collection) { this.collection = collection; return this; } @Override + @Deprecated public DeleteShard setShardName(String shard) { this.shard = shard; return this; } @Override + @Deprecated public DeleteShard setAsyncId(String id) { this.asyncId = id; return this; @@ -663,21 +772,41 @@ public abstract class CollectionAdminRequest } } + /** + * Returns a SolrRequest to force a leader election for a shard in a collection + * + * WARNING: This may cause data loss if the new leader does not contain updates + * acknowledged by the old leader. Use only if leadership elections are entirely + * broken. + */ + public static ForceLeader forceLeaderElection(String collection, String shard) { + return new ForceLeader(collection, shard); + } + // FORCELEADER request public static class ForceLeader extends ShardSpecificAdminRequest { + /** + * @deprecated Use {@link #forceLeaderElection(String, String)} + */ + @Deprecated public ForceLeader() { - super(CollectionAction.FORCELEADER); + super(CollectionAction.FORCELEADER, null, null); } + private ForceLeader(String collection, String shard) { + super(CollectionAction.FORCELEADER, collection, shard); + } @Override + @Deprecated public ForceLeader setCollectionName(String collection) { this.collection = collection; return this; } @Override + @Deprecated public ForceLeader setShardName(String shard) { this.shard = shard; return this; @@ -685,6 +814,9 @@ public abstract class CollectionAdminRequest } + /** + * A response object for {@link RequestStatus} requests + */ public static class RequestStatusResponse extends CollectionAdminResponse { public RequestStatusState getRequestStatus() { @@ -694,15 +826,34 @@ public abstract class CollectionAdminRequest } + /** + * Returns a SolrRequest for checking the status of an asynchronous request + * + * @see CollectionAdminRequest.AsyncCollectionAdminRequest + */ + public static RequestStatus requestStatus(String requestId) { + return new RequestStatus(requestId); + } + // REQUESTSTATUS request public static class RequestStatus extends CollectionAdminRequest { protected String requestId = null; + private RequestStatus(String requestId) { + super(CollectionAction.REQUESTSTATUS); + this.requestId = requestId; + } + + /** + * @deprecated Use {@link #requestStatus(String)} + */ + @Deprecated public RequestStatus() { super(CollectionAction.REQUESTSTATUS); } + @Deprecated public RequestStatus setRequestId(String requestId) { this.requestId = requestId; return this; @@ -726,6 +877,12 @@ public abstract class CollectionAdminRequest return new RequestStatusResponse(); } + /** + * Wait until the asynchronous request is either completed or failed, up to a timeout + * @param client a SolrClient + * @param timeoutSeconds the maximum time to wait in seconds + * @return the last seen state of the request + */ public RequestStatusState waitFor(SolrClient client, long timeoutSeconds) throws IOException, SolrServerException, InterruptedException { long finishTime = System.nanoTime() + TimeUnit.SECONDS.toNanos(timeoutSeconds); @@ -733,7 +890,7 @@ public abstract class CollectionAdminRequest while (System.nanoTime() < finishTime) { state = this.process(client).getRequestStatus(); if (state == RequestStatusState.COMPLETED || state == RequestStatusState.FAILED) { - new DeleteStatus().setRequestId(requestId).process(client); + deleteAsyncId(requestId).process(client); return state; } TimeUnit.SECONDS.sleep(1); @@ -742,21 +899,43 @@ public abstract class CollectionAdminRequest } } + /** + * Returns a SolrRequest to delete an asynchronous request status + */ + public static DeleteStatus deleteAsyncId(String requestId) { + return new DeleteStatus(requestId); + } + + public static DeleteStatus deleteAllAsyncIds() { + return new DeleteStatus().setFlush(true); + } + // DELETESTATUS request public static class DeleteStatus extends CollectionAdminRequest { protected String requestId = null; protected Boolean flush = null; + private DeleteStatus(String requestId) { + super(CollectionAction.DELETESTATUS); + this.requestId = requestId; + } + + /** + * @deprecated Use {@link #deleteAsyncId(String)} or {@link #deleteAllAsyncIds()} + */ + @Deprecated public DeleteStatus() { super(CollectionAction.DELETESTATUS); } + @Deprecated public DeleteStatus setRequestId(String requestId) { this.requestId = requestId; return this; } + @Deprecated public DeleteStatus setFlush(Boolean flush) { this.flush = flush; return this; @@ -773,9 +952,12 @@ public abstract class CollectionAdminRequest @Override public SolrParams getParams() { ModifiableSolrParams params = (ModifiableSolrParams) super.getParams(); + if (requestId == null && flush == null) + throw new IllegalArgumentException("Either requestid or flush parameter must be specified."); + if (requestId != null && flush != null) + throw new IllegalArgumentException("Both requestid and flush parameters can not be specified together."); if (requestId != null) params.set(CoreAdminParams.REQUESTID, requestId); - if (flush != null) params.set(CollectionAdminParams.FLUSH, flush); return params; @@ -788,12 +970,31 @@ public abstract class CollectionAdminRequest } + /** + * Returns a SolrRequest to create a new alias + * @param aliasName the alias name + * @param aliasedCollections the collections to alias + */ + public static CreateAlias createAlias(String aliasName, String aliasedCollections) { + return new CreateAlias(aliasName, aliasedCollections); + } + // CREATEALIAS request public static class CreateAlias extends AsyncCollectionAdminRequest { protected String aliasName; protected String aliasedCollections; + private CreateAlias(String aliasName, String aliasedCollections) { + super(CollectionAction.CREATEALIAS); + this.aliasName = SolrIdentifierValidator.validateAliasName(aliasName); + this.aliasedCollections = aliasedCollections; + } + + /** + * @deprecated Use {@link #createAlias(String, String)} + */ + @Deprecated public CreateAlias() { super(CollectionAction.CREATEALIAS); } @@ -805,12 +1006,9 @@ public abstract class CollectionAdminRequest * * @throws IllegalArgumentException if the alias name contains invalid characters. */ + @Deprecated public CreateAlias setAliasName(String aliasName) { - if (!SolrIdentifierValidator.validateCollectionName(aliasName)) { - throw new IllegalArgumentException(SolrIdentifierValidator.getIdentifierMessage(SolrIdentifierValidator.IdentifierType.ALIAS, - aliasName)); - } - this.aliasName = aliasName; + this.aliasName = SolrIdentifierValidator.validateAliasName(aliasName); return this; } @@ -818,6 +1016,7 @@ public abstract class CollectionAdminRequest return aliasName; } + @Deprecated public CreateAlias setAliasedCollections(String alias) { this.aliasedCollections = alias; return this; @@ -828,6 +1027,7 @@ public abstract class CollectionAdminRequest } @Override + @Deprecated public CreateAlias setAsyncId(String id) { this.asyncId = id; return this; @@ -843,21 +1043,39 @@ public abstract class CollectionAdminRequest } + /** + * Returns a SolrRequest to delete an alias + */ + public static DeleteAlias deleteAlias(String aliasName) { + return new DeleteAlias(aliasName); + } + // DELETEALIAS request public static class DeleteAlias extends AsyncCollectionAdminRequest { protected String aliasName; + private DeleteAlias(String aliasName) { + super(CollectionAction.DELETEALIAS); + this.aliasName = aliasName; + } + + /** + * @deprecated Use {@link #deleteAlias(String)} + */ + @Deprecated public DeleteAlias() { super(CollectionAction.DELETEALIAS); } + @Deprecated public DeleteAlias setAliasName(String aliasName) { this.aliasName = aliasName; return this; } @Override + @Deprecated public DeleteAlias setAsyncId(String id) { this.asyncId = id; return this; @@ -873,6 +1091,20 @@ public abstract class CollectionAdminRequest } + /** + * Returns a SolrRequest to add a replica to a shard in a collection + */ + public static AddReplica addReplicaToShard(String collection, String shard) { + return new AddReplica(collection, shard, null); + } + + /** + * Returns a SolrRequest to add a replica to a collection using a route key + */ + public static AddReplica addReplicaByRouteKey(String collection, String routeKey) { + return new AddReplica(collection, null, routeKey); + } + // ADDREPLICA request public static class AddReplica extends AsyncCollectionAdminRequest { @@ -884,10 +1116,21 @@ public abstract class CollectionAdminRequest protected String dataDir; protected Properties properties; + /** + * @deprecated Use {@link #addReplicaByRouteKey(String, String)} or {@link #addReplicaToShard(String, String)} + */ + @Deprecated public AddReplica() { super(CollectionAction.ADDREPLICA); } + private AddReplica(String collection, String shard, String routeKey) { + super(CollectionAction.ADDREPLICA); + this.collection = collection; + this.shard = shard; + this.routeKey = routeKey; + } + public Properties getProperties() { return properties; } @@ -910,6 +1153,7 @@ public abstract class CollectionAdminRequest return routeKey; } + @Deprecated public AddReplica setRouteKey(String routeKey) { this.routeKey = routeKey; return this; @@ -933,17 +1177,20 @@ public abstract class CollectionAdminRequest return this; } + @Deprecated public AddReplica setCollectionName(String collection) { this.collection = collection; return this; } + @Deprecated public AddReplica setShardName(String shard) { this.shard = shard; return this; } @Override + @Deprecated public AddReplica setAsyncId(String id) { this.asyncId = id; return this; @@ -957,7 +1204,7 @@ public abstract class CollectionAdminRequest params.add(CoreAdminParams.COLLECTION, collection); if (shard == null || shard.isEmpty()) { if (routeKey == null) { - throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Either shard or routeKey must be provided"); + throw new IllegalArgumentException("Either shard or routeKey must be provided"); } params.add(ShardParams._ROUTE_, routeKey); } @@ -979,7 +1226,13 @@ public abstract class CollectionAdminRequest return params; } + } + /** + * Returns a SolrRequest to delete a replica from a shard in a collection + */ + public static DeleteReplica deleteReplica(String collection, String shard, String replica) { + return new DeleteReplica(collection, shard, replica); } // DELETEREPLICA request @@ -991,10 +1244,20 @@ public abstract class CollectionAdminRequest private Boolean deleteInstanceDir; private Boolean deleteIndexDir; + /** + * @deprecated Use {@link #deleteReplica(String, String, String)} + */ + @Deprecated public DeleteReplica() { - super(CollectionAction.DELETEREPLICA); + super(CollectionAction.DELETEREPLICA, null, null); } + private DeleteReplica(String collection, String shard, String replica) { + super(CollectionAction.DELETEREPLICA, collection, shard); + this.replica = replica; + } + + @Deprecated public DeleteReplica setReplica(String replica) { this.replica = replica; return this; @@ -1014,18 +1277,21 @@ public abstract class CollectionAdminRequest } @Override + @Deprecated public DeleteReplica setCollectionName(String collection) { this.collection = collection; return this; } @Override + @Deprecated public DeleteReplica setShardName(String shard) { this.shard = shard; return this; } @Override + @Deprecated public DeleteReplica setAsyncId(String id) { this.asyncId = id; return this; @@ -1070,16 +1336,34 @@ public abstract class CollectionAdminRequest } } + /** + * Returns a SolrRequest to set a cluster property + */ + public static ClusterProp setClusterProperty(String propertyName, String propertyValue) { + return new ClusterProp(propertyName, propertyValue); + } + // CLUSTERPROP request public static class ClusterProp extends CollectionAdminRequest { private String propertyName; private String propertyValue; + /** + * @deprecated Use {@link #setClusterProperty(String, String)} + */ + @Deprecated public ClusterProp() { super(CollectionAction.CLUSTERPROP); } + private ClusterProp(String propertyName, String propertyValue) { + super(CollectionAction.CLUSTERPROP); + this.propertyName = propertyName; + this.propertyValue = propertyValue; + } + + @Deprecated public ClusterProp setPropertyName(String propertyName) { this.propertyName = propertyName; return this; @@ -1089,6 +1373,7 @@ public abstract class CollectionAdminRequest return this.propertyName; } + @Deprecated public ClusterProp setPropertyValue(String propertyValue) { this.propertyValue = propertyValue; return this; @@ -1115,6 +1400,13 @@ public abstract class CollectionAdminRequest } + /** + * Returns a SolrRequest to migrate data matching a split key to another collection + */ + public static Migrate migrateData(String collection, String targetCollection, String splitKey) { + return new Migrate(collection, targetCollection, splitKey); + } + // MIGRATE request public static class Migrate extends AsyncCollectionAdminRequest { @@ -1124,10 +1416,22 @@ public abstract class CollectionAdminRequest private Integer forwardTimeout; private Properties properties; + /** + * @deprecated Use {@link #migrateData(String, String, String)} + */ + @Deprecated public Migrate() { super(CollectionAction.MIGRATE); } + private Migrate(String collection, String targetCollection, String splitKey) { + super(CollectionAction.MIGRATE); + this.collection = collection; + this.targetCollection = targetCollection; + this.splitKey = splitKey; + } + + @Deprecated public Migrate setCollectionName(String collection) { this.collection = collection; return this; @@ -1137,6 +1441,7 @@ public abstract class CollectionAdminRequest return collection; } + @Deprecated public Migrate setTargetCollection(String targetCollection) { this.targetCollection = targetCollection; return this; @@ -1146,6 +1451,7 @@ public abstract class CollectionAdminRequest return this.targetCollection; } + @Deprecated public Migrate setSplitKey(String splitKey) { this.splitKey = splitKey; return this; @@ -1174,6 +1480,7 @@ public abstract class CollectionAdminRequest } @Override + @Deprecated public Migrate setAsyncId(String id) { this.asyncId = id; return this; @@ -1198,46 +1505,87 @@ public abstract class CollectionAdminRequest } + /** + * Returns a SolrRequest to add a role to a node + */ + public static AddRole addRole(String node, String role) { + return new AddRole(node, role); + } + // ADDROLE request public static class AddRole extends CollectionAdminRoleRequest { + /** + * @deprecated Use {@link #addRole(String, String)} + */ + @Deprecated public AddRole() { - super(CollectionAction.ADDROLE); + super(CollectionAction.ADDROLE, null, null); + } + + private AddRole(String node, String role) { + super(CollectionAction.ADDROLE, node, role); } @Override + @Deprecated public AddRole setNode(String node) { this.node = node; return this; } @Override + @Deprecated public AddRole setRole(String role) { this.role = role; return this; } } + /** + * Returns a SolrRequest to remove a role from a node + */ + public static RemoveRole removeRole(String node, String role) { + return new RemoveRole(node, role); + } + // REMOVEROLE request public static class RemoveRole extends CollectionAdminRoleRequest { + /** + * @deprecated Use {@link #removeRole(String, String)} + */ + @Deprecated public RemoveRole() { - super(CollectionAction.REMOVEROLE); + super(CollectionAction.REMOVEROLE, null, null); + } + + private RemoveRole(String node, String role) { + super(CollectionAction.REMOVEROLE, node, role); } @Override + @Deprecated public RemoveRole setNode(String node) { this.node = node; return this; } @Override + @Deprecated public RemoveRole setRole(String role) { this.role = role; return this; } } + /** + * Return a SolrRequest to get the Overseer status + */ + public static OverseerStatus getOverseerStatus() { + return new OverseerStatus(); + } + // OVERSEERSTATUS request public static class OverseerStatus extends AsyncCollectionAdminRequest { @@ -1246,12 +1594,20 @@ public abstract class CollectionAdminRequest } @Override + @Deprecated public OverseerStatus setAsyncId(String id) { this.asyncId = id; return this; } } + /** + * Return a SolrRequest to get the Cluster status + */ + public static ClusterStatus getClusterStatus() { + return new ClusterStatus(); + } + // CLUSTERSTATUS request public static class ClusterStatus extends CollectionAdminRequest { @@ -1310,7 +1666,13 @@ public abstract class CollectionAdminRequest return new CollectionAdminResponse(); } + } + /** + * Returns a SolrRequest to get a list of collections in the cluster + */ + public static List listCollections() { + return new List(); } // LIST request @@ -1325,6 +1687,14 @@ public abstract class CollectionAdminRequest } } + /** + * Returns a SolrRequest to add a property to a specific replica + */ + public static AddReplicaProp addReplicaProperty(String collection, String shard, String replica, + String propertyName, String propertyValue) { + return new AddReplicaProp(collection, shard, replica, propertyName, propertyValue); + } + // ADDREPLICAPROP request public static class AddReplicaProp extends AsyncShardSpecificAdminRequest { @@ -1333,14 +1703,26 @@ public abstract class CollectionAdminRequest private String propertyValue; private Boolean shardUnique; + /** + * @deprecated Use {@link #addReplicaProperty(String, String, String, String, String)} + */ + @Deprecated public AddReplicaProp() { - super(CollectionAction.ADDREPLICAPROP); + super(CollectionAction.ADDREPLICAPROP, null, null); + } + + private AddReplicaProp(String collection, String shard, String replica, String propertyName, String propertyValue) { + super(CollectionAction.ADDREPLICAPROP, collection, shard); + this.replica = replica; + this.propertyName = propertyName; + this.propertyValue = propertyValue; } public String getReplica() { return replica; } + @Deprecated public AddReplicaProp setReplica(String replica) { this.replica = replica; return this; @@ -1350,6 +1732,7 @@ public abstract class CollectionAdminRequest return propertyName; } + @Deprecated public AddReplicaProp setPropertyName(String propertyName) { this.propertyName = propertyName; return this; @@ -1359,6 +1742,7 @@ public abstract class CollectionAdminRequest return propertyValue; } + @Deprecated public AddReplicaProp setPropertyValue(String propertyValue) { this.propertyValue = propertyValue; return this; @@ -1374,18 +1758,21 @@ public abstract class CollectionAdminRequest } @Override + @Deprecated public AddReplicaProp setCollectionName(String collection) { this.collection = collection; return this; } @Override + @Deprecated public AddReplicaProp setShardName(String shard) { this.shard = shard; return this; } @Override + @Deprecated public AddReplicaProp setAsyncId(String id) { this.asyncId = id; return this; @@ -1407,20 +1794,39 @@ public abstract class CollectionAdminRequest } + /** + * Returns a SolrRequest to delete a property from a specific replica + */ + public static DeleteReplicaProp deleteReplicaProperty(String collection, String shard, + String replica, String propertyName) { + return new DeleteReplicaProp(collection, shard, replica, propertyName); + } + // DELETEREPLICAPROP request public static class DeleteReplicaProp extends AsyncShardSpecificAdminRequest { private String replica; private String propertyName; + /** + * @deprecated Use {@link #deleteReplicaProperty(String, String, String, String)} + */ + @Deprecated public DeleteReplicaProp() { - super(CollectionAction.DELETEREPLICAPROP); + super(CollectionAction.DELETEREPLICAPROP, null, null); + } + + private DeleteReplicaProp(String collection, String shard, String replica, String propertyName) { + super(CollectionAction.DELETEREPLICAPROP, collection, shard); + this.replica = replica; + this.propertyName = propertyName; } public String getReplica() { return replica; } + @Deprecated public DeleteReplicaProp setReplica(String replica) { this.replica = replica; return this; @@ -1430,24 +1836,28 @@ public abstract class CollectionAdminRequest return propertyName; } + @Deprecated public DeleteReplicaProp setPropertyName(String propertyName) { this.propertyName = propertyName; return this; } @Override + @Deprecated public DeleteReplicaProp setCollectionName(String collection) { this.collection = collection; return this; } @Override + @Deprecated public DeleteReplicaProp setShardName(String shard) { this.shard = shard; return this; } @Override + @Deprecated public DeleteReplicaProp setAsyncId(String id) { this.asyncId = id; return this; @@ -1464,21 +1874,41 @@ public abstract class CollectionAdminRequest } + /** + * Returns a SolrRequest to migrate a collection state format + * + * This is an expert-level request, and should not generally be necessary. + */ + public static MigrateClusterState migrateCollectionFormat(String collection) { + return new MigrateClusterState(collection); + } + // MIGRATECLUSTERSTATE request public static class MigrateClusterState extends AsyncCollectionAdminRequest { protected String collection; + private MigrateClusterState(String collection) { + super(CollectionAction.MIGRATESTATEFORMAT); + this.collection = collection; + } + + /** + * @deprecated Use {@link #migrateCollectionFormat(String)} + */ + @Deprecated public MigrateClusterState() { super(CollectionAction.MIGRATESTATEFORMAT); } + @Deprecated public MigrateClusterState setCollectionName(String collection) { this.collection = collection; return this; } @Override + @Deprecated public MigrateClusterState setAsyncId(String id) { this.asyncId = id; return this; @@ -1494,6 +1924,13 @@ public abstract class CollectionAdminRequest } } + /** + * Returns a SolrRequest to balance a replica property across the shards of a collection + */ + public static BalanceShardUnique balanceReplicaProperty(String collection, String propertyName) { + return new BalanceShardUnique(collection, propertyName); + } + // BALANCESHARDUNIQUE request public static class BalanceShardUnique extends AsyncCollectionAdminRequest { @@ -1502,6 +1939,16 @@ public abstract class CollectionAdminRequest protected Boolean onlyActiveNodes; protected Boolean shardUnique; + private BalanceShardUnique(String collection, String propertyName) { + super(CollectionAction.BALANCESHARDUNIQUE); + this.collection = collection; + this.propertyName = propertyName; + } + + /** + * @deprecated Use {@link #balanceReplicaProperty(String, String)} + */ + @Deprecated public BalanceShardUnique() { super(CollectionAction.BALANCESHARDUNIQUE); } @@ -1510,6 +1957,7 @@ public abstract class CollectionAdminRequest return propertyName; } + @Deprecated public BalanceShardUnique setPropertyName(String propertyName) { this.propertyName = propertyName; return this; @@ -1533,6 +1981,7 @@ public abstract class CollectionAdminRequest return this; } + @Deprecated public BalanceShardUnique setCollection(String collection) { this.collection = collection; return this; @@ -1543,6 +1992,7 @@ public abstract class CollectionAdminRequest } @Override + @Deprecated public BalanceShardUnique setAsyncId(String id) { this.asyncId = id; return this; diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/request/CoreAdminRequest.java b/solr/solrj/src/java/org/apache/solr/client/solrj/request/CoreAdminRequest.java index ab563ed87ed..7d9e356e73f 100644 --- a/solr/solrj/src/java/org/apache/solr/client/solrj/request/CoreAdminRequest.java +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/request/CoreAdminRequest.java @@ -16,6 +16,11 @@ */ package org.apache.solr.client.solrj.request; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrRequest; import org.apache.solr.client.solrj.SolrServerException; @@ -29,11 +34,6 @@ import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.util.ContentStream; -import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; - /** * This class is experimental and subject to change. * @@ -110,11 +110,7 @@ public class CoreAdminRequest extends SolrRequest { */ @Override public void setCoreName(String coreName) { - if (!SolrIdentifierValidator.validateCoreName(coreName)) { - throw new IllegalArgumentException(SolrIdentifierValidator.getIdentifierMessage(SolrIdentifierValidator.IdentifierType.CORE, - coreName)); - } - this.core = coreName; + this.core = SolrIdentifierValidator.validateCoreName(coreName); } @Override @@ -559,14 +555,9 @@ public class CoreAdminRequest extends SolrRequest { */ public static CoreAdminResponse renameCore(String coreName, String newName, SolrClient client ) throws SolrServerException, IOException { - if (!SolrIdentifierValidator.validateCoreName(newName)) { - throw new IllegalArgumentException(SolrIdentifierValidator.getIdentifierMessage(SolrIdentifierValidator.IdentifierType.CORE, - newName)); - } - CoreAdminRequest req = new CoreAdminRequest(); req.setCoreName(coreName); - req.setOtherCoreName(newName); + req.setOtherCoreName(SolrIdentifierValidator.validateCoreName(newName)); req.setAction( CoreAdminAction.RENAME ); return req.process( client ); } diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/util/SolrIdentifierValidator.java b/solr/solrj/src/java/org/apache/solr/client/solrj/util/SolrIdentifierValidator.java index 449c62127b9..57f9909f051 100644 --- a/solr/solrj/src/java/org/apache/solr/client/solrj/util/SolrIdentifierValidator.java +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/util/SolrIdentifierValidator.java @@ -32,18 +32,28 @@ public class SolrIdentifierValidator { SHARD, COLLECTION, CORE, ALIAS } - public static boolean validateShardName(String shardName) { - return validateIdentifier(shardName); + public static String validateName(IdentifierType type, String name) { + if (!validateIdentifier(name)) + throw new IllegalArgumentException(getIdentifierMessage(type, name)); + return name; + } + + public static String validateShardName(String shardName) { + return validateName(IdentifierType.SHARD, shardName); } - public static boolean validateCollectionName(String collectionName) { - return validateIdentifier(collectionName); + public static String validateCollectionName(String collectionName) { + return validateName(IdentifierType.COLLECTION, collectionName); } - - public static boolean validateCoreName(String name) { - return validateIdentifier(name); + + public static String validateAliasName(String alias) { + return validateName(IdentifierType.ALIAS, alias); } - + + public static String validateCoreName(String coreName) { + return validateName(IdentifierType.CORE, coreName); + } + private static boolean validateIdentifier(String identifier) { if (identifier == null || ! identifierPattern.matcher(identifier).matches()) { return false;