diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index ee2c951042a..a39eba43d8e 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -381,6 +381,8 @@ Other Changes * SOLR-7010: Remove facet.date client functionality. (Steve Rowe) +* SOLR-8725: Allow hyphen in collection, core, shard, and alias name as the non-first character (Anshum Gupta) + ================== 5.5.1 ================== Bug Fixes 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 7a55e053d78..9ff45eaf1c2 100644 --- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java +++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java @@ -805,8 +805,7 @@ public class CoreContainer { try { MDCLoggingContext.setCore(core); if (!SolrIdentifierValidator.validateCoreName(dcore.getName())) { - throw new SolrException(ErrorCode.BAD_REQUEST, "Invalid core: " + dcore.getName() - + ". Core names must consist entirely of periods, underscores, and alphanumerics"); + throw new SolrException(ErrorCode.BAD_REQUEST, SolrIdentifierValidator.getIdentifierMessage(SolrIdentifierValidator.IdentifierType.CORE, dcore.getName())); } if (zkSys.getZkController() != null) { zkSys.getZkController().preRegister(dcore); @@ -1010,9 +1009,9 @@ public class CoreContainer { } public void rename(String name, String toName) { - if(!SolrIdentifierValidator.validateCoreName(toName)) { - throw new SolrException(ErrorCode.BAD_REQUEST, "Invalid core: " + toName - + ". Core names must consist entirely of periods, underscores, and alphanumerics"); + if (!SolrIdentifierValidator.validateCoreName(toName)) { + throw new SolrException(ErrorCode.BAD_REQUEST, SolrIdentifierValidator.getIdentifierMessage(SolrIdentifierValidator.IdentifierType.CORE, + toName)); } try (SolrCore core = getCore(name)) { if (core != null) { 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 c81e18371dc..ce4eab213ee 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 @@ -347,14 +347,12 @@ public class CollectionsHandler extends RequestHandlerBase { verifyRuleParams(h.coreContainer, props); final String collectionName = (String) props.get(NAME); if (!SolrIdentifierValidator.validateCollectionName(collectionName)) { - throw new SolrException(ErrorCode.BAD_REQUEST, "Invalid collection: " + collectionName - + ". Collection names must consist entirely of periods, underscores, and alphanumerics"); + throw new SolrException(ErrorCode.BAD_REQUEST, + SolrIdentifierValidator.getIdentifierMessage(SolrIdentifierValidator.IdentifierType.COLLECTION, collectionName)); } final String shardsParam = (String) props.get(SHARDS_PROP); if (StringUtils.isNotEmpty(shardsParam)) { - log.info("Validating shards param!!!!!!!!" + shardsParam); verifyShardsParam(shardsParam); - log.info("Validating shards param!!!!!!! done" + shardsParam); } if (SYSTEM_COLL.equals(collectionName)) { //We must always create a .system collection with only a single shard @@ -434,8 +432,7 @@ public class CollectionsHandler extends RequestHandlerBase { throws Exception { final String aliasName = req.getParams().get(NAME); if (!SolrIdentifierValidator.validateCollectionName(aliasName)) { - throw new SolrException(ErrorCode.BAD_REQUEST, "Invalid alias: " + aliasName - + ". Aliases must consist entirely of periods, underscores, and alphanumerics"); + throw new SolrException(ErrorCode.BAD_REQUEST, SolrIdentifierValidator.getIdentifierMessage(SolrIdentifierValidator.IdentifierType.ALIAS, aliasName)); } return req.getParams().required().getAll(null, NAME, "collections"); } @@ -502,8 +499,8 @@ public class CollectionsHandler extends RequestHandlerBase { 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, "Invalid shard: " + newShardName - + ". Shard names must consist entirely of periods, underscores, and alphanumerics"); + throw new SolrException(ErrorCode.BAD_REQUEST, SolrIdentifierValidator.getIdentifierMessage(SolrIdentifierValidator.IdentifierType.SHARD, + newShardName)); } 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"); @@ -989,8 +986,8 @@ 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, "Invalid shard: " + shard - + ". Shard names must consist entirely of periods, underscores, and alphanumerics");; + throw new SolrException(ErrorCode.BAD_REQUEST, SolrIdentifierValidator.getIdentifierMessage(SolrIdentifierValidator.IdentifierType.SHARD, + shard)); } } diff --git a/solr/core/src/test/org/apache/solr/cloud/TestCollectionAPI.java b/solr/core/src/test/org/apache/solr/cloud/TestCollectionAPI.java index 353c7084f69..b203f02c877 100644 --- a/solr/core/src/test/org/apache/solr/cloud/TestCollectionAPI.java +++ b/solr/core/src/test/org/apache/solr/cloud/TestCollectionAPI.java @@ -649,7 +649,7 @@ public class TestCollectionAPI extends ReplicaPropertiesBase { final String errorMessage = e.getMessage(); assertTrue(errorMessage.contains("Invalid collection")); assertTrue(errorMessage.contains("invalid@name#with$weird%characters")); - assertTrue(errorMessage.contains("Collection names must consist entirely of")); + assertTrue(errorMessage.contains("collection names must consist entirely of")); } } } @@ -672,7 +672,7 @@ public class TestCollectionAPI extends ReplicaPropertiesBase { final String errorMessage = e.getMessage(); assertTrue(errorMessage.contains("Invalid shard")); assertTrue(errorMessage.contains("invalid@name#with$weird%characters")); - assertTrue(errorMessage.contains("Shard names must consist entirely of")); + assertTrue(errorMessage.contains("shard names must consist entirely of")); } } } @@ -693,7 +693,7 @@ public class TestCollectionAPI extends ReplicaPropertiesBase { final String errorMessage = e.getMessage(); assertTrue(errorMessage.contains("Invalid alias")); assertTrue(errorMessage.contains("invalid@name#with$weird%characters")); - assertTrue(errorMessage.contains("Aliases must consist entirely of")); + assertTrue(errorMessage.contains("alias names must consist entirely of")); } } } @@ -726,7 +726,7 @@ public class TestCollectionAPI extends ReplicaPropertiesBase { final String errorMessage = e.getMessage(); assertTrue(errorMessage.contains("Invalid shard")); assertTrue(errorMessage.contains("invalid@name#with$weird%characters")); - assertTrue(errorMessage.contains("Shard names must consist entirely of")); + assertTrue(errorMessage.contains("shard names must consist entirely of")); } } } 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 768de299e29..9aead924968 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 @@ -292,15 +292,15 @@ public abstract class CollectionAdminRequest { @Override public void setCoreName(String coreName) { if (!SolrIdentifierValidator.validateCoreName(coreName)) { - throw new IllegalArgumentException("Invalid core: " + coreName - + ". Core names must consist entirely of periods, underscores, and alphanumerics"); + throw new IllegalArgumentException(SolrIdentifierValidator.getIdentifierMessage(SolrIdentifierValidator.IdentifierType.CORE, + coreName)); } this.core = coreName; } @@ -560,8 +560,8 @@ 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("Invalid core: " + newName - + ". Core names must consist entirely of periods, underscores, and alphanumerics"); + throw new IllegalArgumentException(SolrIdentifierValidator.getIdentifierMessage(SolrIdentifierValidator.IdentifierType.CORE, + newName)); } CoreAdminRequest req = new CoreAdminRequest(); 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 00d9b83f772..2b1f3b5e140 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 @@ -23,11 +23,15 @@ import java.util.regex.Pattern; * Ensures that provided identifiers align with Solr's recommendations/requirements for choosing * collection, core, etc identifiers. * - * Identifiers are allowed to contain underscores, periods, and alphanumeric characters. + * Identifiers are allowed to contain underscores, periods, hyphens, and alphanumeric characters. */ public class SolrIdentifierValidator { - final static Pattern identifierPattern = Pattern.compile("^[\\._A-Za-z0-9]*$"); - + final static Pattern identifierPattern = Pattern.compile("^(?!\\-)[\\._A-Za-z0-9\\-]*$"); + + public enum IdentifierType { + SHARD, COLLECTION, CORE, ALIAS + } + public static boolean validateShardName(String shardName) { return validateIdentifier(shardName); } @@ -46,6 +50,12 @@ public class SolrIdentifierValidator { } return true; } + + public static String getIdentifierMessage(IdentifierType identifierType, String name) { + return "Invalid " + identifierType.toString().toLowerCase() + ": " + name + ". " + identifierType.toString().toLowerCase() + + " names must consist entirely of periods, underscores, hyphens, and alphanumerics"; + + } } diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/request/TestCollectionAdminRequest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/request/TestCollectionAdminRequest.java index ce6a6aad9c8..5d5c31517bd 100644 --- a/solr/solrj/src/test/org/apache/solr/client/solrj/request/TestCollectionAdminRequest.java +++ b/solr/solrj/src/test/org/apache/solr/client/solrj/request/TestCollectionAdminRequest.java @@ -37,7 +37,7 @@ public class TestCollectionAdminRequest extends LuceneTestCase { final String exceptionMessage = e.getMessage(); assertTrue(exceptionMessage.contains("Invalid collection")); assertTrue(exceptionMessage.contains("invalid$collection@name")); - assertTrue(exceptionMessage.contains("must consist entirely of periods, underscores, and alphanumerics")); + assertTrue(exceptionMessage.contains("must consist entirely of periods, underscores, hyphens, and alphanumerics")); } } @@ -51,7 +51,7 @@ public class TestCollectionAdminRequest extends LuceneTestCase { final String exceptionMessage = e.getMessage(); assertTrue(exceptionMessage.contains("Invalid shard")); assertTrue(exceptionMessage.contains("invalid$shard@name")); - assertTrue(exceptionMessage.contains("must consist entirely of periods, underscores, and alphanumerics")); + assertTrue(exceptionMessage.contains("must consist entirely of periods, underscores, hyphens, and alphanumerics")); } } @@ -65,7 +65,7 @@ public class TestCollectionAdminRequest extends LuceneTestCase { final String exceptionMessage = e.getMessage(); assertTrue(exceptionMessage.contains("Invalid alias")); assertTrue(exceptionMessage.contains("invalid$alias@name")); - assertTrue(exceptionMessage.contains("must consist entirely of periods, underscores, and alphanumerics")); + assertTrue(exceptionMessage.contains("must consist entirely of periods, underscores, hyphens, and alphanumerics")); } } @@ -79,7 +79,7 @@ public class TestCollectionAdminRequest extends LuceneTestCase { final String exceptionMessage = e.getMessage(); assertTrue(exceptionMessage.contains("Invalid shard")); assertTrue(exceptionMessage.contains("invalid$shard@name")); - assertTrue(exceptionMessage.contains("must consist entirely of periods, underscores, and alphanumerics")); + assertTrue(exceptionMessage.contains("must consist entirely of periods, underscores, hyphens, and alphanumerics")); } } } diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/request/TestCoreAdmin.java b/solr/solrj/src/test/org/apache/solr/client/solrj/request/TestCoreAdmin.java index 143d2c32c3b..f3c3d55d5fc 100644 --- a/solr/solrj/src/test/org/apache/solr/client/solrj/request/TestCoreAdmin.java +++ b/solr/solrj/src/test/org/apache/solr/client/solrj/request/TestCoreAdmin.java @@ -171,7 +171,7 @@ public class TestCoreAdmin extends AbstractEmbeddedSolrServerTestCase { final String exceptionMessage = e.getMessage(); assertTrue(exceptionMessage.contains("Invalid core")); assertTrue(exceptionMessage.contains("invalid$core@name")); - assertTrue(exceptionMessage.contains("must consist entirely of periods, underscores, and alphanumerics")); + assertTrue(exceptionMessage.contains("must consist entirely of periods, underscores, hyphens, and alphanumerics")); } } @@ -184,7 +184,7 @@ public class TestCoreAdmin extends AbstractEmbeddedSolrServerTestCase { final String exceptionMessage = e.getMessage(); assertTrue(e.getMessage(), exceptionMessage.contains("Invalid core")); assertTrue(exceptionMessage.contains("invalid$core@name")); - assertTrue(exceptionMessage.contains("must consist entirely of periods, underscores, and alphanumerics")); + assertTrue(exceptionMessage.contains("must consist entirely of periods, underscores, hyphens, and alphanumerics")); } }