diff --git a/buildSrc/src/main/resources/checkstyle_suppressions.xml b/buildSrc/src/main/resources/checkstyle_suppressions.xml index a089d677dc9a5..6593527f23c04 100644 --- a/buildSrc/src/main/resources/checkstyle_suppressions.xml +++ b/buildSrc/src/main/resources/checkstyle_suppressions.xml @@ -256,7 +256,6 @@ - @@ -564,8 +563,6 @@ - - @@ -654,7 +651,6 @@ - diff --git a/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/create/CreateSnapshotRequest.java b/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/create/CreateSnapshotRequest.java index 9cbc1b6563242..ae715050e80b5 100644 --- a/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/create/CreateSnapshotRequest.java +++ b/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/create/CreateSnapshotRequest.java @@ -42,7 +42,7 @@ import static org.elasticsearch.common.settings.Settings.readSettingsFromStream; import static org.elasticsearch.common.settings.Settings.writeSettingsToStream; import static org.elasticsearch.common.settings.Settings.Builder.EMPTY_SETTINGS; -import static org.elasticsearch.common.xcontent.support.XContentMapValues.lenientNodeBooleanValue; +import static org.elasticsearch.common.xcontent.support.XContentMapValues.nodeBooleanValue; /** * Create snapshot request @@ -366,14 +366,14 @@ public CreateSnapshotRequest source(Map source) { throw new IllegalArgumentException("malformed indices section, should be an array of strings"); } } else if (name.equals("partial")) { - partial(lenientNodeBooleanValue(entry.getValue())); + partial(nodeBooleanValue(entry.getValue(), "partial")); } else if (name.equals("settings")) { if (!(entry.getValue() instanceof Map)) { throw new IllegalArgumentException("malformed settings section, should indices an inner object"); } settings((Map) entry.getValue()); } else if (name.equals("include_global_state")) { - includeGlobalState = lenientNodeBooleanValue(entry.getValue()); + includeGlobalState = nodeBooleanValue(entry.getValue(), "include_global_state"); } } indicesOptions(IndicesOptions.fromMap((Map) source, IndicesOptions.lenientExpandOpen())); diff --git a/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequest.java b/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequest.java index 641525f00e8bd..a7bbd02ee54eb 100644 --- a/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequest.java +++ b/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequest.java @@ -40,7 +40,7 @@ import static org.elasticsearch.common.settings.Settings.readSettingsFromStream; import static org.elasticsearch.common.settings.Settings.writeSettingsToStream; import static org.elasticsearch.common.settings.Settings.Builder.EMPTY_SETTINGS; -import static org.elasticsearch.common.xcontent.support.XContentMapValues.lenientNodeBooleanValue; +import static org.elasticsearch.common.xcontent.support.XContentMapValues.nodeBooleanValue; /** * Restore snapshot request @@ -481,16 +481,16 @@ public RestoreSnapshotRequest source(Map source) { throw new IllegalArgumentException("malformed indices section, should be an array of strings"); } } else if (name.equals("partial")) { - partial(lenientNodeBooleanValue(entry.getValue())); + partial(nodeBooleanValue(entry.getValue(), "partial")); } else if (name.equals("settings")) { if (!(entry.getValue() instanceof Map)) { throw new IllegalArgumentException("malformed settings section"); } settings((Map) entry.getValue()); } else if (name.equals("include_global_state")) { - includeGlobalState = lenientNodeBooleanValue(entry.getValue()); + includeGlobalState = nodeBooleanValue(entry.getValue(), "include_global_state"); } else if (name.equals("include_aliases")) { - includeAliases = lenientNodeBooleanValue(entry.getValue()); + includeAliases = nodeBooleanValue(entry.getValue(), "include_aliases"); } else if (name.equals("rename_pattern")) { if (entry.getValue() instanceof String) { renamePattern((String) entry.getValue()); diff --git a/core/src/main/java/org/elasticsearch/action/admin/indices/flush/TransportShardFlushAction.java b/core/src/main/java/org/elasticsearch/action/admin/indices/flush/TransportShardFlushAction.java index b04bb86a63c28..026946334ac6a 100644 --- a/core/src/main/java/org/elasticsearch/action/admin/indices/flush/TransportShardFlushAction.java +++ b/core/src/main/java/org/elasticsearch/action/admin/indices/flush/TransportShardFlushAction.java @@ -23,7 +23,7 @@ import org.elasticsearch.action.support.replication.ReplicationResponse; import org.elasticsearch.action.support.replication.TransportReplicationAction; import org.elasticsearch.cluster.action.shard.ShardStateAction; -import org.elasticsearch.cluster.block.ClusterBlockLevel; +import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.inject.Inject; @@ -65,7 +65,7 @@ protected ReplicaResult shardOperationOnReplica(ShardFlushRequest request, Index } @Override - protected boolean shouldExecuteReplication(Settings settings) { + protected boolean shouldExecuteReplication(IndexMetaData indexMetaData) { return true; } } diff --git a/core/src/main/java/org/elasticsearch/action/admin/indices/refresh/TransportShardRefreshAction.java b/core/src/main/java/org/elasticsearch/action/admin/indices/refresh/TransportShardRefreshAction.java index d8e9d8c0b9e72..d1d8b4078b647 100644 --- a/core/src/main/java/org/elasticsearch/action/admin/indices/refresh/TransportShardRefreshAction.java +++ b/core/src/main/java/org/elasticsearch/action/admin/indices/refresh/TransportShardRefreshAction.java @@ -24,7 +24,7 @@ import org.elasticsearch.action.support.replication.ReplicationResponse; import org.elasticsearch.action.support.replication.TransportReplicationAction; import org.elasticsearch.cluster.action.shard.ShardStateAction; -import org.elasticsearch.cluster.block.ClusterBlockLevel; +import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.inject.Inject; @@ -68,7 +68,7 @@ protected ReplicaResult shardOperationOnReplica(BasicReplicationRequest request, } @Override - protected boolean shouldExecuteReplication(Settings settings) { + protected boolean shouldExecuteReplication(IndexMetaData indexMetaData) { return true; } } diff --git a/core/src/main/java/org/elasticsearch/action/get/MultiGetRequest.java b/core/src/main/java/org/elasticsearch/action/get/MultiGetRequest.java index 5407184ded31a..d4627391b1169 100644 --- a/core/src/main/java/org/elasticsearch/action/get/MultiGetRequest.java +++ b/core/src/main/java/org/elasticsearch/action/get/MultiGetRequest.java @@ -379,7 +379,8 @@ public static void parseDocuments(XContentParser parser, List items, @Null } else if ("_version_type".equals(currentFieldName) || "_versionType".equals(currentFieldName) || "version_type".equals(currentFieldName) || "versionType".equals(currentFieldName)) { versionType = VersionType.fromString(parser.text()); } else if ("_source".equals(currentFieldName)) { - if (parser.isBooleanValue()) { + // check lenient to avoid interpreting the value as string but parse strict in order to provoke an error early on. + if (parser.isBooleanValueLenient()) { fetchSourceContext = new FetchSourceContext(parser.booleanValue(), fetchSourceContext.includes(), fetchSourceContext.excludes()); } else if (token == XContentParser.Token.VALUE_STRING) { diff --git a/core/src/main/java/org/elasticsearch/action/get/TransportGetAction.java b/core/src/main/java/org/elasticsearch/action/get/TransportGetAction.java index 6b9de7ecf64e3..ee835fa06be5e 100644 --- a/core/src/main/java/org/elasticsearch/action/get/TransportGetAction.java +++ b/core/src/main/java/org/elasticsearch/action/get/TransportGetAction.java @@ -71,7 +71,7 @@ protected void resolveRequest(ClusterState state, InternalRequest request) { if (request.request().realtime && // if the realtime flag is set request.request().preference() == null && // the preference flag is not already set indexMeta != null && // and we have the index - IndexMetaData.isIndexUsingShadowReplicas(indexMeta.getSettings())) { // and the index uses shadow replicas + indexMeta.isIndexUsingShadowReplicas()) { // and the index uses shadow replicas // set the preference for the request to use "_primary" automatically request.request().preference(Preference.PRIMARY.type()); } diff --git a/core/src/main/java/org/elasticsearch/action/support/AutoCreateIndex.java b/core/src/main/java/org/elasticsearch/action/support/AutoCreateIndex.java index a9a5afed9f315..be039d80d9f73 100644 --- a/core/src/main/java/org/elasticsearch/action/support/AutoCreateIndex.java +++ b/core/src/main/java/org/elasticsearch/action/support/AutoCreateIndex.java @@ -106,7 +106,7 @@ private AutoCreate(String value) { boolean autoCreateIndex; List> expressions = new ArrayList<>(); try { - autoCreateIndex = Booleans.parseBooleanExact(value); + autoCreateIndex = Booleans.parseBoolean(value); } catch (IllegalArgumentException ex) { try { String[] patterns = Strings.commaDelimitedListToStringArray(value); diff --git a/core/src/main/java/org/elasticsearch/action/support/IndicesOptions.java b/core/src/main/java/org/elasticsearch/action/support/IndicesOptions.java index 2bc49f7e9f869..b82bfcc7170d8 100644 --- a/core/src/main/java/org/elasticsearch/action/support/IndicesOptions.java +++ b/core/src/main/java/org/elasticsearch/action/support/IndicesOptions.java @@ -26,7 +26,7 @@ import java.io.IOException; import java.util.Map; -import static org.elasticsearch.common.xcontent.support.XContentMapValues.lenientNodeBooleanValue; +import static org.elasticsearch.common.xcontent.support.XContentMapValues.nodeBooleanValue; import static org.elasticsearch.common.xcontent.support.XContentMapValues.nodeStringArrayValue; /** @@ -195,8 +195,8 @@ public static IndicesOptions fromParameters(Object wildcardsString, Object ignor //note that allowAliasesToMultipleIndices is not exposed, always true (only for internal use) return fromOptions( - lenientNodeBooleanValue(ignoreUnavailableString, defaultSettings.ignoreUnavailable()), - lenientNodeBooleanValue(allowNoIndicesString, defaultSettings.allowNoIndices()), + nodeBooleanValue(ignoreUnavailableString, "ignore_unavailable", defaultSettings.ignoreUnavailable()), + nodeBooleanValue(allowNoIndicesString, "allow_no_indices", defaultSettings.allowNoIndices()), expandWildcardsOpen, expandWildcardsClosed, defaultSettings.allowAliasesToMultipleIndices(), @@ -279,7 +279,7 @@ public String toString() { ", allow_no_indices=" + allowNoIndices() + ", expand_wildcards_open=" + expandWildcardsOpen() + ", expand_wildcards_closed=" + expandWildcardsClosed() + - ", allow_alisases_to_multiple_indices=" + allowAliasesToMultipleIndices() + + ", allow_aliases_to_multiple_indices=" + allowAliasesToMultipleIndices() + ", forbid_closed_indices=" + forbidClosedIndices() + ']'; } diff --git a/core/src/main/java/org/elasticsearch/action/support/replication/TransportReplicationAction.java b/core/src/main/java/org/elasticsearch/action/support/replication/TransportReplicationAction.java index d3646ac98e7c2..6fec41ff9a3cd 100644 --- a/core/src/main/java/org/elasticsearch/action/support/replication/TransportReplicationAction.java +++ b/core/src/main/java/org/elasticsearch/action/support/replication/TransportReplicationAction.java @@ -315,7 +315,7 @@ public void handleException(TransportException exp) { } else { setPhase(replicationTask, "primary"); final IndexMetaData indexMetaData = clusterService.state().getMetaData().index(request.shardId().getIndex()); - final boolean executeOnReplicas = (indexMetaData == null) || shouldExecuteReplication(indexMetaData.getSettings()); + final boolean executeOnReplicas = (indexMetaData == null) || shouldExecuteReplication(indexMetaData); final ActionListener listener = createResponseListener(primaryShardReference); createReplicatedOperation(request, ActionListener.wrap(result -> result.respond(listener), listener::onFailure), @@ -914,8 +914,8 @@ public void onFailure(Exception e) { * Indicated whether this operation should be replicated to shadow replicas or not. If this method returns true the replication phase * will be skipped. For example writes such as index and delete don't need to be replicated on shadow replicas but refresh and flush do. */ - protected boolean shouldExecuteReplication(Settings settings) { - return IndexMetaData.isIndexUsingShadowReplicas(settings) == false; + protected boolean shouldExecuteReplication(IndexMetaData indexMetaData) { + return indexMetaData.isIndexUsingShadowReplicas() == false; } class ShardReference implements Releasable { diff --git a/core/src/main/java/org/elasticsearch/cluster/InternalClusterInfoService.java b/core/src/main/java/org/elasticsearch/cluster/InternalClusterInfoService.java index b8ac2a5eb50c3..a9392d3c017de 100644 --- a/core/src/main/java/org/elasticsearch/cluster/InternalClusterInfoService.java +++ b/core/src/main/java/org/elasticsearch/cluster/InternalClusterInfoService.java @@ -377,14 +377,13 @@ static void buildShardLevelInfo(Logger logger, ShardStats[] stats, ImmutableOpen MetaData meta = state.getMetaData(); for (ShardStats s : stats) { IndexMetaData indexMeta = meta.index(s.getShardRouting().index()); - Settings indexSettings = indexMeta == null ? null : indexMeta.getSettings(); newShardRoutingToDataPath.put(s.getShardRouting(), s.getDataPath()); long size = s.getStats().getStore().sizeInBytes(); String sid = ClusterInfo.shardIdentifierFromRouting(s.getShardRouting()); if (logger.isTraceEnabled()) { logger.trace("shard: {} size: {}", sid, size); } - if (indexSettings != null && IndexMetaData.isIndexUsingShadowReplicas(indexSettings)) { + if (indexMeta != null && indexMeta.isIndexUsingShadowReplicas()) { // Shards on a shared filesystem should be considered of size 0 if (logger.isTraceEnabled()) { logger.trace("shard: {} is using shadow replicas and will be treated as size 0", sid); diff --git a/core/src/main/java/org/elasticsearch/cluster/metadata/AutoExpandReplicas.java b/core/src/main/java/org/elasticsearch/cluster/metadata/AutoExpandReplicas.java index 4b4a8e54d7c6c..fa30abe5a736b 100644 --- a/core/src/main/java/org/elasticsearch/cluster/metadata/AutoExpandReplicas.java +++ b/core/src/main/java/org/elasticsearch/cluster/metadata/AutoExpandReplicas.java @@ -33,7 +33,7 @@ final class AutoExpandReplicas { public static final Setting SETTING = new Setting<>(IndexMetaData.SETTING_AUTO_EXPAND_REPLICAS, "false", (value) -> { final int min; final int max; - if (Booleans.parseBoolean(value, true) == false) { + if (Booleans.isFalse(value)) { return new AutoExpandReplicas(0, 0, false); } final int dash = value.indexOf('-'); diff --git a/core/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java b/core/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java index ba5ce1067b3bb..6865983e180c7 100644 --- a/core/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java +++ b/core/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java @@ -1263,9 +1263,10 @@ public static IndexMetaData fromXContent(XContentParser parser) throws IOExcepti * is the returned value from * {@link #isIndexUsingShadowReplicas(org.elasticsearch.common.settings.Settings)}. */ - public static boolean isOnSharedFilesystem(Settings settings) { + public boolean isOnSharedFilesystem(Settings settings) { // don't use the setting directly, not to trigger verbose deprecation logging - return settings.getAsBoolean(SETTING_SHARED_FILESYSTEM, isIndexUsingShadowReplicas(settings)); + return settings.getAsBooleanLenientForPreEs6Indices( + this.indexCreatedVersion, SETTING_SHARED_FILESYSTEM, isIndexUsingShadowReplicas(settings)); } /** @@ -1273,9 +1274,13 @@ public static boolean isOnSharedFilesystem(Settings settings) { * with these settings uses shadow replicas. Otherwise false. The default * setting for this is false. */ - public static boolean isIndexUsingShadowReplicas(Settings settings) { + public boolean isIndexUsingShadowReplicas() { + return isIndexUsingShadowReplicas(this.settings); + } + + public boolean isIndexUsingShadowReplicas(Settings settings) { // don't use the setting directly, not to trigger verbose deprecation logging - return settings.getAsBoolean(SETTING_SHADOW_REPLICAS, false); + return settings.getAsBooleanLenientForPreEs6Indices(this.indexCreatedVersion, SETTING_SHADOW_REPLICAS, false); } /** diff --git a/core/src/main/java/org/elasticsearch/cluster/metadata/MappingMetaData.java b/core/src/main/java/org/elasticsearch/cluster/metadata/MappingMetaData.java index c9a0c6175532b..08d5211e12d74 100644 --- a/core/src/main/java/org/elasticsearch/cluster/metadata/MappingMetaData.java +++ b/core/src/main/java/org/elasticsearch/cluster/metadata/MappingMetaData.java @@ -34,7 +34,7 @@ import java.io.IOException; import java.util.Map; -import static org.elasticsearch.common.xcontent.support.XContentMapValues.lenientNodeBooleanValue; +import static org.elasticsearch.common.xcontent.support.XContentMapValues.nodeBooleanValue; /** * Mapping configuration for a type. @@ -95,10 +95,6 @@ public MappingMetaData(CompressedXContent mapping) throws IOException { initMappers((Map) mappingMap.get(this.type)); } - public MappingMetaData(Map mapping) throws IOException { - this(mapping.keySet().iterator().next(), mapping); - } - public MappingMetaData(String type, Map mapping) throws IOException { this.type = type; XContentBuilder mappingBuilder = XContentFactory.jsonBuilder().map(mapping); @@ -127,7 +123,12 @@ private void initMappers(Map withoutType) { String fieldName = entry.getKey(); Object fieldNode = entry.getValue(); if (fieldName.equals("required")) { - required = lenientNodeBooleanValue(fieldNode); + try { + required = nodeBooleanValue(fieldNode); + } catch (IllegalArgumentException ex) { + throw new IllegalArgumentException("Failed to create mapping for type [" + this.type() + "]. " + + "Illegal value in field [_routing.required].", ex); + } } } this.routing = new Routing(required); diff --git a/core/src/main/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexService.java b/core/src/main/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexService.java index 64f96c8e263bb..7015695948930 100644 --- a/core/src/main/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexService.java +++ b/core/src/main/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexService.java @@ -428,7 +428,7 @@ public ClusterState execute(ClusterState currentState) throws Exception { .put(indexMetaData, false) .build(); - String maybeShadowIndicator = IndexMetaData.isIndexUsingShadowReplicas(indexMetaData.getSettings()) ? "s" : ""; + String maybeShadowIndicator = indexMetaData.isIndexUsingShadowReplicas() ? "s" : ""; logger.info("[{}] creating index, cause [{}], templates {}, shards [{}]/[{}{}], mappings {}", request.index(), request.cause(), templateNames, indexMetaData.getNumberOfShards(), indexMetaData.getNumberOfReplicas(), maybeShadowIndicator, mappings.keySet()); diff --git a/core/src/main/java/org/elasticsearch/cluster/routing/IndexRoutingTable.java b/core/src/main/java/org/elasticsearch/cluster/routing/IndexRoutingTable.java index 1d137d30dba37..53590550d84df 100644 --- a/core/src/main/java/org/elasticsearch/cluster/routing/IndexRoutingTable.java +++ b/core/src/main/java/org/elasticsearch/cluster/routing/IndexRoutingTable.java @@ -140,7 +140,7 @@ boolean validate(MetaData metaData) { } if (indexMetaData.getCreationVersion().onOrAfter(Version.V_5_0_0_alpha1) && - IndexMetaData.isIndexUsingShadowReplicas(indexMetaData.getSettings()) == false && // see #20650 + indexMetaData.isIndexUsingShadowReplicas() == false && // see #20650 shardRouting.primary() && shardRouting.initializing() && shardRouting.relocating() == false && RecoverySource.isInitialRecovery(shardRouting.recoverySource().getType()) == false && inSyncAllocationIds.contains(shardRouting.allocationId().getId()) == false) diff --git a/core/src/main/java/org/elasticsearch/cluster/routing/RoutingNodes.java b/core/src/main/java/org/elasticsearch/cluster/routing/RoutingNodes.java index 6b0b13247170b..45d567b657e9b 100644 --- a/core/src/main/java/org/elasticsearch/cluster/routing/RoutingNodes.java +++ b/core/src/main/java/org/elasticsearch/cluster/routing/RoutingNodes.java @@ -540,7 +540,7 @@ assert getByAllocationId(failedShard.shardId(), failedShard.allocationId().getId if (failedShard.primary()) { // promote active replica to primary if active replica exists (only the case for shadow replicas) ShardRouting activeReplica = activeReplica(failedShard.shardId()); - assert activeReplica == null || IndexMetaData.isIndexUsingShadowReplicas(indexMetaData.getSettings()) : + assert activeReplica == null || indexMetaData.isIndexUsingShadowReplicas() : "initializing primary [" + failedShard + "] with active replicas [" + activeReplica + "] only expected when " + "using shadow replicas"; if (activeReplica == null) { @@ -599,7 +599,7 @@ private void promoteReplicaToPrimary(ShardRouting activeReplica, IndexMetaData i assert activeReplica.started() : "replica relocation should have been cancelled: " + activeReplica; ShardRouting primarySwappedCandidate = promoteActiveReplicaShardToPrimary(activeReplica); routingChangesObserver.replicaPromoted(activeReplica); - if (IndexMetaData.isIndexUsingShadowReplicas(indexMetaData.getSettings())) { + if (indexMetaData.isIndexUsingShadowReplicas()) { ShardRouting initializedShard = reinitShadowPrimary(primarySwappedCandidate); routingChangesObserver.startedPrimaryReinitialized(primarySwappedCandidate, initializedShard); } diff --git a/core/src/main/java/org/elasticsearch/common/Booleans.java b/core/src/main/java/org/elasticsearch/common/Booleans.java index 9ec1ac968aca6..025174c477d64 100644 --- a/core/src/main/java/org/elasticsearch/common/Booleans.java +++ b/core/src/main/java/org/elasticsearch/common/Booleans.java @@ -19,34 +19,28 @@ package org.elasticsearch.common; -public class Booleans { +public final class Booleans { + private Booleans() { + throw new AssertionError("No instances intended"); + } /** - * Returns false if text is in false, 0, off, no; else, true + * Parses a char[] representation of a boolean value to boolean. + * + * @return true iff the sequence of chars is "true", false iff the sequence of chars is "false" or the + * provided default value iff either text is null or length == 0. + * @throws IllegalArgumentException if the string cannot be parsed to boolean. */ public static boolean parseBoolean(char[] text, int offset, int length, boolean defaultValue) { - // TODO: the leniency here is very dangerous: a simple typo will be misinterpreted and the user won't know. - // We should remove it and cutover to https://github.com/rmuir/booleanparser if (text == null || length == 0) { return defaultValue; + } else { + return parseBoolean(new String(text, offset, length)); } - if (length == 1) { - return text[offset] != '0'; - } - if (length == 2) { - return !(text[offset] == 'n' && text[offset + 1] == 'o'); - } - if (length == 3) { - return !(text[offset] == 'o' && text[offset + 1] == 'f' && text[offset + 2] == 'f'); - } - if (length == 5) { - return !(text[offset] == 'f' && text[offset + 1] == 'a' && text[offset + 2] == 'l' && text[offset + 3] == 's' && text[offset + 4] == 'e'); - } - return true; } /** - * returns true if the a sequence of chars is one of "true","false","on","off","yes","no","0","1" + * returns true iff the sequence of chars is one of "true","false". * * @param text sequence to check * @param offset offset to start @@ -56,55 +50,70 @@ public static boolean isBoolean(char[] text, int offset, int length) { if (text == null || length == 0) { return false; } - if (length == 1) { - return text[offset] == '0' || text[offset] == '1'; - } - if (length == 2) { - return (text[offset] == 'n' && text[offset + 1] == 'o') || (text[offset] == 'o' && text[offset + 1] == 'n'); - } - if (length == 3) { - return (text[offset] == 'o' && text[offset + 1] == 'f' && text[offset + 2] == 'f') || - (text[offset] == 'y' && text[offset + 1] == 'e' && text[offset + 2] == 's'); - } - if (length == 4) { - return (text[offset] == 't' && text[offset + 1] == 'r' && text[offset + 2] == 'u' && text[offset + 3] == 'e'); - } - if (length == 5) { - return (text[offset] == 'f' && text[offset + 1] == 'a' && text[offset + 2] == 'l' && text[offset + 3] == 's' && text[offset + 4] == 'e'); - } - return false; + return isBoolean(new String(text, offset, length)); + } + + public static boolean isBoolean(String value) { + return isFalse(value) || isTrue(value); } - /*** + /** + * Parses a string representation of a boolean value to boolean. * - * @return true/false - * throws exception if string cannot be parsed to boolean + * @return true iff the provided value is "true". false iff the provided value is "false". + * @throws IllegalArgumentException if the string cannot be parsed to boolean. */ - public static Boolean parseBooleanExact(String value) { - boolean isFalse = isExplicitFalse(value); - if (isFalse) { + public static boolean parseBoolean(String value) { + if (isFalse(value)) { return false; } - boolean isTrue = isExplicitTrue(value); - if (isTrue) { + if (isTrue(value)) { return true; } + throw new IllegalArgumentException("Failed to parse value [" + value + "] as only [true] or [false] are allowed."); + } - throw new IllegalArgumentException("Failed to parse value [" + value + "] cannot be parsed to boolean [ true/1/on/yes OR false/0/off/no ]"); + /** + * + * @param value text to parse. + * @param defaultValue The default value to return if the provided value is null. + * @return see {@link #parseBoolean(String)} + */ + public static boolean parseBoolean(String value, boolean defaultValue) { + if (Strings.hasText(value)) { + return parseBoolean(value); + } + return defaultValue; } public static Boolean parseBoolean(String value, Boolean defaultValue) { + if (Strings.hasText(value)) { + return parseBoolean(value); + } + return defaultValue; + } + + /** + * Returns false if text is in false, 0, off, no; else, true + * + * @deprecated Only kept to provide automatic upgrades for pre 6.0 indices. Use {@link #parseBoolean(String, Boolean)} instead. + */ + @Deprecated + public static Boolean parseBooleanLenient(String value, Boolean defaultValue) { if (value == null) { // only for the null case we do that here! return defaultValue; } - return parseBoolean(value, false); + return parseBooleanLenient(value, false); } /** * Returns true iff the value is neither of the following: * false, 0, off, no * otherwise false + * + * @deprecated Only kept to provide automatic upgrades for pre 6.0 indices. Use {@link #parseBoolean(String, boolean)} instead. */ - public static boolean parseBoolean(String value, boolean defaultValue) { + @Deprecated + public static boolean parseBooleanLenient(String value, boolean defaultValue) { if (value == null) { return defaultValue; } @@ -112,21 +121,77 @@ public static boolean parseBoolean(String value, boolean defaultValue) { } /** - * Returns true iff the value is either of the following: - * false, 0, off, no - * otherwise false + * @return true iff the value is false, otherwise false. */ - public static boolean isExplicitFalse(String value) { - return value != null && (value.equals("false") || value.equals("0") || value.equals("off") || value.equals("no")); + public static boolean isFalse(String value) { + return "false".equals(value); } /** - * Returns true iff the value is either of the following: - * true, 1, on, yes - * otherwise false + * @return true iff the value is true, otherwise false + */ + public static boolean isTrue(String value) { + return "true".equals(value); + } + + /** + * Returns false if text is in false, 0, off, no; else, true + * + * @deprecated Only kept to provide automatic upgrades for pre 6.0 indices. Use {@link #parseBoolean(char[], int, int, boolean)} instead + */ + @Deprecated + public static boolean parseBooleanLenient(char[] text, int offset, int length, boolean defaultValue) { + if (text == null || length == 0) { + return defaultValue; + } + if (length == 1) { + return text[offset] != '0'; + } + if (length == 2) { + return !(text[offset] == 'n' && text[offset + 1] == 'o'); + } + if (length == 3) { + return !(text[offset] == 'o' && text[offset + 1] == 'f' && text[offset + 2] == 'f'); + } + if (length == 5) { + return !(text[offset] == 'f' && text[offset + 1] == 'a' && text[offset + 2] == 'l' && text[offset + 3] == 's' && + text[offset + 4] == 'e'); + } + return true; + } + + /** + * returns true if the a sequence of chars is one of "true","false","on","off","yes","no","0","1" + * + * @param text sequence to check + * @param offset offset to start + * @param length length to check + * + * @deprecated Only kept to provide automatic upgrades for pre 6.0 indices. Use {@link #isBoolean(char[], int, int)} instead. */ - public static boolean isExplicitTrue(String value) { - return value != null && (value.equals("true") || value.equals("1") || value.equals("on") || value.equals("yes")); + @Deprecated + public static boolean isBooleanLenient(char[] text, int offset, int length) { + if (text == null || length == 0) { + return false; + } + if (length == 1) { + return text[offset] == '0' || text[offset] == '1'; + } + if (length == 2) { + return (text[offset] == 'n' && text[offset + 1] == 'o') || (text[offset] == 'o' && text[offset + 1] == 'n'); + } + if (length == 3) { + return (text[offset] == 'o' && text[offset + 1] == 'f' && text[offset + 2] == 'f') || + (text[offset] == 'y' && text[offset + 1] == 'e' && text[offset + 2] == 's'); + } + if (length == 4) { + return (text[offset] == 't' && text[offset + 1] == 'r' && text[offset + 2] == 'u' && text[offset + 3] == 'e'); + } + if (length == 5) { + return (text[offset] == 'f' && text[offset + 1] == 'a' && text[offset + 2] == 'l' && text[offset + 3] == 's' && + text[offset + 4] == 'e'); + } + return false; } } diff --git a/core/src/main/java/org/elasticsearch/common/TriFunction.java b/core/src/main/java/org/elasticsearch/common/TriFunction.java new file mode 100644 index 0000000000000..85655863a4f9e --- /dev/null +++ b/core/src/main/java/org/elasticsearch/common/TriFunction.java @@ -0,0 +1,42 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.common; + +/** + * Represents a function that accepts three arguments and produces a result. + * + * @param the type of the first argument + * @param the type of the second argument + * @param the type of the third argument + * @param the return type + */ +@FunctionalInterface +public interface TriFunction { + /** + * Applies this function to the given arguments. + * + * @param s the first function argument + * @param t the second function argument + * @param u the third function argument + * @return the result + */ + R apply(S s, T t, U u); +} diff --git a/core/src/main/java/org/elasticsearch/common/settings/Setting.java b/core/src/main/java/org/elasticsearch/common/settings/Setting.java index 45ebe1b061c62..74e10bd6e11b3 100644 --- a/core/src/main/java/org/elasticsearch/common/settings/Setting.java +++ b/core/src/main/java/org/elasticsearch/common/settings/Setting.java @@ -668,15 +668,15 @@ public static Setting intSetting(String key, int defaultValue, Property } public static Setting boolSetting(String key, boolean defaultValue, Property... properties) { - return new Setting<>(key, (s) -> Boolean.toString(defaultValue), Booleans::parseBooleanExact, properties); + return new Setting<>(key, (s) -> Boolean.toString(defaultValue), Booleans::parseBoolean, properties); } public static Setting boolSetting(String key, Setting fallbackSetting, Property... properties) { - return new Setting<>(key, fallbackSetting, Booleans::parseBooleanExact, properties); + return new Setting<>(key, fallbackSetting, Booleans::parseBoolean, properties); } public static Setting boolSetting(String key, Function defaultValueFn, Property... properties) { - return new Setting<>(key, defaultValueFn, Booleans::parseBooleanExact, properties); + return new Setting<>(key, defaultValueFn, Booleans::parseBoolean, properties); } public static Setting byteSizeSetting(String key, ByteSizeValue value, Property... properties) { diff --git a/core/src/main/java/org/elasticsearch/common/settings/Settings.java b/core/src/main/java/org/elasticsearch/common/settings/Settings.java index ef9ff00a1f029..e588b28b6354b 100644 --- a/core/src/main/java/org/elasticsearch/common/settings/Settings.java +++ b/core/src/main/java/org/elasticsearch/common/settings/Settings.java @@ -26,6 +26,8 @@ import org.elasticsearch.common.io.Streams; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.logging.DeprecationLogger; +import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.settings.loader.SettingsLoader; import org.elasticsearch.common.settings.loader.SettingsLoaderFactory; import org.elasticsearch.common.unit.ByteSizeUnit; @@ -74,6 +76,7 @@ * An immutable settings implementation. */ public final class Settings implements ToXContent { + private static final DeprecationLogger deprecationLogger = new DeprecationLogger(Loggers.getLogger(Settings.class)); public static final Settings EMPTY = new Builder().build(); private static final Pattern ARRAY_PATTERN = Pattern.compile("(.*)\\.\\d+$"); @@ -313,6 +316,32 @@ public Boolean getAsBoolean(String setting, Boolean defaultValue) { return Booleans.parseBoolean(get(setting), defaultValue); } + // TODO #22298: Delete this method and update call sites to #getAsBoolean(String, Boolean). + /** + * Returns the setting value (as boolean) associated with the setting key. If it does not exist, returns the default value provided. + * If the index was created on Elasticsearch below 6.0, booleans will be parsed leniently otherwise they are parsed strictly. + * + * See {@link Booleans#isBooleanLenient(char[], int, int)} for the definition of a "lenient boolean" + * and {@link Booleans#isBoolean(char[], int, int)} for the definition of a "strict boolean". + * + * @deprecated Only used to provide automatic upgrades for pre 6.0 indices. + */ + @Deprecated + public Boolean getAsBooleanLenientForPreEs6Indices(Version indexVersion, String setting, Boolean defaultValue) { + if (indexVersion.before(Version.V_6_0_0_alpha1_UNRELEASED)) { + //Only emit a warning if the setting's value is not a proper boolean + final String value = get(setting, "false"); + if (Booleans.isBoolean(value) == false) { + @SuppressWarnings("deprecation") + boolean convertedValue = Booleans.parseBooleanLenient(get(setting), defaultValue); + deprecationLogger.deprecated("The value [{}] of setting [{}] is not coerced into boolean anymore. Please change " + + "this value to [{}].", value, setting, String.valueOf(convertedValue)); + return convertedValue; + } + } + return getAsBoolean(setting, defaultValue); + } + /** * Returns the setting value (as time) associated with the setting key. If it does not exists, * returns the default value provided. diff --git a/core/src/main/java/org/elasticsearch/common/xcontent/XContent.java b/core/src/main/java/org/elasticsearch/common/xcontent/XContent.java index e7dbeafe5d0db..879b9e9d723f6 100644 --- a/core/src/main/java/org/elasticsearch/common/xcontent/XContent.java +++ b/core/src/main/java/org/elasticsearch/common/xcontent/XContent.java @@ -52,7 +52,7 @@ public interface XContent { */ static boolean isStrictDuplicateDetectionEnabled() { // Don't allow duplicate keys in JSON content by default but let the user opt out - return Booleans.parseBooleanExact(System.getProperty("es.xcontent.strict_duplicate_detection", "true")); + return Booleans.parseBoolean(System.getProperty("es.xcontent.strict_duplicate_detection", "true")); } /** diff --git a/core/src/main/java/org/elasticsearch/common/xcontent/XContentParser.java b/core/src/main/java/org/elasticsearch/common/xcontent/XContentParser.java index 7ca77442268cd..e1f1c4b3f8a1f 100644 --- a/core/src/main/java/org/elasticsearch/common/xcontent/XContentParser.java +++ b/core/src/main/java/org/elasticsearch/common/xcontent/XContentParser.java @@ -201,16 +201,32 @@ enum NumberType { double doubleValue() throws IOException; + /** + * @return true iff the current value is either boolean (true or false) or one of "false", "true". + */ + boolean isBooleanValue() throws IOException; + + boolean booleanValue() throws IOException; + + // TODO #22298: Remove this method and replace all call sites with #isBooleanValue() /** * returns true if the current value is boolean in nature. * values that are considered booleans: * - boolean value (true/false) * - numeric integers (=0 is considered as false, !=0 is true) * - one of the following strings: "true","false","on","off","yes","no","1","0" + * + * @deprecated Just present for providing backwards compatibility. Use {@link #isBooleanValue()} instead. */ - boolean isBooleanValue() throws IOException; + @Deprecated + boolean isBooleanValueLenient() throws IOException; - boolean booleanValue() throws IOException; + // TODO #22298: Remove this method and replace all call sites with #booleanValue() + /** + * @deprecated Just present for providing backwards compatibility. Use {@link #booleanValue()} instead. + */ + @Deprecated + boolean booleanValueLenient() throws IOException; /** * Reads a plain binary value that was written via one of the following methods: diff --git a/core/src/main/java/org/elasticsearch/common/xcontent/support/AbstractXContentParser.java b/core/src/main/java/org/elasticsearch/common/xcontent/support/AbstractXContentParser.java index 162e5f7fb7d86..95fe08d96c35e 100644 --- a/core/src/main/java/org/elasticsearch/common/xcontent/support/AbstractXContentParser.java +++ b/core/src/main/java/org/elasticsearch/common/xcontent/support/AbstractXContentParser.java @@ -74,6 +74,28 @@ void ensureNumberConversion(boolean coerce, long result, Class @Override public boolean isBooleanValue() throws IOException { + switch (currentToken()) { + case VALUE_BOOLEAN: + return true; + case VALUE_STRING: + return Booleans.isBoolean(textCharacters(), textOffset(), textLength()); + default: + return false; + } + } + + @Override + public boolean booleanValue() throws IOException { + Token token = currentToken(); + if (token == Token.VALUE_STRING) { + return Booleans.parseBoolean(textCharacters(), textOffset(), textLength(), false /* irrelevant */); + } + return doBooleanValue(); + } + + @Override + @Deprecated + public boolean isBooleanValueLenient() throws IOException { switch (currentToken()) { case VALUE_BOOLEAN: return true; @@ -81,19 +103,20 @@ public boolean isBooleanValue() throws IOException { NumberType numberType = numberType(); return numberType == NumberType.LONG || numberType == NumberType.INT; case VALUE_STRING: - return Booleans.isBoolean(textCharacters(), textOffset(), textLength()); + return Booleans.isBooleanLenient(textCharacters(), textOffset(), textLength()); default: return false; } } @Override - public boolean booleanValue() throws IOException { + @Deprecated + public boolean booleanValueLenient() throws IOException { Token token = currentToken(); if (token == Token.VALUE_NUMBER) { return intValue() != 0; } else if (token == Token.VALUE_STRING) { - return Booleans.parseBoolean(textCharacters(), textOffset(), textLength(), false /* irrelevant */); + return Booleans.parseBooleanLenient(textCharacters(), textOffset(), textLength(), false /* irrelevant */); } return doBooleanValue(); } diff --git a/core/src/main/java/org/elasticsearch/common/xcontent/support/XContentMapValues.java b/core/src/main/java/org/elasticsearch/common/xcontent/support/XContentMapValues.java index 09d9dabac7540..36eacb81f8309 100644 --- a/core/src/main/java/org/elasticsearch/common/xcontent/support/XContentMapValues.java +++ b/core/src/main/java/org/elasticsearch/common/xcontent/support/XContentMapValues.java @@ -24,6 +24,7 @@ import org.apache.lucene.util.automaton.CharacterRunAutomaton; import org.apache.lucene.util.automaton.Operations; import org.elasticsearch.ElasticsearchParseException; +import org.elasticsearch.common.Booleans; import org.elasticsearch.common.Numbers; import org.elasticsearch.common.Strings; import org.elasticsearch.common.regex.Regex; @@ -412,39 +413,29 @@ public static long nodeLongValue(Object node) { return Long.parseLong(node.toString()); } - /** - * This method is very lenient, use {@link #nodeBooleanValue} instead. - */ - public static boolean lenientNodeBooleanValue(Object node, boolean defaultValue) { - if (node == null) { - return defaultValue; + public static boolean nodeBooleanValue(Object node, String name, boolean defaultValue) { + try { + return nodeBooleanValue(node, defaultValue); + } catch (IllegalArgumentException ex) { + throw new IllegalArgumentException("Could not convert [" + name + "] to boolean", ex); } - return lenientNodeBooleanValue(node); } - /** - * This method is very lenient, use {@link #nodeBooleanValue} instead. - */ - public static boolean lenientNodeBooleanValue(Object node) { - if (node instanceof Boolean) { - return (Boolean) node; - } - if (node instanceof Number) { - return ((Number) node).intValue() != 0; + public static boolean nodeBooleanValue(Object node, boolean defaultValue) { + String nodeValue = node == null ? null : node.toString(); + return Booleans.parseBoolean(nodeValue, defaultValue); + } + + public static boolean nodeBooleanValue(Object node, String name) { + try { + return nodeBooleanValue(node); + } catch (IllegalArgumentException ex) { + throw new IllegalArgumentException("Could not convert [" + name + "] to boolean", ex); } - String value = node.toString(); - return !(value.equals("false") || value.equals("0") || value.equals("off")); } public static boolean nodeBooleanValue(Object node) { - switch (node.toString()) { - case "true": - return true; - case "false": - return false; - default: - throw new IllegalArgumentException("Can't parse boolean value [" + node + "], expected [true] or [false]"); - } + return Booleans.parseBoolean(node.toString()); } public static TimeValue nodeTimeValue(Object node, TimeValue defaultValue) { diff --git a/core/src/main/java/org/elasticsearch/gateway/PrimaryShardAllocator.java b/core/src/main/java/org/elasticsearch/gateway/PrimaryShardAllocator.java index e930f327f0d33..927397725be0c 100644 --- a/core/src/main/java/org/elasticsearch/gateway/PrimaryShardAllocator.java +++ b/core/src/main/java/org/elasticsearch/gateway/PrimaryShardAllocator.java @@ -477,9 +477,11 @@ static NodeShardsResult buildVersionBasedNodeShardsResult(ShardRouting shard, bo */ private boolean recoverOnAnyNode(IndexMetaData metaData) { // don't use the setting directly, not to trigger verbose deprecation logging - return (IndexMetaData.isOnSharedFilesystem(metaData.getSettings()) || IndexMetaData.isOnSharedFilesystem(this.settings)) - && (metaData.getSettings().getAsBoolean(IndexMetaData.SETTING_SHARED_FS_ALLOW_RECOVERY_ON_ANY_NODE, false) || - this.settings.getAsBoolean(IndexMetaData.SETTING_SHARED_FS_ALLOW_RECOVERY_ON_ANY_NODE, false)); + return (metaData.isOnSharedFilesystem(metaData.getSettings()) || metaData.isOnSharedFilesystem(this.settings)) + && (metaData.getSettings().getAsBooleanLenientForPreEs6Indices( + metaData.getCreationVersion(), IndexMetaData.SETTING_SHARED_FS_ALLOW_RECOVERY_ON_ANY_NODE, false) || + this.settings.getAsBooleanLenientForPreEs6Indices + (metaData.getCreationVersion(), IndexMetaData.SETTING_SHARED_FS_ALLOW_RECOVERY_ON_ANY_NODE, false)); } protected abstract FetchResult fetchData(ShardRouting shard, RoutingAllocation allocation); diff --git a/core/src/main/java/org/elasticsearch/index/IndexModule.java b/core/src/main/java/org/elasticsearch/index/IndexModule.java index 97edd2fd468f8..25e32dc0dee94 100644 --- a/core/src/main/java/org/elasticsearch/index/IndexModule.java +++ b/core/src/main/java/org/elasticsearch/index/IndexModule.java @@ -23,6 +23,7 @@ import org.elasticsearch.client.Client; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.Strings; +import org.elasticsearch.common.TriFunction; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting.Property; import org.elasticsearch.common.settings.Settings; @@ -69,7 +70,7 @@ * IndexModule represents the central extension point for index level custom implementations like: *
    *
  • {@link SimilarityProvider} - New {@link SimilarityProvider} implementations can be registered through - * {@link #addSimilarity(String, BiFunction)}while existing Providers can be referenced through Settings under the + * {@link #addSimilarity(String, TriFunction)}while existing Providers can be referenced through Settings under the * {@link IndexModule#SIMILARITY_SETTINGS_PREFIX} prefix along with the "type" value. For example, to reference the * {@link BM25SimilarityProvider}, the configuration "index.similarity.my_similarity.type : "BM25" can be used.
  • *
  • {@link IndexStore} - Custom {@link IndexStore} instances can be registered via {@link #addIndexStore(String, Function)}
  • @@ -112,7 +113,7 @@ public final class IndexModule { final SetOnce engineFactory = new SetOnce<>(); private SetOnce indexSearcherWrapper = new SetOnce<>(); private final Set indexEventListeners = new HashSet<>(); - private final Map> similarities = new HashMap<>(); + private final Map> similarities = new HashMap<>(); private final Map> storeTypes = new HashMap<>(); private final SetOnce> forceQueryCacheProvider = new SetOnce<>(); private final List searchOperationListeners = new ArrayList<>(); @@ -256,7 +257,7 @@ public void addIndexStore(String type, Function provi * @param name Name of the SimilarityProvider * @param similarity SimilarityProvider to register */ - public void addSimilarity(String name, BiFunction similarity) { + public void addSimilarity(String name, TriFunction similarity) { ensureNotFrozen(); if (similarities.containsKey(name) || SimilarityService.BUILT_IN.containsKey(name)) { throw new IllegalArgumentException("similarity for name: [" + name + " is already registered"); diff --git a/core/src/main/java/org/elasticsearch/index/IndexService.java b/core/src/main/java/org/elasticsearch/index/IndexService.java index 50fdb5272c0d6..25e2666343fa6 100644 --- a/core/src/main/java/org/elasticsearch/index/IndexService.java +++ b/core/src/main/java/org/elasticsearch/index/IndexService.java @@ -343,8 +343,8 @@ public synchronized IndexShard createShard(ShardRouting routing) throws IOExcept logger.debug("creating shard_id {}", shardId); // if we are on a shared FS we only own the shard (ie. we can safely delete it) if we are the primary. - final boolean canDeleteShardContent = IndexMetaData.isOnSharedFilesystem(indexSettings) == false || - (primary && IndexMetaData.isOnSharedFilesystem(indexSettings)); + final boolean canDeleteShardContent = this.indexSettings.isOnSharedFilesystem() == false || + (primary && this.indexSettings.isOnSharedFilesystem()); final Engine.Warmer engineWarmer = (searcher) -> { IndexShard shard = getShardOrNull(shardId.getId()); if (shard != null) { @@ -353,7 +353,7 @@ public synchronized IndexShard createShard(ShardRouting routing) throws IOExcept }; store = new Store(shardId, this.indexSettings, indexStore.newDirectoryService(path), lock, new StoreCloseListener(shardId, canDeleteShardContent, () -> eventListener.onStoreClosed(shardId))); - if (useShadowEngine(primary, indexSettings)) { + if (useShadowEngine(primary, this.indexSettings)) { indexShard = new ShadowIndexShard(routing, this.indexSettings, path, store, indexCache, mapperService, similarityService, indexFieldData, engineFactory, eventListener, searcherWrapper, threadPool, bigArrays, engineWarmer, searchOperationListeners); @@ -381,8 +381,8 @@ public synchronized IndexShard createShard(ShardRouting routing) throws IOExcept } } - static boolean useShadowEngine(boolean primary, Settings indexSettings) { - return primary == false && IndexMetaData.isIndexUsingShadowReplicas(indexSettings); + static boolean useShadowEngine(boolean primary, IndexSettings indexSettings) { + return primary == false && indexSettings.isShadowReplicaIndex(); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/IndexSettings.java b/core/src/main/java/org/elasticsearch/index/IndexSettings.java index 25751cfc77190..260cb593a82de 100644 --- a/core/src/main/java/org/elasticsearch/index/IndexSettings.java +++ b/core/src/main/java/org/elasticsearch/index/IndexSettings.java @@ -229,7 +229,7 @@ public IndexSettings(final IndexMetaData indexMetaData, final Settings nodeSetti nodeName = Node.NODE_NAME_SETTING.get(settings); this.indexMetaData = indexMetaData; numberOfShards = settings.getAsInt(IndexMetaData.SETTING_NUMBER_OF_SHARDS, null); - isShadowReplicaIndex = IndexMetaData.isIndexUsingShadowReplicas(settings); + isShadowReplicaIndex = indexMetaData.isIndexUsingShadowReplicas(settings); this.defaultField = DEFAULT_FIELD_SETTING.get(settings); this.queryStringLenient = QUERY_STRING_LENIENT_SETTING.get(settings); @@ -327,16 +327,7 @@ public String customDataPath() { * filesystem. */ public boolean isOnSharedFilesystem() { - return IndexMetaData.isOnSharedFilesystem(getSettings()); - } - - /** - * Returns true iff the given settings indicate that the index associated - * with these settings uses shadow replicas. Otherwise false. The default - * setting for this is false. - */ - public boolean isIndexUsingShadowReplicas() { - return IndexMetaData.isOnSharedFilesystem(getSettings()); + return indexMetaData.isOnSharedFilesystem(getSettings()); } /** diff --git a/core/src/main/java/org/elasticsearch/index/MergePolicyConfig.java b/core/src/main/java/org/elasticsearch/index/MergePolicyConfig.java index 0f7305789ecb5..c2625f7615bff 100644 --- a/core/src/main/java/org/elasticsearch/index/MergePolicyConfig.java +++ b/core/src/main/java/org/elasticsearch/index/MergePolicyConfig.java @@ -164,7 +164,8 @@ public final class MergePolicyConfig { ByteSizeValue maxMergedSegment = indexSettings.getValue(INDEX_MERGE_POLICY_MAX_MERGED_SEGMENT_SETTING); double segmentsPerTier = indexSettings.getValue(INDEX_MERGE_POLICY_SEGMENTS_PER_TIER_SETTING); double reclaimDeletesWeight = indexSettings.getValue(INDEX_MERGE_POLICY_RECLAIM_DELETES_WEIGHT_SETTING); - this.mergesEnabled = indexSettings.getSettings().getAsBoolean(INDEX_MERGE_ENABLED, true); + this.mergesEnabled = indexSettings.getSettings() + .getAsBooleanLenientForPreEs6Indices(indexSettings.getIndexVersionCreated(), INDEX_MERGE_ENABLED, true); if (mergesEnabled == false) { logger.warn("[{}] is set to false, this should only be used in tests and can cause serious problems in production environments", INDEX_MERGE_ENABLED); } diff --git a/core/src/main/java/org/elasticsearch/index/analysis/ASCIIFoldingTokenFilterFactory.java b/core/src/main/java/org/elasticsearch/index/analysis/ASCIIFoldingTokenFilterFactory.java index 4318ef273dca9..1486382521aa8 100644 --- a/core/src/main/java/org/elasticsearch/index/analysis/ASCIIFoldingTokenFilterFactory.java +++ b/core/src/main/java/org/elasticsearch/index/analysis/ASCIIFoldingTokenFilterFactory.java @@ -37,7 +37,8 @@ public class ASCIIFoldingTokenFilterFactory extends AbstractTokenFilterFactory i public ASCIIFoldingTokenFilterFactory(IndexSettings indexSettings, Environment environment, String name, Settings settings) { super(indexSettings, name, settings); - preserveOriginal = settings.getAsBoolean(PRESERVE_ORIGINAL.getPreferredName(), DEFAULT_PRESERVE_ORIGINAL); + preserveOriginal = settings.getAsBooleanLenientForPreEs6Indices( + indexSettings.getIndexVersionCreated(), PRESERVE_ORIGINAL.getPreferredName(), DEFAULT_PRESERVE_ORIGINAL); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/analysis/Analysis.java b/core/src/main/java/org/elasticsearch/index/analysis/Analysis.java index aded2bb4ee9fc..170e35905d538 100644 --- a/core/src/main/java/org/elasticsearch/index/analysis/Analysis.java +++ b/core/src/main/java/org/elasticsearch/index/analysis/Analysis.java @@ -178,12 +178,15 @@ public static CharArraySet parseCommonWords(Environment env, Settings settings, return parseWords(env, settings, "common_words", defaultCommonWords, NAMED_STOP_WORDS, ignoreCase); } - public static CharArraySet parseArticles(Environment env, Settings settings) { - return parseWords(env, settings, "articles", null, null, settings.getAsBoolean("articles_case", false)); + public static CharArraySet parseArticles(Environment env, org.elasticsearch.Version indexCreatedVersion, Settings settings) { + boolean articlesCase = settings.getAsBooleanLenientForPreEs6Indices(indexCreatedVersion, "articles_case", false); + return parseWords(env, settings, "articles", null, null, articlesCase); } - public static CharArraySet parseStopWords(Environment env, Settings settings, CharArraySet defaultStopWords) { - return parseStopWords(env, settings, defaultStopWords, settings.getAsBoolean("stopwords_case", false)); + public static CharArraySet parseStopWords(Environment env, org.elasticsearch.Version indexCreatedVersion, Settings settings, + CharArraySet defaultStopWords) { + boolean stopwordsCase = settings.getAsBooleanLenientForPreEs6Indices(indexCreatedVersion, "stopwords_case", false); + return parseStopWords(env, settings, defaultStopWords, stopwordsCase); } public static CharArraySet parseStopWords(Environment env, Settings settings, CharArraySet defaultStopWords, boolean ignoreCase) { @@ -205,12 +208,14 @@ private static CharArraySet resolveNamedWords(Collection words, Map wordList = getWordList(env, settings, settingsPrefix); if (wordList == null) { return null; } - return new CharArraySet(wordList, settings.getAsBoolean(settingsPrefix + "_case", false)); + boolean ignoreCase = settings.getAsBooleanLenientForPreEs6Indices(indexCreatedVersion, settingsPrefix + "_case", false); + return new CharArraySet(wordList, ignoreCase); } /** diff --git a/core/src/main/java/org/elasticsearch/index/analysis/ArabicAnalyzerProvider.java b/core/src/main/java/org/elasticsearch/index/analysis/ArabicAnalyzerProvider.java index fffa594b9e1c0..10d8f22bde7e8 100644 --- a/core/src/main/java/org/elasticsearch/index/analysis/ArabicAnalyzerProvider.java +++ b/core/src/main/java/org/elasticsearch/index/analysis/ArabicAnalyzerProvider.java @@ -31,8 +31,10 @@ public class ArabicAnalyzerProvider extends AbstractIndexAnalyzerProvider scripts = new HashSet<>(Arrays.asList("han", "hiragana", "katakana", "hangul")); if (asArray != null) { diff --git a/core/src/main/java/org/elasticsearch/index/analysis/CatalanAnalyzerProvider.java b/core/src/main/java/org/elasticsearch/index/analysis/CatalanAnalyzerProvider.java index 25328421f9948..ff0f9e323097d 100644 --- a/core/src/main/java/org/elasticsearch/index/analysis/CatalanAnalyzerProvider.java +++ b/core/src/main/java/org/elasticsearch/index/analysis/CatalanAnalyzerProvider.java @@ -31,8 +31,10 @@ public class CatalanAnalyzerProvider extends AbstractIndexAnalyzerProvider rules = Analysis.getWordSet(env, settings, "keywords"); + boolean ignoreCase = settings.getAsBooleanLenientForPreEs6Indices(indexSettings.getIndexVersionCreated(), "ignore_case", false); + Set rules = Analysis.getWordSet(env, indexSettings.getIndexVersionCreated(), settings, "keywords"); if (rules == null) { throw new IllegalArgumentException("keyword filter requires either `keywords` or `keywords_path` to be configured"); } diff --git a/core/src/main/java/org/elasticsearch/index/analysis/LatvianAnalyzerProvider.java b/core/src/main/java/org/elasticsearch/index/analysis/LatvianAnalyzerProvider.java index a288747ab4b2b..a7731f352b997 100644 --- a/core/src/main/java/org/elasticsearch/index/analysis/LatvianAnalyzerProvider.java +++ b/core/src/main/java/org/elasticsearch/index/analysis/LatvianAnalyzerProvider.java @@ -31,8 +31,10 @@ public class LatvianAnalyzerProvider extends AbstractIndexAnalyzerProvider tokenizerFactoryFactory = diff --git a/core/src/main/java/org/elasticsearch/index/analysis/ThaiAnalyzerProvider.java b/core/src/main/java/org/elasticsearch/index/analysis/ThaiAnalyzerProvider.java index f1a69c62b1e09..119eb81d7482d 100644 --- a/core/src/main/java/org/elasticsearch/index/analysis/ThaiAnalyzerProvider.java +++ b/core/src/main/java/org/elasticsearch/index/analysis/ThaiAnalyzerProvider.java @@ -30,7 +30,8 @@ public class ThaiAnalyzerProvider extends AbstractIndexAnalyzerProvider "O", "Neil" flags |= getFlag(STEM_ENGLISH_POSSESSIVE, settings, "stem_english_possessive", true); // If not null is the set of tokens to protect from being delimited - Set protectedWords = Analysis.getWordSet(env, settings, "protected_words"); + Set protectedWords = Analysis.getWordSet(env, indexSettings.getIndexVersionCreated(), settings, "protected_words"); this.protoWords = protectedWords == null ? null : CharArraySet.copy(protectedWords); this.flags = flags; } @@ -101,7 +101,7 @@ public TokenStream create(TokenStream tokenStream) { } public int getFlag(int flag, Settings settings, String key, boolean defaultValue) { - if (settings.getAsBoolean(key, defaultValue)) { + if (settings.getAsBooleanLenientForPreEs6Indices(indexSettings.getIndexVersionCreated(), key, defaultValue)) { return flag; } return 0; diff --git a/core/src/main/java/org/elasticsearch/index/analysis/compound/AbstractCompoundWordTokenFilterFactory.java b/core/src/main/java/org/elasticsearch/index/analysis/compound/AbstractCompoundWordTokenFilterFactory.java index e7147334a7eaa..9be3f38b02fbc 100644 --- a/core/src/main/java/org/elasticsearch/index/analysis/compound/AbstractCompoundWordTokenFilterFactory.java +++ b/core/src/main/java/org/elasticsearch/index/analysis/compound/AbstractCompoundWordTokenFilterFactory.java @@ -44,8 +44,9 @@ public AbstractCompoundWordTokenFilterFactory(IndexSettings indexSettings, Envir minWordSize = settings.getAsInt("min_word_size", CompoundWordTokenFilterBase.DEFAULT_MIN_WORD_SIZE); minSubwordSize = settings.getAsInt("min_subword_size", CompoundWordTokenFilterBase.DEFAULT_MIN_SUBWORD_SIZE); maxSubwordSize = settings.getAsInt("max_subword_size", CompoundWordTokenFilterBase.DEFAULT_MAX_SUBWORD_SIZE); - onlyLongestMatch = settings.getAsBoolean("only_longest_match", false); - wordList = Analysis.getWordSet(env, settings, "word_list"); + onlyLongestMatch = settings + .getAsBooleanLenientForPreEs6Indices(indexSettings.getIndexVersionCreated(), "only_longest_match", false); + wordList = Analysis.getWordSet(env, indexSettings.getIndexVersionCreated(), settings, "word_list"); if (wordList == null) { throw new IllegalArgumentException("word_list must be provided for [" + name + "], either as a path to a file, or directly"); } diff --git a/core/src/main/java/org/elasticsearch/index/mapper/AllFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/AllFieldMapper.java index d77a99cf3655d..58380ce689034 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/AllFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/AllFieldMapper.java @@ -40,7 +40,6 @@ import java.util.List; import java.util.Map; -import static org.elasticsearch.common.xcontent.support.XContentMapValues.lenientNodeBooleanValue; import static org.elasticsearch.common.xcontent.support.XContentMapValues.nodeMapValue; import static org.elasticsearch.index.mapper.TypeParsers.parseTextField; @@ -118,7 +117,7 @@ public MetadataFieldMapper.Builder parse(String name, Map n // the AllFieldMapper ctor in the builder since it is not valid. Here we validate // the doc values settings (old and new) are rejected Object docValues = node.get("doc_values"); - if (docValues != null && lenientNodeBooleanValue(docValues)) { + if (docValues != null && TypeParsers.nodeBooleanValueLenient(name, "doc_values", docValues)) { throw new MapperParsingException("Field [" + name + "] is always tokenized and cannot have doc values"); } @@ -139,8 +138,8 @@ public MetadataFieldMapper.Builder parse(String name, Map n String fieldName = entry.getKey(); Object fieldNode = entry.getValue(); if (fieldName.equals("enabled")) { - builder.enabled(lenientNodeBooleanValue(fieldNode) ? EnabledAttributeMapper.ENABLED : - EnabledAttributeMapper.DISABLED); + boolean enabled = TypeParsers.nodeBooleanValueLenient(name, "enabled", fieldNode); + builder.enabled(enabled ? EnabledAttributeMapper.ENABLED : EnabledAttributeMapper.DISABLED); iterator.remove(); } } diff --git a/core/src/main/java/org/elasticsearch/index/mapper/BaseGeoPointFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/BaseGeoPointFieldMapper.java index c075d784c942e..610588e654052 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/BaseGeoPointFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/BaseGeoPointFieldMapper.java @@ -123,7 +123,7 @@ public abstract static class TypeParser implements Mapper.TypeParser { Object propNode = entry.getValue(); if (propName.equals(Names.IGNORE_MALFORMED)) { - builder.ignoreMalformed(XContentMapValues.lenientNodeBooleanValue(propNode)); + builder.ignoreMalformed(TypeParsers.nodeBooleanValue(name, Names.IGNORE_MALFORMED, propNode, parserContext)); iterator.remove(); } } diff --git a/core/src/main/java/org/elasticsearch/index/mapper/BooleanFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/BooleanFieldMapper.java index fc9520beeab39..7bd8c79ee670a 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/BooleanFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/BooleanFieldMapper.java @@ -26,8 +26,10 @@ import org.apache.lucene.search.Query; import org.apache.lucene.search.TermRangeQuery; import org.apache.lucene.util.BytesRef; -import org.elasticsearch.common.Booleans; +import org.elasticsearch.Version; import org.elasticsearch.common.Nullable; +import org.elasticsearch.common.logging.DeprecationLogger; +import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.lucene.Lucene; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; @@ -44,13 +46,13 @@ import java.util.List; import java.util.Map; -import static org.elasticsearch.common.xcontent.support.XContentMapValues.lenientNodeBooleanValue; import static org.elasticsearch.index.mapper.TypeParsers.parseField; /** * A field mapper for boolean fields. */ public class BooleanFieldMapper extends FieldMapper { + private static final DeprecationLogger deprecationLogger = new DeprecationLogger(Loggers.getLogger(BooleanFieldMapper.class)); public static final String CONTENT_TYPE = "boolean"; @@ -108,7 +110,7 @@ public Mapper.Builder parse(String name, Map node, ParserContext if (propNode == null) { throw new MapperParsingException("Property [null_value] cannot be null."); } - builder.nullValue(lenientNodeBooleanValue(propNode)); + builder.nullValue(TypeParsers.nodeBooleanValue(name, "null_value", propNode, parserContext)); iterator.remove(); } } @@ -231,7 +233,15 @@ protected void parseCreateField(ParseContext context, List field value = fieldType().nullValue(); } } else { - value = context.parser().booleanValue(); + if (indexCreatedVersion.onOrAfter(Version.V_6_0_0_alpha1_UNRELEASED)) { + value = context.parser().booleanValue(); + } else { + value = context.parser().booleanValueLenient(); + if (context.parser().isBooleanValueLenient() != context.parser().isBooleanValue()) { + String rawValue = context.parser().text(); + deprecationLogger.deprecated("Expected a boolean for property [{}] but got [{}]", fieldType().name(), rawValue); + } + } } } diff --git a/core/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java index d2833d4bfb36b..52e5de0a176d9 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java @@ -151,7 +151,7 @@ public Mapper.Builder parse(String name, Map node, ParserCo builder.nullValue(propNode.toString()); iterator.remove(); } else if (propName.equals("ignore_malformed")) { - builder.ignoreMalformed(TypeParsers.nodeBooleanValue("ignore_malformed", propNode, parserContext)); + builder.ignoreMalformed(TypeParsers.nodeBooleanValue(name, "ignore_malformed", propNode, parserContext)); iterator.remove(); } else if (propName.equals("locale")) { builder.locale(LocaleUtils.parse(propNode.toString())); diff --git a/core/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java index b2152e41b75ab..0ed093b3a884f 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java @@ -237,7 +237,7 @@ protected void setupFieldType(BuilderContext context) { } } - private final Version indexCreatedVersion; + protected final Version indexCreatedVersion; protected MappedFieldType fieldType; protected final MappedFieldType defaultFieldType; protected MultiFields multiFields; diff --git a/core/src/main/java/org/elasticsearch/index/mapper/FieldNamesFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/FieldNamesFieldMapper.java index 764586562d29c..863ce3c514905 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/FieldNamesFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/FieldNamesFieldMapper.java @@ -36,8 +36,6 @@ import java.util.Map; import java.util.Objects; -import static org.elasticsearch.common.xcontent.support.XContentMapValues.lenientNodeBooleanValue; - /** * A mapper that indexes the field names of a document under _field_names. This mapper is typically useful in order * to have fast exists and missing queries/filters. @@ -107,7 +105,7 @@ public MetadataFieldMapper.Builder parse(String name, Map n String fieldName = entry.getKey(); Object fieldNode = entry.getValue(); if (fieldName.equals("enabled")) { - builder.enabled(lenientNodeBooleanValue(fieldNode)); + builder.enabled(TypeParsers.nodeBooleanValue(name, "enabled", fieldNode, parserContext)); iterator.remove(); } } diff --git a/core/src/main/java/org/elasticsearch/index/mapper/GeoShapeFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/GeoShapeFieldMapper.java index f1a73308692f5..c46fe227d6fdc 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/GeoShapeFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/GeoShapeFieldMapper.java @@ -41,7 +41,6 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.DistanceUnit; import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.common.xcontent.support.XContentMapValues; import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.index.query.QueryShardException; import org.locationtech.spatial4j.shape.Point; @@ -54,9 +53,6 @@ import java.util.Map; import java.util.Objects; -import static org.elasticsearch.common.xcontent.support.XContentMapValues.lenientNodeBooleanValue; - - /** * FieldMapper for indexing {@link org.locationtech.spatial4j.shape.Shape}s. *

    @@ -185,11 +181,12 @@ public Mapper.Builder parse(String name, Map node, ParserContext builder.fieldType().setStrategyName(fieldNode.toString()); iterator.remove(); } else if (Names.COERCE.equals(fieldName)) { - builder.coerce(lenientNodeBooleanValue(fieldNode)); + builder.coerce(TypeParsers.nodeBooleanValue(fieldName, Names.COERCE, fieldNode, parserContext)); iterator.remove(); } else if (Names.STRATEGY_POINTS_ONLY.equals(fieldName) && builder.fieldType().strategyName.equals(SpatialStrategy.TERM.getStrategyName()) == false) { - builder.fieldType().setPointsOnly(XContentMapValues.lenientNodeBooleanValue(fieldNode)); + boolean pointsOnly = TypeParsers.nodeBooleanValue(fieldName, Names.STRATEGY_POINTS_ONLY, fieldNode, parserContext); + builder.fieldType().setPointsOnly(pointsOnly); iterator.remove(); } } diff --git a/core/src/main/java/org/elasticsearch/index/mapper/IpFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/IpFieldMapper.java index 0b3b4fd8a4086..9f4412c34ccca 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/IpFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/IpFieldMapper.java @@ -114,7 +114,7 @@ public Mapper.Builder parse(String name, Map node, ParserCo builder.nullValue(InetAddresses.forString(propNode.toString())); iterator.remove(); } else if (propName.equals("ignore_malformed")) { - builder.ignoreMalformed(TypeParsers.nodeBooleanValue("ignore_malformed", propNode, parserContext)); + builder.ignoreMalformed(TypeParsers.nodeBooleanValue(name, "ignore_malformed", propNode, parserContext)); iterator.remove(); } else if (TypeParsers.parseMultiField(builder, name, parserContext, propName, propNode)) { iterator.remove(); diff --git a/core/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java index f4f6266262fe2..8824b84fc9b10 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java @@ -136,10 +136,10 @@ public Mapper.Builder parse(String name, Map node, ParserCo builder.ignoreAbove(XContentMapValues.nodeIntegerValue(propNode, -1)); iterator.remove(); } else if (propName.equals("norms")) { - builder.omitNorms(XContentMapValues.nodeBooleanValue(propNode) == false); + builder.omitNorms(XContentMapValues.nodeBooleanValue(propNode, "norms") == false); iterator.remove(); } else if (propName.equals("eager_global_ordinals")) { - builder.eagerGlobalOrdinals(XContentMapValues.nodeBooleanValue(propNode)); + builder.eagerGlobalOrdinals(XContentMapValues.nodeBooleanValue(propNode, "eager_global_ordinals")); iterator.remove(); } else if (propName.equals("normalizer")) { if (propNode != null) { diff --git a/core/src/main/java/org/elasticsearch/index/mapper/NumberFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/NumberFieldMapper.java index c922cd8b54c7f..e9043b3c754be 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/NumberFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/NumberFieldMapper.java @@ -150,10 +150,10 @@ public Mapper.Builder parse(String name, Map node, builder.nullValue(type.parse(propNode, false)); iterator.remove(); } else if (propName.equals("ignore_malformed")) { - builder.ignoreMalformed(TypeParsers.nodeBooleanValue("ignore_malformed", propNode, parserContext)); + builder.ignoreMalformed(TypeParsers.nodeBooleanValue(name,"ignore_malformed", propNode, parserContext)); iterator.remove(); } else if (propName.equals("coerce")) { - builder.coerce(TypeParsers.nodeBooleanValue("coerce", propNode, parserContext)); + builder.coerce(TypeParsers.nodeBooleanValue(name, "coerce", propNode, parserContext)); iterator.remove(); } } diff --git a/core/src/main/java/org/elasticsearch/index/mapper/ObjectMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/ObjectMapper.java index 60c264e570617..9cd6ef3b65f46 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/ObjectMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/ObjectMapper.java @@ -42,8 +42,6 @@ import java.util.Locale; import java.util.Map; -import static org.elasticsearch.common.xcontent.support.XContentMapValues.lenientNodeBooleanValue; - public class ObjectMapper extends Mapper implements Cloneable { public static final String CONTENT_TYPE = "object"; @@ -167,7 +165,7 @@ public static class TypeParser implements Mapper.TypeParser { @Override public Mapper.Builder parse(String name, Map node, ParserContext parserContext) throws MapperParsingException { ObjectMapper.Builder builder = new Builder(name); - parseNested(name, node, builder); + parseNested(name, node, builder, parserContext); for (Iterator> iterator = node.entrySet().iterator(); iterator.hasNext();) { Map.Entry entry = iterator.next(); String fieldName = entry.getKey(); @@ -185,11 +183,12 @@ protected static boolean parseObjectOrDocumentTypeProperties(String fieldName, O if (value.equalsIgnoreCase("strict")) { builder.dynamic(Dynamic.STRICT); } else { - builder.dynamic(lenientNodeBooleanValue(fieldNode) ? Dynamic.TRUE : Dynamic.FALSE); + boolean dynamic = TypeParsers.nodeBooleanValue(fieldName, "dynamic", fieldNode, parserContext); + builder.dynamic(dynamic ? Dynamic.TRUE : Dynamic.FALSE); } return true; } else if (fieldName.equals("enabled")) { - builder.enabled(lenientNodeBooleanValue(fieldNode)); + builder.enabled(TypeParsers.nodeBooleanValue(fieldName, "enabled", fieldNode, parserContext)); return true; } else if (fieldName.equals("properties")) { if (fieldNode instanceof Collection && ((Collection) fieldNode).isEmpty()) { @@ -201,13 +200,14 @@ protected static boolean parseObjectOrDocumentTypeProperties(String fieldName, O } return true; } else if (fieldName.equals("include_in_all")) { - builder.includeInAll(lenientNodeBooleanValue(fieldNode)); + builder.includeInAll(TypeParsers.nodeBooleanValue(fieldName, "include_in_all", fieldNode, parserContext)); return true; } return false; } - protected static void parseNested(String name, Map node, ObjectMapper.Builder builder) { + protected static void parseNested(String name, Map node, ObjectMapper.Builder builder, + ParserContext parserContext) { boolean nested = false; boolean nestedIncludeInParent = false; boolean nestedIncludeInRoot = false; @@ -224,12 +224,12 @@ protected static void parseNested(String name, Map node, ObjectM } fieldNode = node.get("include_in_parent"); if (fieldNode != null) { - nestedIncludeInParent = lenientNodeBooleanValue(fieldNode); + nestedIncludeInParent = TypeParsers.nodeBooleanValue(name, "include_in_parent", fieldNode, parserContext); node.remove("include_in_parent"); } fieldNode = node.get("include_in_root"); if (fieldNode != null) { - nestedIncludeInRoot = lenientNodeBooleanValue(fieldNode); + nestedIncludeInRoot = TypeParsers.nodeBooleanValue(name, "include_in_root", fieldNode, parserContext); node.remove("include_in_root"); } if (nested) { diff --git a/core/src/main/java/org/elasticsearch/index/mapper/ParentFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/ParentFieldMapper.java index 6b4133fd33aab..aee6979b5c809 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/ParentFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/ParentFieldMapper.java @@ -122,7 +122,7 @@ public MetadataFieldMapper.Builder parse(String name, Map node, } iterator.remove(); } else if (fieldName.equals("eager_global_ordinals")) { - builder.eagerGlobalOrdinals(XContentMapValues.nodeBooleanValue(fieldNode)); + builder.eagerGlobalOrdinals(XContentMapValues.nodeBooleanValue(fieldNode, "eager_global_ordinals")); iterator.remove(); } } diff --git a/core/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java index b0a809c12dfce..d3c9afd2f9629 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/RangeFieldMapper.java @@ -166,7 +166,7 @@ public Mapper.Builder parse(String name, Map node, throw new MapperParsingException("Property [null_value] is not supported for [" + this.type.name + "] field types."); } else if (propName.equals("coerce")) { - builder.coerce(TypeParsers.nodeBooleanValue("coerce", propNode, parserContext)); + builder.coerce(TypeParsers.nodeBooleanValue(name, "coerce", propNode, parserContext)); iterator.remove(); } else if (propName.equals("locale")) { builder.locale(LocaleUtils.parse(propNode.toString())); diff --git a/core/src/main/java/org/elasticsearch/index/mapper/RootObjectMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/RootObjectMapper.java index 0ae7ce3358113..c51f29072c188 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/RootObjectMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/RootObjectMapper.java @@ -150,10 +150,10 @@ protected boolean processField(RootObjectMapper.Builder builder, String fieldNam builder.dynamicTemplates(templates); return true; } else if (fieldName.equals("date_detection")) { - ((Builder) builder).dateDetection = new Explicit<>(nodeBooleanValue(fieldNode), true); + builder.dateDetection = new Explicit<>(nodeBooleanValue(fieldNode, "date_detection"), true); return true; } else if (fieldName.equals("numeric_detection")) { - ((Builder) builder).numericDetection = new Explicit<>(nodeBooleanValue(fieldNode), true); + builder.numericDetection = new Explicit<>(nodeBooleanValue(fieldNode, "numeric_detection"), true); return true; } return false; diff --git a/core/src/main/java/org/elasticsearch/index/mapper/RoutingFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/RoutingFieldMapper.java index 8640bfaa35bdc..d1161b4740f22 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/RoutingFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/RoutingFieldMapper.java @@ -32,8 +32,6 @@ import java.util.List; import java.util.Map; -import static org.elasticsearch.common.xcontent.support.XContentMapValues.lenientNodeBooleanValue; - public class RoutingFieldMapper extends MetadataFieldMapper { public static final String NAME = "_routing"; @@ -86,7 +84,7 @@ public MetadataFieldMapper.Builder parse(String name, Map n String fieldName = entry.getKey(); Object fieldNode = entry.getValue(); if (fieldName.equals("required")) { - builder.required(lenientNodeBooleanValue(fieldNode)); + builder.required(TypeParsers.nodeBooleanValue(name, "required", fieldNode, parserContext)); iterator.remove(); } } diff --git a/core/src/main/java/org/elasticsearch/index/mapper/ScaledFloatFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/ScaledFloatFieldMapper.java index 6cd69c0fc6b7f..cf2564f0382f4 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/ScaledFloatFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/ScaledFloatFieldMapper.java @@ -147,10 +147,10 @@ public Mapper.Builder parse(String name, Map node, builder.nullValue(NumberFieldMapper.NumberType.DOUBLE.parse(propNode, false)); iterator.remove(); } else if (propName.equals("ignore_malformed")) { - builder.ignoreMalformed(TypeParsers.nodeBooleanValue("ignore_malformed", propNode, parserContext)); + builder.ignoreMalformed(TypeParsers.nodeBooleanValue(name, "ignore_malformed", propNode, parserContext)); iterator.remove(); } else if (propName.equals("coerce")) { - builder.coerce(TypeParsers.nodeBooleanValue("coerce", propNode, parserContext)); + builder.coerce(TypeParsers.nodeBooleanValue(name, "coerce", propNode, parserContext)); iterator.remove(); } else if (propName.equals("scaling_factor")) { builder.scalingFactor(NumberFieldMapper.NumberType.DOUBLE.parse(propNode, false).doubleValue()); diff --git a/core/src/main/java/org/elasticsearch/index/mapper/SourceFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/SourceFieldMapper.java index efddec9066937..e06ec80a472dd 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/SourceFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/SourceFieldMapper.java @@ -47,8 +47,6 @@ import java.util.Map; import java.util.function.Function; -import static org.elasticsearch.common.xcontent.support.XContentMapValues.lenientNodeBooleanValue; - public class SourceFieldMapper extends MetadataFieldMapper { public static final String NAME = "_source"; @@ -116,7 +114,7 @@ public MetadataFieldMapper.Builder parse(String name, Map n String fieldName = entry.getKey(); Object fieldNode = entry.getValue(); if (fieldName.equals("enabled")) { - builder.enabled(lenientNodeBooleanValue(fieldNode)); + builder.enabled(TypeParsers.nodeBooleanValue(name, "enabled", fieldNode, parserContext)); iterator.remove(); } else if ("format".equals(fieldName) && parserContext.indexVersionCreated().before(Version.V_5_0_0_alpha1)) { // ignore on old indices, reject on and after 5.0 diff --git a/core/src/main/java/org/elasticsearch/index/mapper/TextFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/TextFieldMapper.java index bb8c4d77a6311..b41695eb8bd49 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/TextFieldMapper.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/TextFieldMapper.java @@ -144,10 +144,10 @@ public Mapper.Builder parse(String fieldName, Map node, ParserCo builder.positionIncrementGap(newPositionIncrementGap); iterator.remove(); } else if (propName.equals("fielddata")) { - builder.fielddata(XContentMapValues.nodeBooleanValue(propNode)); + builder.fielddata(XContentMapValues.nodeBooleanValue(propNode, "fielddata")); iterator.remove(); } else if (propName.equals("eager_global_ordinals")) { - builder.eagerGlobalOrdinals(XContentMapValues.nodeBooleanValue(propNode)); + builder.eagerGlobalOrdinals(XContentMapValues.nodeBooleanValue(propNode, "eager_global_ordinals")); iterator.remove(); } else if (propName.equals("fielddata_frequency_filter")) { Map frequencyFilter = (Map) propNode; diff --git a/core/src/main/java/org/elasticsearch/index/mapper/TypeParsers.java b/core/src/main/java/org/elasticsearch/index/mapper/TypeParsers.java index 6e88e8b46cd04..3faa135402d7d 100644 --- a/core/src/main/java/org/elasticsearch/index/mapper/TypeParsers.java +++ b/core/src/main/java/org/elasticsearch/index/mapper/TypeParsers.java @@ -22,6 +22,7 @@ import org.apache.lucene.index.IndexOptions; import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.Version; +import org.elasticsearch.common.Booleans; import org.elasticsearch.common.joda.FormatDateTimeFormatter; import org.elasticsearch.common.joda.Joda; import org.elasticsearch.common.logging.DeprecationLogger; @@ -30,17 +31,13 @@ import org.elasticsearch.index.analysis.NamedAnalyzer; import org.elasticsearch.index.similarity.SimilarityProvider; -import java.util.Arrays; import java.util.Collections; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.Set; import static org.elasticsearch.common.xcontent.support.XContentMapValues.isArray; -import static org.elasticsearch.common.xcontent.support.XContentMapValues.lenientNodeBooleanValue; import static org.elasticsearch.common.xcontent.support.XContentMapValues.nodeFloatValue; import static org.elasticsearch.common.xcontent.support.XContentMapValues.nodeMapValue; import static org.elasticsearch.common.xcontent.support.XContentMapValues.nodeStringValue; @@ -54,17 +51,37 @@ public class TypeParsers { public static final String INDEX_OPTIONS_OFFSETS = "offsets"; private static final DeprecationLogger DEPRECATION_LOGGER = new DeprecationLogger(Loggers.getLogger(TypeParsers.class)); - private static final Set BOOLEAN_STRINGS = new HashSet<>(Arrays.asList("true", "false")); - public static boolean nodeBooleanValue(String name, Object node, Mapper.TypeParser.ParserContext parserContext) { - // TODO: remove this leniency in 6.0 - if (BOOLEAN_STRINGS.contains(node.toString()) == false) { - DEPRECATION_LOGGER.deprecated("Expected a boolean for property [{}] but got [{}]", name, node); + //TODO 22298: Remove this method and have all call-sites use XContentMapValues.nodeBooleanValue(node) directly. + public static boolean nodeBooleanValue(String fieldName, String propertyName, Object node, + Mapper.TypeParser.ParserContext parserContext) { + if (parserContext.indexVersionCreated().onOrAfter(Version.V_6_0_0_alpha1_UNRELEASED)) { + return XContentMapValues.nodeBooleanValue(node, fieldName + "." + propertyName); + } else { + return nodeBooleanValueLenient(fieldName, propertyName, node); + } + } + + //TODO 22298: Remove this method and have all call-sites use XContentMapValues.nodeBooleanValue(node) directly. + public static boolean nodeBooleanValueLenient(String fieldName, String propertyName, Object node) { + if (Booleans.isBoolean(node.toString()) == false) { + DEPRECATION_LOGGER.deprecated("Expected a boolean for property [{}] for field [{}] but got [{}]", + propertyName, fieldName, node); + } + if (node instanceof Boolean) { + return (Boolean) node; } - return XContentMapValues.lenientNodeBooleanValue(node); + if (node instanceof Number) { + return ((Number) node).intValue() != 0; + } + @SuppressWarnings("deprecated") + boolean value = Booleans.parseBooleanLenient(node.toString(), false); + return value; } - private static void parseAnalyzersAndTermVectors(FieldMapper.Builder builder, String name, Map fieldNode, Mapper.TypeParser.ParserContext parserContext) { + + private static void parseAnalyzersAndTermVectors(FieldMapper.Builder builder, String name, Map fieldNode, + Mapper.TypeParser.ParserContext parserContext) { NamedAnalyzer indexAnalyzer = null; NamedAnalyzer searchAnalyzer = null; NamedAnalyzer searchQuoteAnalyzer = null; @@ -77,16 +94,17 @@ private static void parseAnalyzersAndTermVectors(FieldMapper.Builder builder, St parseTermVector(name, propNode.toString(), builder); iterator.remove(); } else if (propName.equals("store_term_vectors")) { - builder.storeTermVectors(nodeBooleanValue("store_term_vectors", propNode, parserContext)); + builder.storeTermVectors(nodeBooleanValue(name, "store_term_vectors", propNode, parserContext)); iterator.remove(); } else if (propName.equals("store_term_vector_offsets")) { - builder.storeTermVectorOffsets(nodeBooleanValue("store_term_vector_offsets", propNode, parserContext)); + builder.storeTermVectorOffsets(nodeBooleanValue(name, "store_term_vector_offsets", propNode, parserContext)); iterator.remove(); } else if (propName.equals("store_term_vector_positions")) { - builder.storeTermVectorPositions(nodeBooleanValue("store_term_vector_positions", propNode, parserContext)); + builder.storeTermVectorPositions( + nodeBooleanValue(name, "store_term_vector_positions", propNode, parserContext)); iterator.remove(); } else if (propName.equals("store_term_vector_payloads")) { - builder.storeTermVectorPayloads(nodeBooleanValue("store_term_vector_payloads", propNode, parserContext)); + builder.storeTermVectorPayloads(nodeBooleanValue(name,"store_term_vector_payloads", propNode, parserContext)); iterator.remove(); } else if (propName.equals("analyzer")) { NamedAnalyzer analyzer = parserContext.getIndexAnalyzers().get(propNode.toString()); @@ -117,7 +135,8 @@ private static void parseAnalyzersAndTermVectors(FieldMapper.Builder builder, St } if (searchAnalyzer == null && searchQuoteAnalyzer != null) { - throw new MapperParsingException("analyzer and search_analyzer on field [" + name + "] must be set when search_quote_analyzer is set"); + throw new MapperParsingException("analyzer and search_analyzer on field [" + name + + "] must be set when search_quote_analyzer is set"); } if (searchAnalyzer == null) { @@ -139,16 +158,17 @@ private static void parseAnalyzersAndTermVectors(FieldMapper.Builder builder, St } } - public static boolean parseNorms(FieldMapper.Builder builder, String propName, Object propNode, Mapper.TypeParser.ParserContext parserContext) { + public static boolean parseNorms(FieldMapper.Builder builder, String fieldName, String propName, Object propNode, + Mapper.TypeParser.ParserContext parserContext) { if (propName.equals("norms")) { if (propNode instanceof Map) { final Map properties = nodeMapValue(propNode, "norms"); - for (Iterator> propsIterator = properties.entrySet().iterator(); propsIterator.hasNext();) { + for (Iterator> propsIterator = properties.entrySet().iterator(); propsIterator.hasNext(); ) { Entry entry2 = propsIterator.next(); final String propName2 = entry2.getKey(); final Object propNode2 = entry2.getValue(); if (propName2.equals("enabled")) { - builder.omitNorms(!lenientNodeBooleanValue(propNode2)); + builder.omitNorms(nodeBooleanValue(fieldName, "enabled", propNode2, parserContext) == false); propsIterator.remove(); } else if (propName2.equals("loading")) { // ignore for bw compat @@ -156,13 +176,14 @@ public static boolean parseNorms(FieldMapper.Builder builder, String propName, O } } DocumentMapperParser.checkNoRemainingFields(propName, properties, parserContext.indexVersionCreated()); - DEPRECATION_LOGGER.deprecated("The [norms{enabled:true/false}] way of specifying norms is deprecated, please use [norms:true/false] instead"); + DEPRECATION_LOGGER.deprecated("The [norms{enabled:true/false}] way of specifying norms is deprecated, please use " + + "[norms:true/false] instead"); } else { - builder.omitNorms(nodeBooleanValue("norms", propNode, parserContext) == false); + builder.omitNorms(nodeBooleanValue(fieldName,"norms", propNode, parserContext) == false); } return true; } else if (propName.equals("omit_norms")) { - builder.omitNorms(nodeBooleanValue("norms", propNode, parserContext)); + builder.omitNorms(nodeBooleanValue(fieldName,"norms", propNode, parserContext)); DEPRECATION_LOGGER.deprecated("[omit_norms] is deprecated, please use [norms] instead with the opposite boolean value"); return true; } else { @@ -174,14 +195,15 @@ public static boolean parseNorms(FieldMapper.Builder builder, String propName, O * Parse text field attributes. In addition to {@link #parseField common attributes} * this will parse analysis and term-vectors related settings. */ - public static void parseTextField(FieldMapper.Builder builder, String name, Map fieldNode, Mapper.TypeParser.ParserContext parserContext) { + public static void parseTextField(FieldMapper.Builder builder, String name, Map fieldNode, + Mapper.TypeParser.ParserContext parserContext) { parseField(builder, name, fieldNode, parserContext); parseAnalyzersAndTermVectors(builder, name, fieldNode, parserContext); - for (Iterator> iterator = fieldNode.entrySet().iterator(); iterator.hasNext();) { + for (Iterator> iterator = fieldNode.entrySet().iterator(); iterator.hasNext(); ) { Map.Entry entry = iterator.next(); final String propName = entry.getKey(); final Object propNode = entry.getValue(); - if (parseNorms(builder, propName, propNode, parserContext)) { + if (parseNorms(builder, name, propName, propNode, parserContext)) { iterator.remove(); } } @@ -190,8 +212,8 @@ public static void parseTextField(FieldMapper.Builder builder, String name, Map< /** * Parse common field attributes such as {@code doc_values} or {@code store}. */ - public static void parseField(FieldMapper.Builder builder, String name, Map fieldNode, Mapper.TypeParser.ParserContext parserContext) { - Version indexVersionCreated = parserContext.indexVersionCreated(); + public static void parseField(FieldMapper.Builder builder, String name, Map fieldNode, + Mapper.TypeParser.ParserContext parserContext) { for (Iterator> iterator = fieldNode.entrySet().iterator(); iterator.hasNext();) { Map.Entry entry = iterator.next(); final String propName = entry.getKey(); @@ -204,28 +226,29 @@ public static void parseField(FieldMapper.Builder builder, String name, Map) propNode; } else { throw new MapperParsingException("expected map for property [fields] on field [" + propNode + "] or " + - "[" + propName + "] but got a " + propNode.getClass()); + "[" + propName + "] but got a " + propNode.getClass()); } for (Map.Entry multiFieldEntry : multiFieldsPropNodes.entrySet()) { String multiFieldName = multiFieldEntry.getKey(); if (multiFieldName.contains(".")) { - throw new MapperParsingException("Field name [" + multiFieldName + "] which is a multi field of [" + name + "] cannot contain '.'"); + throw new MapperParsingException("Field name [" + multiFieldName + "] which is a multi field of [" + name + "] cannot" + + " contain '.'"); } if (!(multiFieldEntry.getValue() instanceof Map)) { throw new MapperParsingException("illegal field [" + multiFieldName + "], only fields can be specified inside fields"); @@ -343,40 +369,11 @@ public static void parseTermVector(String fieldName, String termVector, FieldMap } } - private static boolean parseIndex(String fieldName, String index) throws MapperParsingException { - switch (index) { - case "true": - return true; - case "false": - return false; - case "not_analyzed": - case "analyzed": - case "no": - DEPRECATION_LOGGER.deprecated("Expected a boolean for property [index] but got [{}]", index); - return "no".equals(index) == false; - default: - throw new IllegalArgumentException("Can't parse [index] value [" + index + "] for field [" + fieldName + "], expected [true] or [false]"); - } - } - - private static boolean parseStore(String store) throws MapperParsingException { - if (BOOLEAN_STRINGS.contains(store) == false) { - DEPRECATION_LOGGER.deprecated("Expected a boolean for property [store] but got [{}]", store); - } - if ("no".equals(store)) { - return false; - } else if ("yes".equals(store)) { - return true; - } else { - return lenientNodeBooleanValue(store); - } - } - @SuppressWarnings("unchecked") public static void parseCopyFields(Object propNode, FieldMapper.Builder builder) { FieldMapper.CopyTo.Builder copyToBuilder = new FieldMapper.CopyTo.Builder(); if (isArray(propNode)) { - for(Object node : (List) propNode) { + for (Object node : (List) propNode) { copyToBuilder.add(nodeStringValue(node, null)); } } else { diff --git a/core/src/main/java/org/elasticsearch/index/shard/IndexShard.java b/core/src/main/java/org/elasticsearch/index/shard/IndexShard.java index 7cdeca2f5fb3f..cb486de610b6e 100644 --- a/core/src/main/java/org/elasticsearch/index/shard/IndexShard.java +++ b/core/src/main/java/org/elasticsearch/index/shard/IndexShard.java @@ -1008,7 +1008,7 @@ private void internalPerformTranslogRecovery(boolean skipTranslogRecovery, boole } recoveryState.setStage(RecoveryState.Stage.VERIFY_INDEX); // also check here, before we apply the translog - if (Booleans.parseBoolean(checkIndexOnStartup, false)) { + if (Booleans.isTrue(checkIndexOnStartup)) { try { checkIndex(); } catch (IOException ex) { diff --git a/core/src/main/java/org/elasticsearch/index/similarity/BM25SimilarityProvider.java b/core/src/main/java/org/elasticsearch/index/similarity/BM25SimilarityProvider.java index 68e50da134876..78c9a4b000cb6 100644 --- a/core/src/main/java/org/elasticsearch/index/similarity/BM25SimilarityProvider.java +++ b/core/src/main/java/org/elasticsearch/index/similarity/BM25SimilarityProvider.java @@ -21,6 +21,7 @@ import org.apache.lucene.search.similarities.BM25Similarity; import org.apache.lucene.search.similarities.Similarity; +import org.elasticsearch.Version; import org.elasticsearch.common.settings.Settings; /** @@ -38,11 +39,12 @@ public class BM25SimilarityProvider extends AbstractSimilarityProvider { private final BM25Similarity similarity; - public BM25SimilarityProvider(String name, Settings settings) { + public BM25SimilarityProvider(String name, Settings settings, Settings indexSettings) { super(name); float k1 = settings.getAsFloat("k1", 1.2f); float b = settings.getAsFloat("b", 0.75f); - boolean discountOverlaps = settings.getAsBoolean("discount_overlaps", true); + boolean discountOverlaps = settings.getAsBooleanLenientForPreEs6Indices( + Version.indexCreated(indexSettings), "discount_overlaps", true); this.similarity = new BM25Similarity(k1, b); this.similarity.setDiscountOverlaps(discountOverlaps); diff --git a/core/src/main/java/org/elasticsearch/index/similarity/ClassicSimilarityProvider.java b/core/src/main/java/org/elasticsearch/index/similarity/ClassicSimilarityProvider.java index f9a6ff2f5fb9c..79e73eaf7e7bc 100644 --- a/core/src/main/java/org/elasticsearch/index/similarity/ClassicSimilarityProvider.java +++ b/core/src/main/java/org/elasticsearch/index/similarity/ClassicSimilarityProvider.java @@ -20,6 +20,7 @@ package org.elasticsearch.index.similarity; import org.apache.lucene.search.similarities.ClassicSimilarity; +import org.elasticsearch.Version; import org.elasticsearch.common.settings.Settings; /** @@ -35,9 +36,10 @@ public class ClassicSimilarityProvider extends AbstractSimilarityProvider { private final ClassicSimilarity similarity = new ClassicSimilarity(); - public ClassicSimilarityProvider(String name, Settings settings) { + public ClassicSimilarityProvider(String name, Settings settings, Settings indexSettings) { super(name); - boolean discountOverlaps = settings.getAsBoolean("discount_overlaps", true); + boolean discountOverlaps = settings.getAsBooleanLenientForPreEs6Indices( + Version.indexCreated(indexSettings), "discount_overlaps", true); this.similarity.setDiscountOverlaps(discountOverlaps); } diff --git a/core/src/main/java/org/elasticsearch/index/similarity/DFISimilarityProvider.java b/core/src/main/java/org/elasticsearch/index/similarity/DFISimilarityProvider.java index 54b0aab758871..e795c7e232f22 100644 --- a/core/src/main/java/org/elasticsearch/index/similarity/DFISimilarityProvider.java +++ b/core/src/main/java/org/elasticsearch/index/similarity/DFISimilarityProvider.java @@ -25,6 +25,7 @@ import org.apache.lucene.search.similarities.IndependenceSaturated; import org.apache.lucene.search.similarities.IndependenceStandardized; import org.apache.lucene.search.similarities.Similarity; +import org.elasticsearch.Version; import org.elasticsearch.common.settings.Settings; import java.util.HashMap; @@ -55,9 +56,10 @@ public class DFISimilarityProvider extends AbstractSimilarityProvider { private final DFISimilarity similarity; - public DFISimilarityProvider(String name, Settings settings) { + public DFISimilarityProvider(String name, Settings settings, Settings indexSettings) { super(name); - boolean discountOverlaps = settings.getAsBoolean("discount_overlaps", true); + boolean discountOverlaps = settings.getAsBooleanLenientForPreEs6Indices( + Version.indexCreated(indexSettings), "discount_overlaps", true); Independence measure = parseIndependence(settings); this.similarity = new DFISimilarity(measure); this.similarity.setDiscountOverlaps(discountOverlaps); diff --git a/core/src/main/java/org/elasticsearch/index/similarity/DFRSimilarityProvider.java b/core/src/main/java/org/elasticsearch/index/similarity/DFRSimilarityProvider.java index 2aeb685de34b0..0d47e86da0182 100644 --- a/core/src/main/java/org/elasticsearch/index/similarity/DFRSimilarityProvider.java +++ b/core/src/main/java/org/elasticsearch/index/similarity/DFRSimilarityProvider.java @@ -75,7 +75,7 @@ public class DFRSimilarityProvider extends AbstractSimilarityProvider { private final DFRSimilarity similarity; - public DFRSimilarityProvider(String name, Settings settings) { + public DFRSimilarityProvider(String name, Settings settings, Settings indexSettings) { super(name); BasicModel basicModel = parseBasicModel(settings); AfterEffect afterEffect = parseAfterEffect(settings); diff --git a/core/src/main/java/org/elasticsearch/index/similarity/IBSimilarityProvider.java b/core/src/main/java/org/elasticsearch/index/similarity/IBSimilarityProvider.java index 4b83bc838f29a..a43276bbfaa82 100644 --- a/core/src/main/java/org/elasticsearch/index/similarity/IBSimilarityProvider.java +++ b/core/src/main/java/org/elasticsearch/index/similarity/IBSimilarityProvider.java @@ -65,7 +65,7 @@ public class IBSimilarityProvider extends AbstractSimilarityProvider { private final IBSimilarity similarity; - public IBSimilarityProvider(String name, Settings settings) { + public IBSimilarityProvider(String name, Settings settings, Settings indexSettings) { super(name); Distribution distribution = parseDistribution(settings); Lambda lambda = parseLambda(settings); diff --git a/core/src/main/java/org/elasticsearch/index/similarity/LMDirichletSimilarityProvider.java b/core/src/main/java/org/elasticsearch/index/similarity/LMDirichletSimilarityProvider.java index 24494dc0b751b..170a7e42133c9 100644 --- a/core/src/main/java/org/elasticsearch/index/similarity/LMDirichletSimilarityProvider.java +++ b/core/src/main/java/org/elasticsearch/index/similarity/LMDirichletSimilarityProvider.java @@ -36,7 +36,7 @@ public class LMDirichletSimilarityProvider extends AbstractSimilarityProvider { private final LMDirichletSimilarity similarity; - public LMDirichletSimilarityProvider(String name, Settings settings) { + public LMDirichletSimilarityProvider(String name, Settings settings, Settings indexSettings) { super(name); float mu = settings.getAsFloat("mu", 2000f); this.similarity = new LMDirichletSimilarity(mu); diff --git a/core/src/main/java/org/elasticsearch/index/similarity/LMJelinekMercerSimilarityProvider.java b/core/src/main/java/org/elasticsearch/index/similarity/LMJelinekMercerSimilarityProvider.java index cd10d29735551..2ee04b78ec2ef 100644 --- a/core/src/main/java/org/elasticsearch/index/similarity/LMJelinekMercerSimilarityProvider.java +++ b/core/src/main/java/org/elasticsearch/index/similarity/LMJelinekMercerSimilarityProvider.java @@ -36,7 +36,7 @@ public class LMJelinekMercerSimilarityProvider extends AbstractSimilarityProvide private final LMJelinekMercerSimilarity similarity; - public LMJelinekMercerSimilarityProvider(String name, Settings settings) { + public LMJelinekMercerSimilarityProvider(String name, Settings settings, Settings indexSettings) { super(name); float lambda = settings.getAsFloat("lambda", 0.1f); this.similarity = new LMJelinekMercerSimilarity(lambda); diff --git a/core/src/main/java/org/elasticsearch/index/similarity/SimilarityService.java b/core/src/main/java/org/elasticsearch/index/similarity/SimilarityService.java index a8b7fafb9804e..54aa940a71f4a 100644 --- a/core/src/main/java/org/elasticsearch/index/similarity/SimilarityService.java +++ b/core/src/main/java/org/elasticsearch/index/similarity/SimilarityService.java @@ -22,6 +22,7 @@ import org.apache.lucene.search.similarities.PerFieldSimilarityWrapper; import org.apache.lucene.search.similarities.Similarity; import org.elasticsearch.Version; +import org.elasticsearch.common.TriFunction; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.AbstractIndexComponent; import org.elasticsearch.index.IndexModule; @@ -32,7 +33,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; -import java.util.function.BiFunction; public final class SimilarityService extends AbstractIndexComponent { @@ -40,11 +40,11 @@ public final class SimilarityService extends AbstractIndexComponent { private final Similarity defaultSimilarity; private final Similarity baseSimilarity; private final Map similarities; - static final Map> DEFAULTS; - public static final Map> BUILT_IN; + private static final Map> DEFAULTS; + public static final Map> BUILT_IN; static { - Map> defaults = new HashMap<>(); - Map> buildIn = new HashMap<>(); + Map> defaults = new HashMap<>(); + Map> buildIn = new HashMap<>(); defaults.put("classic", ClassicSimilarityProvider::new); defaults.put("BM25", BM25SimilarityProvider::new); buildIn.put("classic", ClassicSimilarityProvider::new); @@ -58,7 +58,8 @@ public final class SimilarityService extends AbstractIndexComponent { BUILT_IN = Collections.unmodifiableMap(buildIn); } - public SimilarityService(IndexSettings indexSettings, Map> similarities) { + public SimilarityService(IndexSettings indexSettings, + Map> similarities) { super(indexSettings); Map providers = new HashMap<>(similarities.size()); Map similaritySettings = this.indexSettings.getSettings().getGroups(IndexModule.SIMILARITY_SETTINGS_PREFIX); @@ -68,20 +69,22 @@ public SimilarityService(IndexSettings indexSettings, Map factory = similarities.getOrDefault(typeName, BUILT_IN.get(typeName)); - if (settings == null) { - settings = Settings.Builder.EMPTY_SETTINGS; + TriFunction defaultFactory = BUILT_IN.get(typeName); + TriFunction factory = similarities.getOrDefault(typeName, defaultFactory); + if (providerSettings == null) { + providerSettings = Settings.Builder.EMPTY_SETTINGS; } - providers.put(name, factory.apply(name, settings)); + providers.put(name, factory.apply(name, providerSettings, indexSettings.getSettings())); } - for (Map.Entry entry : addSimilarities(similaritySettings, DEFAULTS).entrySet()) { + Map providerMapping = addSimilarities(similaritySettings, indexSettings.getSettings(), DEFAULTS); + for (Map.Entry entry : providerMapping.entrySet()) { // Avoid overwriting custom providers for indices older that v5.0 if (providers.containsKey(entry.getKey()) && indexSettings.getIndexVersionCreated().before(Version.V_5_0_0_alpha1)) { continue; @@ -102,17 +105,17 @@ public Similarity similarity(MapperService mapperService) { defaultSimilarity; } - private Map addSimilarities(Map similaritySettings, - Map> similarities) { + private Map addSimilarities(Map similaritySettings, Settings indexSettings, + Map> similarities) { Map providers = new HashMap<>(similarities.size()); - for (Map.Entry> entry : similarities.entrySet()) { + for (Map.Entry> entry : similarities.entrySet()) { String name = entry.getKey(); - BiFunction factory = entry.getValue(); - Settings settings = similaritySettings.get(name); - if (settings == null) { - settings = Settings.Builder.EMPTY_SETTINGS; + TriFunction factory = entry.getValue(); + Settings providerSettings = similaritySettings.get(name); + if (providerSettings == null) { + providerSettings = Settings.Builder.EMPTY_SETTINGS; } - providers.put(name, factory.apply(name, settings)); + providers.put(name, factory.apply(name, providerSettings, indexSettings)); } return providers; } diff --git a/core/src/main/java/org/elasticsearch/index/store/FsDirectoryService.java b/core/src/main/java/org/elasticsearch/index/store/FsDirectoryService.java index b6bc8c6081539..bf8e8466dae8b 100644 --- a/core/src/main/java/org/elasticsearch/index/store/FsDirectoryService.java +++ b/core/src/main/java/org/elasticsearch/index/store/FsDirectoryService.java @@ -29,7 +29,6 @@ import org.apache.lucene.store.SimpleFSDirectory; import org.apache.lucene.store.SimpleFSLockFactory; import org.apache.lucene.store.SleepingLockWrapper; -import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting.Property; @@ -75,7 +74,7 @@ public Directory newDirectory() throws IOException { Set preLoadExtensions = new HashSet<>( indexSettings.getValue(IndexModule.INDEX_STORE_PRE_LOAD_SETTING)); wrapped = setPreload(wrapped, location, lockFactory, preLoadExtensions); - if (IndexMetaData.isOnSharedFilesystem(indexSettings.getSettings())) { + if (indexSettings.isOnSharedFilesystem()) { wrapped = new SleepingLockWrapper(wrapped, 5000); } return wrapped; diff --git a/core/src/main/java/org/elasticsearch/rest/RestRequest.java b/core/src/main/java/org/elasticsearch/rest/RestRequest.java index 8c05a2b3ae71d..b4b0614f8ad08 100644 --- a/core/src/main/java/org/elasticsearch/rest/RestRequest.java +++ b/core/src/main/java/org/elasticsearch/rest/RestRequest.java @@ -200,7 +200,13 @@ public long paramAsLong(String key, long defaultValue) { @Override public boolean paramAsBoolean(String key, boolean defaultValue) { - return Booleans.parseBoolean(param(key), defaultValue); + String rawParam = param(key); + // Treat empty string as true because that allows the presence of the url parameter to mean "turn this on" + if (rawParam != null && rawParam.length() == 0) { + return true; + } else { + return Booleans.parseBoolean(rawParam, defaultValue); + } } @Override diff --git a/core/src/main/java/org/elasticsearch/rest/action/cat/RestShardsAction.java b/core/src/main/java/org/elasticsearch/rest/action/cat/RestShardsAction.java index 8944c0827eb01..06b14573a57be 100644 --- a/core/src/main/java/org/elasticsearch/rest/action/cat/RestShardsAction.java +++ b/core/src/main/java/org/elasticsearch/rest/action/cat/RestShardsAction.java @@ -195,7 +195,7 @@ private Table buildTable(RestRequest request, ClusterStateResponse state, Indice IndexMetaData indexMeta = state.getState().getMetaData().getIndexSafe(shard.index()); boolean usesShadowReplicas = false; if (indexMeta != null) { - usesShadowReplicas = IndexMetaData.isIndexUsingShadowReplicas(indexMeta.getSettings()); + usesShadowReplicas = indexMeta.isIndexUsingShadowReplicas(); } if (shard.primary()) { table.addCell("p"); diff --git a/core/src/main/java/org/elasticsearch/rest/action/search/RestMultiSearchAction.java b/core/src/main/java/org/elasticsearch/rest/action/search/RestMultiSearchAction.java index 5cfa7795e00c1..a5a56ebe543d2 100644 --- a/core/src/main/java/org/elasticsearch/rest/action/search/RestMultiSearchAction.java +++ b/core/src/main/java/org/elasticsearch/rest/action/search/RestMultiSearchAction.java @@ -42,7 +42,7 @@ import java.util.Map; import java.util.function.BiConsumer; -import static org.elasticsearch.common.xcontent.support.XContentMapValues.lenientNodeBooleanValue; +import static org.elasticsearch.common.xcontent.support.XContentMapValues.nodeBooleanValue; import static org.elasticsearch.common.xcontent.support.XContentMapValues.nodeStringArrayValue; import static org.elasticsearch.common.xcontent.support.XContentMapValues.nodeStringValue; import static org.elasticsearch.rest.RestRequest.Method.GET; @@ -158,7 +158,7 @@ public static void parseMultiLineRequest(RestRequest request, IndicesOptions ind } else if ("search_type".equals(entry.getKey()) || "searchType".equals(entry.getKey())) { searchRequest.searchType(nodeStringValue(value, null)); } else if ("request_cache".equals(entry.getKey()) || "requestCache".equals(entry.getKey())) { - searchRequest.requestCache(lenientNodeBooleanValue(value)); + searchRequest.requestCache(nodeBooleanValue(value, entry.getKey())); } else if ("preference".equals(entry.getKey())) { searchRequest.preference(nodeStringValue(value, null)); } else if ("routing".equals(entry.getKey())) { diff --git a/core/src/main/java/org/elasticsearch/search/fetch/subphase/FetchSourceContext.java b/core/src/main/java/org/elasticsearch/search/fetch/subphase/FetchSourceContext.java index f3e8bab93fa70..c86342f690f13 100644 --- a/core/src/main/java/org/elasticsearch/search/fetch/subphase/FetchSourceContext.java +++ b/core/src/main/java/org/elasticsearch/search/fetch/subphase/FetchSourceContext.java @@ -96,9 +96,9 @@ public static FetchSourceContext parseFromRestRequest(RestRequest request) { String source = request.param("_source"); if (source != null) { - if (Booleans.isExplicitTrue(source)) { + if (Booleans.isTrue(source)) { fetchSource = true; - } else if (Booleans.isExplicitFalse(source)) { + } else if (Booleans.isFalse(source)) { fetchSource = false; } else { source_includes = Strings.splitStringByCommaToArray(source); diff --git a/core/src/test/java/org/elasticsearch/action/get/MultiGetRequestTests.java b/core/src/test/java/org/elasticsearch/action/get/MultiGetRequestTests.java new file mode 100644 index 0000000000000..6c79b20774c8d --- /dev/null +++ b/core/src/test/java/org/elasticsearch/action/get/MultiGetRequestTests.java @@ -0,0 +1,67 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.action.get; + +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.search.fetch.subphase.FetchSourceContext; +import org.elasticsearch.test.ESTestCase; + +public class MultiGetRequestTests extends ESTestCase { + + public void testAddWithInvalidSourceValueIsRejected() throws Exception { + String sourceValue = randomFrom("on", "off", "0", "1"); + XContentParser parser = createParser(XContentFactory.jsonBuilder() + .startObject() + .startArray("docs") + .startObject() + .field("_source", sourceValue) + .endObject() + .endArray() + .endObject() + ); + + MultiGetRequest multiGetRequest = new MultiGetRequest(); + IllegalArgumentException ex = expectThrows(IllegalArgumentException.class, () -> multiGetRequest.add + (randomAsciiOfLength(5), randomAsciiOfLength(3), null, FetchSourceContext.FETCH_SOURCE, null, parser, true)); + assertEquals("Failed to parse value [" + sourceValue + "] as only [true] or [false] are allowed.", ex.getMessage()); + } + + public void testAddWithValidSourceValueIsAccepted() throws Exception { + XContentParser parser = createParser(XContentFactory.jsonBuilder() + .startObject() + .startArray("docs") + .startObject() + .field("_source", randomFrom("false", "true")) + .endObject() + .startObject() + .field("_source", randomBoolean()) + .endObject() + .endArray() + .endObject() + ); + + MultiGetRequest multiGetRequest = new MultiGetRequest(); + multiGetRequest.add( + randomAsciiOfLength(5), randomAsciiOfLength(3), null, FetchSourceContext.FETCH_SOURCE, null, parser, true); + + assertEquals(2, multiGetRequest.getItems().size()); + } +} diff --git a/core/src/test/java/org/elasticsearch/action/support/IndicesOptionsTests.java b/core/src/test/java/org/elasticsearch/action/support/IndicesOptionsTests.java index d656e0f62a923..c687fc6cabcb4 100644 --- a/core/src/test/java/org/elasticsearch/action/support/IndicesOptionsTests.java +++ b/core/src/test/java/org/elasticsearch/action/support/IndicesOptionsTests.java @@ -31,7 +31,8 @@ public class IndicesOptionsTests extends ESTestCase { public void testSerialization() throws Exception { int iterations = randomIntBetween(5, 20); for (int i = 0; i < iterations; i++) { - IndicesOptions indicesOptions = IndicesOptions.fromOptions(randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean()); + IndicesOptions indicesOptions = IndicesOptions.fromOptions( + randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean()); BytesStreamOutput output = new BytesStreamOutput(); Version outputVersion = randomVersion(random()); diff --git a/core/src/test/java/org/elasticsearch/bwcompat/RestoreBackwardsCompatIT.java b/core/src/test/java/org/elasticsearch/bwcompat/RestoreBackwardsCompatIT.java index 6d13d3cf418c4..6f8019bcdddc6 100644 --- a/core/src/test/java/org/elasticsearch/bwcompat/RestoreBackwardsCompatIT.java +++ b/core/src/test/java/org/elasticsearch/bwcompat/RestoreBackwardsCompatIT.java @@ -52,6 +52,7 @@ import java.util.TreeSet; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; +import static org.hamcrest.Matchers.anyOf; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThan; @@ -189,7 +190,15 @@ private void testOldSnapshot(String version, String repo, String snapshot) throw assertThat(template.patterns(), equalTo(Collections.singletonList("te*"))); assertThat(template.settings().getAsInt(IndexMetaData.SETTING_NUMBER_OF_SHARDS, -1), equalTo(1)); assertThat(template.mappings().size(), equalTo(1)); - assertThat(template.mappings().get("type1").string(), equalTo("{\"type1\":{\"_source\":{\"enabled\":false}}}")); + assertThat(template.mappings().get("type1").string(), + anyOf( + equalTo("{\"type1\":{\"_source\":{\"enabled\":false}}}"), + equalTo("{\"type1\":{\"_source\":{\"enabled\":\"false\"}}}"), + equalTo("{\"type1\":{\"_source\":{\"enabled\":\"0\"}}}"), + equalTo("{\"type1\":{\"_source\":{\"enabled\":0}}}"), + equalTo("{\"type1\":{\"_source\":{\"enabled\":\"off\"}}}"), + equalTo("{\"type1\":{\"_source\":{\"enabled\":\"no\"}}}") + )); assertThat(template.aliases().size(), equalTo(3)); assertThat(template.aliases().get("alias1"), notNullValue()); assertThat(template.aliases().get("alias2").filter().string(), containsString(version)); diff --git a/core/src/test/java/org/elasticsearch/cluster/SimpleClusterStateIT.java b/core/src/test/java/org/elasticsearch/cluster/SimpleClusterStateIT.java index 1944ed6e3bc6d..89d33043e574f 100644 --- a/core/src/test/java/org/elasticsearch/cluster/SimpleClusterStateIT.java +++ b/core/src/test/java/org/elasticsearch/cluster/SimpleClusterStateIT.java @@ -96,18 +96,37 @@ public void testIndexTemplates() throws Exception { client().admin().indices().preparePutTemplate("foo_template") .setPatterns(Collections.singletonList("te*")) .setOrder(0) - .addMapping("type1", XContentFactory.jsonBuilder().startObject().startObject("type1").startObject("properties") - .startObject("field1").field("type", "text").field("store", true).endObject() - .startObject("field2").field("type", "keyword").field("store", true).endObject() - .endObject().endObject().endObject()) + .addMapping("type1", XContentFactory.jsonBuilder() + .startObject() + .startObject("type1") + .startObject("properties") + .startObject("field1") + .field("type", "text") + .field("store", true) + .endObject() + .startObject("field2") + .field("type", "keyword") + .field("store", true) + .endObject() + .endObject() + .endObject() + .endObject()) .get(); client().admin().indices().preparePutTemplate("fuu_template") .setPatterns(Collections.singletonList("test*")) .setOrder(1) - .addMapping("type1", XContentFactory.jsonBuilder().startObject().startObject("type1").startObject("properties") - .startObject("field2").field("type", "text").field("store", "no").endObject() - .endObject().endObject().endObject()) + .addMapping("type1", XContentFactory.jsonBuilder() + .startObject() + .startObject("type1") + .startObject("properties") + .startObject("field2") + .field("type", "text") + .field("store", false) + .endObject() + .endObject() + .endObject() + .endObject()) .get(); ClusterStateResponse clusterStateResponseUnfiltered = client().admin().cluster().prepareState().get(); diff --git a/core/src/test/java/org/elasticsearch/common/BooleansTests.java b/core/src/test/java/org/elasticsearch/common/BooleansTests.java index 176c4c75dc7a6..2e14159c07cde 100644 --- a/core/src/test/java/org/elasticsearch/common/BooleansTests.java +++ b/core/src/test/java/org/elasticsearch/common/BooleansTests.java @@ -28,59 +28,103 @@ import static org.hamcrest.Matchers.nullValue; public class BooleansTests extends ESTestCase { + private static final String[] NON_BOOLEANS = new String[]{"11", "00", "sdfsdfsf", "F", "T", "on", "off", "yes", "no", "0", "1", + "True", "False"}; + private static final String[] BOOLEANS = new String[]{"true", "false"}; + public void testIsBoolean() { + for (String b : BOOLEANS) { + String t = "prefix" + b + "suffix"; + assertTrue("failed to recognize [" + b + "] as boolean", + Booleans.isBoolean(t.toCharArray(), "prefix".length(), b.length())); + assertTrue("failed to recognize [" + b + "] as boolean", Booleans.isBoolean(b)); + } + } + + public void testIsNonBoolean() { + assertThat(Booleans.isBoolean(null, 0, 1), is(false)); + + for (String nb : NON_BOOLEANS) { + String t = "prefix" + nb + "suffix"; + assertFalse("recognized [" + nb + "] as boolean", Booleans.isBoolean(t.toCharArray(), "prefix".length(), nb.length())); + assertFalse("recognized [" + nb + "] as boolean", Booleans.isBoolean(t)); + } + } + + public void testParseBooleanWithFallback() { + assertFalse(Booleans.parseBoolean(null, false)); + assertTrue(Booleans.parseBoolean(null, true)); + assertNull(Booleans.parseBoolean(null, null)); + assertFalse(Booleans.parseBoolean(null, Boolean.FALSE)); + assertTrue(Booleans.parseBoolean(null, Boolean.TRUE)); + + assertTrue(Booleans.parseBoolean("true", randomFrom(Boolean.TRUE, Boolean.FALSE, null))); + assertFalse(Booleans.parseBoolean("false", randomFrom(Boolean.TRUE, Boolean.FALSE, null))); + } + + public void testParseNonBooleanWithFallback() { + for (String nonBoolean : NON_BOOLEANS) { + boolean defaultValue = randomFrom(Boolean.TRUE, Boolean.FALSE); + + expectThrows(IllegalArgumentException.class, + () -> Booleans.parseBoolean(nonBoolean, defaultValue)); + expectThrows(IllegalArgumentException.class, + () -> Booleans.parseBoolean(nonBoolean.toCharArray(), 0, nonBoolean.length(), defaultValue)); + } + } + + public void testParseBoolean() { + assertTrue(Booleans.parseBoolean("true")); + assertFalse(Booleans.parseBoolean("false")); + } + + public void testParseNonBoolean() { + expectThrows(IllegalArgumentException.class, () -> Booleans.parseBoolean(null)); + for (String nonBoolean : NON_BOOLEANS) { + expectThrows(IllegalArgumentException.class, () -> Booleans.parseBoolean(nonBoolean)); + } + } + + public void testIsBooleanLenient() { String[] booleans = new String[]{"true", "false", "on", "off", "yes", "no", "0", "1"}; String[] notBooleans = new String[]{"11", "00", "sdfsdfsf", "F", "T"}; - assertThat(Booleans.isBoolean(null, 0, 1), is(false)); + assertThat(Booleans.isBooleanLenient(null, 0, 1), is(false)); for (String b : booleans) { String t = "prefix" + b + "suffix"; - assertThat("failed to recognize [" + b + "] as boolean", Booleans.isBoolean(t.toCharArray(), "prefix".length(), b.length()), Matchers.equalTo(true)); + assertTrue("failed to recognize [" + b + "] as boolean", + Booleans.isBooleanLenient(t.toCharArray(), "prefix".length(), b.length())); } for (String nb : notBooleans) { String t = "prefix" + nb + "suffix"; - assertThat("recognized [" + nb + "] as boolean", Booleans.isBoolean(t.toCharArray(), "prefix".length(), nb.length()), Matchers.equalTo(false)); + assertFalse("recognized [" + nb + "] as boolean", + Booleans.isBooleanLenient(t.toCharArray(), "prefix".length(), nb.length())); } } - public void testParseBoolean() { - assertThat(Booleans.parseBoolean(randomFrom("true", "on", "yes", "1"), randomBoolean()), is(true)); - assertThat(Booleans.parseBoolean(randomFrom("false", "off", "no", "0"), randomBoolean()), is(false)); - assertThat(Booleans.parseBoolean(randomFrom("true", "on", "yes").toUpperCase(Locale.ROOT), randomBoolean()), is(true)); - assertThat(Booleans.parseBoolean(null, false), is(false)); - assertThat(Booleans.parseBoolean(null, true), is(true)); - - assertThat(Booleans.parseBoolean(randomFrom("true", "on", "yes", "1"), randomFrom(Boolean.TRUE, Boolean.FALSE, null)), is(true)); - assertThat(Booleans.parseBoolean(randomFrom("false", "off", "no", "0"), randomFrom(Boolean.TRUE, Boolean.FALSE, null)), is(false)); - assertThat(Booleans.parseBoolean(randomFrom("true", "on", "yes").toUpperCase(Locale.ROOT),randomFrom(Boolean.TRUE, Boolean.FALSE, null)), is(true)); - assertThat(Booleans.parseBoolean(null, Boolean.FALSE), is(false)); - assertThat(Booleans.parseBoolean(null, Boolean.TRUE), is(true)); - assertThat(Booleans.parseBoolean(null, null), nullValue()); + public void testParseBooleanLenient() { + assertThat(Booleans.parseBooleanLenient(randomFrom("true", "on", "yes", "1"), randomBoolean()), is(true)); + assertThat(Booleans.parseBooleanLenient(randomFrom("false", "off", "no", "0"), randomBoolean()), is(false)); + assertThat(Booleans.parseBooleanLenient(randomFrom("true", "on", "yes").toUpperCase(Locale.ROOT), randomBoolean()), is(true)); + assertThat(Booleans.parseBooleanLenient(null, false), is(false)); + assertThat(Booleans.parseBooleanLenient(null, true), is(true)); + + assertThat(Booleans.parseBooleanLenient( + randomFrom("true", "on", "yes", "1"), randomFrom(Boolean.TRUE, Boolean.FALSE, null)), is(true)); + assertThat(Booleans.parseBooleanLenient( + randomFrom("false", "off", "no", "0"), randomFrom(Boolean.TRUE, Boolean.FALSE, null)), is(false)); + assertThat(Booleans.parseBooleanLenient( + randomFrom("true", "on", "yes").toUpperCase(Locale.ROOT),randomFrom(Boolean.TRUE, Boolean.FALSE, null)), is(true)); + assertThat(Booleans.parseBooleanLenient(null, Boolean.FALSE), is(false)); + assertThat(Booleans.parseBooleanLenient(null, Boolean.TRUE), is(true)); + assertThat(Booleans.parseBooleanLenient(null, null), nullValue()); char[] chars = randomFrom("true", "on", "yes", "1").toCharArray(); - assertThat(Booleans.parseBoolean(chars, 0, chars.length, randomBoolean()), is(true)); + assertThat(Booleans.parseBooleanLenient(chars, 0, chars.length, randomBoolean()), is(true)); chars = randomFrom("false", "off", "no", "0").toCharArray(); - assertThat(Booleans.parseBoolean(chars,0, chars.length, randomBoolean()), is(false)); + assertThat(Booleans.parseBooleanLenient(chars,0, chars.length, randomBoolean()), is(false)); chars = randomFrom("true", "on", "yes").toUpperCase(Locale.ROOT).toCharArray(); - assertThat(Booleans.parseBoolean(chars,0, chars.length, randomBoolean()), is(true)); - } - - public void testParseBooleanExact() { - assertThat(Booleans.parseBooleanExact(randomFrom("true", "on", "yes", "1")), is(true)); - assertThat(Booleans.parseBooleanExact(randomFrom("false", "off", "no", "0")), is(false)); - try { - Booleans.parseBooleanExact(randomFrom("fred", "foo", "barney", null)); - fail("Expected exception while parsing invalid boolean value "); - } catch (Exception ex) { - assertTrue(ex instanceof IllegalArgumentException); - } - } - - public void testIsExplicit() { - assertThat(Booleans.isExplicitFalse(randomFrom("true", "on", "yes", "1", "foo", null)), is(false)); - assertThat(Booleans.isExplicitFalse(randomFrom("false", "off", "no", "0")), is(true)); - assertThat(Booleans.isExplicitTrue(randomFrom("true", "on", "yes", "1")), is(true)); - assertThat(Booleans.isExplicitTrue(randomFrom("false", "off", "no", "0", "foo", null)), is(false)); + assertThat(Booleans.parseBooleanLenient(chars,0, chars.length, randomBoolean()), is(true)); } } diff --git a/core/src/test/java/org/elasticsearch/common/settings/SettingTests.java b/core/src/test/java/org/elasticsearch/common/settings/SettingTests.java index 3789ea40459b2..24b48cbf3683c 100644 --- a/core/src/test/java/org/elasticsearch/common/settings/SettingTests.java +++ b/core/src/test/java/org/elasticsearch/common/settings/SettingTests.java @@ -127,7 +127,7 @@ public void testSimpleUpdate() { settingUpdater.apply(build, Settings.EMPTY); fail("not a boolean"); } catch (IllegalArgumentException ex) { - assertEquals("Failed to parse value [I am not a boolean] cannot be parsed to boolean [ true/1/on/yes OR false/0/off/no ]", + assertEquals("Failed to parse value [I am not a boolean] as only [true] or [false] are allowed.", ex.getMessage()); } } diff --git a/core/src/test/java/org/elasticsearch/common/settings/SettingsModuleTests.java b/core/src/test/java/org/elasticsearch/common/settings/SettingsModuleTests.java index dc0545624d662..929aacf8a9a74 100644 --- a/core/src/test/java/org/elasticsearch/common/settings/SettingsModuleTests.java +++ b/core/src/test/java/org/elasticsearch/common/settings/SettingsModuleTests.java @@ -118,7 +118,7 @@ public void testSpecialTribeSetting() { new SettingsModule(settings); fail(); } catch (IllegalArgumentException ex) { - assertEquals("Failed to parse value [BOOM] cannot be parsed to boolean [ true/1/on/yes OR false/0/off/no ]", + assertEquals("Failed to parse value [BOOM] as only [true] or [false] are allowed.", ex.getMessage()); } } diff --git a/core/src/test/java/org/elasticsearch/common/settings/SettingsTests.java b/core/src/test/java/org/elasticsearch/common/settings/SettingsTests.java index 62fa9ec82c419..4b1aa077b675b 100644 --- a/core/src/test/java/org/elasticsearch/common/settings/SettingsTests.java +++ b/core/src/test/java/org/elasticsearch/common/settings/SettingsTests.java @@ -19,14 +19,14 @@ package org.elasticsearch.common.settings; +import org.elasticsearch.Version; +import org.elasticsearch.common.Booleans; import org.elasticsearch.common.settings.loader.YamlSettingsLoader; -import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.test.ESTestCase; import org.hamcrest.Matchers; import java.io.IOException; import java.util.ArrayList; -import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -148,6 +148,66 @@ public void testGetAsSettings() { assertThat(fooSettings.get("baz"), equalTo("ghi")); } + @SuppressWarnings("deprecation") //#getAsBooleanLenientForPreEs6Indices is the test subject + public void testLenientBooleanForPreEs6Index() throws IOException { + // time to say goodbye? + assertTrue( + "It's time to implement #22298. Please delete this test and Settings#getAsBooleanLenientForPreEs6Indices().", + Version.CURRENT.minimumCompatibilityVersion().before(Version.V_6_0_0_alpha1_UNRELEASED)); + + + String falsy = randomFrom("false", "off", "no", "0"); + String truthy = randomFrom("true", "on", "yes", "1"); + + Settings settings = Settings.builder() + .put("foo", falsy) + .put("bar", truthy).build(); + + assertFalse(settings.getAsBooleanLenientForPreEs6Indices(Version.V_5_0_0, "foo", null)); + assertTrue(settings.getAsBooleanLenientForPreEs6Indices(Version.V_5_0_0, "bar", null)); + assertTrue(settings.getAsBooleanLenientForPreEs6Indices(Version.V_5_0_0, "baz", true)); + + List expectedDeprecationWarnings = new ArrayList<>(); + if (Booleans.isBoolean(falsy) == false) { + expectedDeprecationWarnings.add( + "The value [" + falsy + "] of setting [foo] is not coerced into boolean anymore. Please change this value to [false]."); + } + if (Booleans.isBoolean(truthy) == false) { + expectedDeprecationWarnings.add( + "The value [" + truthy + "] of setting [bar] is not coerced into boolean anymore. Please change this value to [true]."); + } + + if (expectedDeprecationWarnings.isEmpty() == false) { + assertWarnings(expectedDeprecationWarnings.toArray(new String[1])); + } + } + + @SuppressWarnings("deprecation") //#getAsBooleanLenientForPreEs6Indices is the test subject + public void testInvalidLenientBooleanForCurrentIndexVersion() { + String falsy = randomFrom("off", "no", "0"); + String truthy = randomFrom("on", "yes", "1"); + + Settings settings = Settings.builder() + .put("foo", falsy) + .put("bar", truthy).build(); + + expectThrows(IllegalArgumentException.class, + () -> settings.getAsBooleanLenientForPreEs6Indices(Version.CURRENT, "foo", null)); + expectThrows(IllegalArgumentException.class, + () -> settings.getAsBooleanLenientForPreEs6Indices(Version.CURRENT, "bar", null)); + } + + @SuppressWarnings("deprecation") //#getAsBooleanLenientForPreEs6Indices is the test subject + public void testValidLenientBooleanForCurrentIndexVersion() { + Settings settings = Settings.builder() + .put("foo", "false") + .put("bar", "true").build(); + + assertFalse(settings.getAsBooleanLenientForPreEs6Indices(Version.CURRENT, "foo", null)); + assertTrue(settings.getAsBooleanLenientForPreEs6Indices(Version.CURRENT, "bar", null)); + assertTrue(settings.getAsBooleanLenientForPreEs6Indices(Version.CURRENT, "baz", true)); + } + public void testMultLevelGetPrefix() { Settings settings = Settings.builder() .put("1.2.3", "hello world") diff --git a/core/src/test/java/org/elasticsearch/common/xcontent/XContentParserTests.java b/core/src/test/java/org/elasticsearch/common/xcontent/XContentParserTests.java index a7257fbca8b45..02fd68890a6f7 100644 --- a/core/src/test/java/org/elasticsearch/common/xcontent/XContentParserTests.java +++ b/core/src/test/java/org/elasticsearch/common/xcontent/XContentParserTests.java @@ -19,11 +19,13 @@ package org.elasticsearch.common.xcontent; +import com.fasterxml.jackson.core.JsonParseException; import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.test.ESTestCase; import java.io.IOException; +import java.util.Arrays; import java.util.List; import java.util.Map; @@ -32,6 +34,7 @@ import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.isIn; import static org.hamcrest.Matchers.nullValue; public class XContentParserTests extends ESTestCase { @@ -102,4 +105,92 @@ private Map readMapStrings(String source) throws IOException { return randomBoolean() ? parser.mapStringsOrdered() : parser.mapStrings(); } } + + @SuppressWarnings("deprecation") // #isBooleanValueLenient() and #booleanValueLenient() are the test subjects + public void testReadLenientBooleans() throws IOException { + // allow String, boolean and int representations of lenient booleans + String falsy = randomFrom("\"off\"", "\"no\"", "\"0\"", "0", "\"false\"", "false"); + String truthy = randomFrom("\"on\"", "\"yes\"", "\"1\"", "1", "\"true\"", "true"); + + try (XContentParser parser = createParser(JsonXContent.jsonXContent, "{\"foo\": " + falsy + ", \"bar\": " + truthy + "}")) { + XContentParser.Token token = parser.nextToken(); + assertThat(token, equalTo(XContentParser.Token.START_OBJECT)); + token = parser.nextToken(); + assertThat(token, equalTo(XContentParser.Token.FIELD_NAME)); + assertThat(parser.currentName(), equalTo("foo")); + token = parser.nextToken(); + assertThat(token, isIn( + Arrays.asList(XContentParser.Token.VALUE_STRING, XContentParser.Token.VALUE_NUMBER, XContentParser.Token.VALUE_BOOLEAN))); + assertTrue(parser.isBooleanValueLenient()); + assertFalse(parser.booleanValueLenient()); + + token = parser.nextToken(); + assertThat(token, equalTo(XContentParser.Token.FIELD_NAME)); + assertThat(parser.currentName(), equalTo("bar")); + token = parser.nextToken(); + assertThat(token, isIn( + Arrays.asList(XContentParser.Token.VALUE_STRING, XContentParser.Token.VALUE_NUMBER, XContentParser.Token.VALUE_BOOLEAN))); + assertTrue(parser.isBooleanValueLenient()); + assertTrue(parser.booleanValueLenient()); + } + } + + public void testReadBooleansFailsForLenientBooleans() throws IOException { + String falsy = randomFrom("\"off\"", "\"no\"", "\"0\"", "0"); + String truthy = randomFrom("\"on\"", "\"yes\"", "\"1\"", "1"); + + try (XContentParser parser = createParser(JsonXContent.jsonXContent, "{\"foo\": " + falsy + ", \"bar\": " + truthy + "}")) { + XContentParser.Token token = parser.nextToken(); + assertThat(token, equalTo(XContentParser.Token.START_OBJECT)); + + token = parser.nextToken(); + assertThat(token, equalTo(XContentParser.Token.FIELD_NAME)); + assertThat(parser.currentName(), equalTo("foo")); + token = parser.nextToken(); + assertThat(token, isIn(Arrays.asList(XContentParser.Token.VALUE_STRING, XContentParser.Token.VALUE_NUMBER))); + assertFalse(parser.isBooleanValue()); + if (token.equals(XContentParser.Token.VALUE_STRING)) { + expectThrows(IllegalArgumentException.class, parser::booleanValue); + } else { + expectThrows(JsonParseException.class, parser::booleanValue); + } + + token = parser.nextToken(); + assertThat(token, equalTo(XContentParser.Token.FIELD_NAME)); + assertThat(parser.currentName(), equalTo("bar")); + token = parser.nextToken(); + assertThat(token, isIn(Arrays.asList(XContentParser.Token.VALUE_STRING, XContentParser.Token.VALUE_NUMBER))); + assertFalse(parser.isBooleanValue()); + if (token.equals(XContentParser.Token.VALUE_STRING)) { + expectThrows(IllegalArgumentException.class, parser::booleanValue); + } else { + expectThrows(JsonParseException.class, parser::booleanValue); + } + } + } + + public void testReadBooleans() throws IOException { + String falsy = randomFrom("\"false\"", "false"); + String truthy = randomFrom("\"true\"", "true"); + + try (XContentParser parser = createParser(JsonXContent.jsonXContent, "{\"foo\": " + falsy + ", \"bar\": " + truthy + "}")) { + XContentParser.Token token = parser.nextToken(); + assertThat(token, equalTo(XContentParser.Token.START_OBJECT)); + token = parser.nextToken(); + assertThat(token, equalTo(XContentParser.Token.FIELD_NAME)); + assertThat(parser.currentName(), equalTo("foo")); + token = parser.nextToken(); + assertThat(token, isIn(Arrays.asList(XContentParser.Token.VALUE_STRING, XContentParser.Token.VALUE_BOOLEAN))); + assertTrue(parser.isBooleanValue()); + assertFalse(parser.booleanValue()); + + token = parser.nextToken(); + assertThat(token, equalTo(XContentParser.Token.FIELD_NAME)); + assertThat(parser.currentName(), equalTo("bar")); + token = parser.nextToken(); + assertThat(token, isIn(Arrays.asList(XContentParser.Token.VALUE_STRING, XContentParser.Token.VALUE_BOOLEAN))); + assertTrue(parser.isBooleanValue()); + assertTrue(parser.booleanValue()); + } + } } diff --git a/core/src/test/java/org/elasticsearch/index/IndexModuleTests.java b/core/src/test/java/org/elasticsearch/index/IndexModuleTests.java index 0958bbc605526..86dbc8b740e7d 100644 --- a/core/src/test/java/org/elasticsearch/index/IndexModuleTests.java +++ b/core/src/test/java/org/elasticsearch/index/IndexModuleTests.java @@ -296,7 +296,7 @@ public void testAddSimilarity() throws IOException { .build(); IndexModule module = new IndexModule(IndexSettingsModule.newIndexSettings("foo", indexSettings), new AnalysisRegistry(environment, emptyMap(), emptyMap(), emptyMap(), emptyMap(), emptyMap())); - module.addSimilarity("test_similarity", (string, settings) -> new SimilarityProvider() { + module.addSimilarity("test_similarity", (string, providerSettings, indexLevelSettings) -> new SimilarityProvider() { @Override public String name() { return string; @@ -304,7 +304,7 @@ public String name() { @Override public Similarity get() { - return new TestSimilarity(settings.get("key")); + return new TestSimilarity(providerSettings.get("key")); } }); diff --git a/core/src/test/java/org/elasticsearch/index/IndexServiceTests.java b/core/src/test/java/org/elasticsearch/index/IndexServiceTests.java index a601f238d24b2..28d67a4a1e2b6 100644 --- a/core/src/test/java/org/elasticsearch/index/IndexServiceTests.java +++ b/core/src/test/java/org/elasticsearch/index/IndexServiceTests.java @@ -21,9 +21,8 @@ import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.TopDocs; -import org.elasticsearch.cluster.metadata.AliasMetaData; +import org.elasticsearch.Version; import org.elasticsearch.cluster.metadata.IndexMetaData; -import org.elasticsearch.common.Nullable; import org.elasticsearch.common.compress.CompressedXContent; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; @@ -34,7 +33,6 @@ import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.shard.IndexShard; import org.elasticsearch.index.translog.Translog; -import org.elasticsearch.indices.InvalidAliasNameException; import org.elasticsearch.test.ESSingleNodeTestCase; import org.elasticsearch.threadpool.ThreadPool; @@ -45,24 +43,32 @@ import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_REPLICAS; import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_SHARDS; -import static org.elasticsearch.index.query.QueryBuilders.termQuery; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.nullValue; /** Unit test(s) for IndexService */ public class IndexServiceTests extends ESSingleNodeTestCase { public void testDetermineShadowEngineShouldBeUsed() { - Settings regularSettings = Settings.builder() - .put(SETTING_NUMBER_OF_SHARDS, 2) - .put(SETTING_NUMBER_OF_REPLICAS, 1) - .build(); - - Settings shadowSettings = Settings.builder() - .put(SETTING_NUMBER_OF_SHARDS, 2) - .put(SETTING_NUMBER_OF_REPLICAS, 1) - .put(IndexMetaData.SETTING_SHADOW_REPLICAS, true) - .build(); + IndexSettings regularSettings = new IndexSettings( + IndexMetaData + .builder("regular") + .settings(Settings.builder() + .put(SETTING_NUMBER_OF_SHARDS, 2) + .put(SETTING_NUMBER_OF_REPLICAS, 1) + .put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT) + .build()) + .build(), + Settings.EMPTY); + + IndexSettings shadowSettings = new IndexSettings( + IndexMetaData + .builder("shadow") + .settings(Settings.builder() + .put(SETTING_NUMBER_OF_SHARDS, 2) + .put(SETTING_NUMBER_OF_REPLICAS, 1) + .put(IndexMetaData.SETTING_SHADOW_REPLICAS, true) + .put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT) + .build()) + .build(), + Settings.EMPTY); assertFalse("no shadow replicas for normal settings", IndexService.useShadowEngine(true, regularSettings)); assertFalse("no shadow replicas for normal settings", IndexService.useShadowEngine(false, regularSettings)); diff --git a/core/src/test/java/org/elasticsearch/index/IndexingSlowLogTests.java b/core/src/test/java/org/elasticsearch/index/IndexingSlowLogTests.java index 16903a01d911c..ecdba6ec44f1e 100644 --- a/core/src/test/java/org/elasticsearch/index/IndexingSlowLogTests.java +++ b/core/src/test/java/org/elasticsearch/index/IndexingSlowLogTests.java @@ -88,7 +88,7 @@ public void testReformatSetting() { settings.updateIndexMetaData(newIndexMeta("index", Settings.builder().put(IndexingSlowLog.INDEX_INDEXING_SLOWLOG_REFORMAT_SETTING.getKey(), "NOT A BOOLEAN").build())); fail(); } catch (IllegalArgumentException ex) { - assertEquals(ex.getMessage(), "Failed to parse value [NOT A BOOLEAN] cannot be parsed to boolean [ true/1/on/yes OR false/0/off/no ]"); + assertEquals(ex.getMessage(), "Failed to parse value [NOT A BOOLEAN] as only [true] or [false] are allowed."); } assertTrue(log.isReformat()); } diff --git a/core/src/test/java/org/elasticsearch/index/mapper/BooleanFieldMapperTests.java b/core/src/test/java/org/elasticsearch/index/mapper/BooleanFieldMapperTests.java index 308f7755275b3..2486f91ccd3d0 100644 --- a/core/src/test/java/org/elasticsearch/index/mapper/BooleanFieldMapperTests.java +++ b/core/src/test/java/org/elasticsearch/index/mapper/BooleanFieldMapperTests.java @@ -30,8 +30,12 @@ import org.apache.lucene.store.Directory; import org.apache.lucene.store.RAMDirectory; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.Version; +import org.elasticsearch.cluster.metadata.IndexMetaData; +import org.elasticsearch.common.Booleans; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.compress.CompressedXContent; +import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; @@ -43,19 +47,25 @@ import org.junit.Before; import java.io.IOException; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; import static org.hamcrest.Matchers.containsString; public class BooleanFieldMapperTests extends ESSingleNodeTestCase { - - IndexService indexService; - DocumentMapperParser parser; + private IndexService indexService; + private DocumentMapperParser parser; + private DocumentMapperParser preEs6Parser; @Before public void setup() { indexService = createIndex("test"); parser = indexService.mapperService().documentMapperParser(); + + IndexService preEs6IndexService = createIndex("legacy", + Settings.builder().put(IndexMetaData.SETTING_VERSION_CREATED, Version.V_5_0_0).build()); + preEs6Parser = preEs6IndexService.mapperService().documentMapperParser(); } @Override @@ -121,6 +131,69 @@ public void testSerialization() throws IOException { assertEquals("{\"field\":{\"type\":\"boolean\",\"doc_values\":false,\"null_value\":true}}", builder.string()); } + public void testParsesPreEs6BooleansLenient() throws IOException { + String mapping = XContentFactory.jsonBuilder() + .startObject() + .startObject("type") + .startObject("properties") + .startObject("field1") + .field("type", "boolean") + .endObject() + .startObject("field2") + .field("type", "boolean") + .endObject() + .endObject() + .endObject() + .endObject().string(); + DocumentMapper defaultMapper = preEs6Parser.parse("type", new CompressedXContent(mapping)); + + String falsy = randomFrom("false", "off", "no", "0"); + String truthy = randomFrom("true", "on", "yes", "1"); + + ParsedDocument parsedDoc = defaultMapper.parse("legacy", "type", "1", XContentFactory.jsonBuilder() + .startObject() + .field("field1", falsy) + .field("field2", truthy) + .endObject() + .bytes()); + Document doc = parsedDoc.rootDoc(); + assertEquals("F", doc.getField("field1").stringValue()); + assertEquals("T", doc.getField("field2").stringValue()); + + List expectedDeprecationWarnings = new ArrayList<>(); + if (Booleans.isBoolean(falsy) == false) { + expectedDeprecationWarnings.add("Expected a boolean for property [field1] but got ["+ falsy + "]"); + } + if (Booleans.isBoolean(truthy) == false) { + expectedDeprecationWarnings.add("Expected a boolean for property [field2] but got [" + truthy + "]"); + } + + if (expectedDeprecationWarnings.isEmpty() == false) { + assertWarnings(expectedDeprecationWarnings.toArray(new String[1])); + } + } + + public void testParsesEs6BooleansStrict() throws IOException { + String mapping = XContentFactory.jsonBuilder() + .startObject() + .startObject("type") + .startObject("properties") + .startObject("field") + .field("type", "boolean") + .endObject() + .endObject() + .endObject() + .endObject().string(); + DocumentMapper defaultMapper = parser.parse("type", new CompressedXContent(mapping)); + BytesReference source = XContentFactory.jsonBuilder() + .startObject() + // omit "false"/"true" here as they should still be parsed correctly + .field("field", randomFrom("off", "no", "0", "on", "yes", "1")) + .endObject().bytes(); + MapperParsingException ex = expectThrows(MapperParsingException.class, () -> defaultMapper.parse("test", "type", "1", source)); + assertEquals("failed to parse [field]", ex.getMessage()); + } + public void testMultiFields() throws IOException { String mapping = XContentFactory.jsonBuilder().startObject().startObject("type") .startObject("properties") @@ -133,7 +206,8 @@ public void testMultiFields() throws IOException { .endObject() .endObject().endObject() .endObject().endObject().string(); - DocumentMapper mapper = indexService.mapperService().merge("type", new CompressedXContent(mapping), MapperService.MergeReason.MAPPING_UPDATE, false); + DocumentMapper mapper = indexService.mapperService() + .merge("type", new CompressedXContent(mapping), MapperService.MergeReason.MAPPING_UPDATE, false); assertEquals(mapping, mapper.mappingSource().toString()); BytesReference source = XContentFactory.jsonBuilder() .startObject() diff --git a/core/src/test/java/org/elasticsearch/index/mapper/FieldTypeTestCase.java b/core/src/test/java/org/elasticsearch/index/mapper/FieldTypeTestCase.java index 96ca2e72b9571..5d86602c4ca09 100644 --- a/core/src/test/java/org/elasticsearch/index/mapper/FieldTypeTestCase.java +++ b/core/src/test/java/org/elasticsearch/index/mapper/FieldTypeTestCase.java @@ -19,6 +19,8 @@ package org.elasticsearch.index.mapper; import org.apache.lucene.analysis.standard.StandardAnalyzer; +import org.elasticsearch.Version; +import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.analysis.AnalyzerScope; import org.elasticsearch.index.analysis.NamedAnalyzer; @@ -32,6 +34,8 @@ /** Base test case for subclasses of MappedFieldType */ public abstract class FieldTypeTestCase extends ESTestCase { + private static final Settings INDEX_SETTINGS = Settings.builder().put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT).build(); + /** Abstraction for mutating a property of a MappedFieldType */ public abstract static class Modifier { /** The name of the property that is being modified. Used in test failure messages. */ @@ -117,17 +121,17 @@ public void normalizeOther(MappedFieldType other) { new Modifier("similarity", false) { @Override public void modify(MappedFieldType ft) { - ft.setSimilarity(new BM25SimilarityProvider("foo", Settings.EMPTY)); + ft.setSimilarity(new BM25SimilarityProvider("foo", Settings.EMPTY, INDEX_SETTINGS)); } }, new Modifier("similarity", false) { @Override public void modify(MappedFieldType ft) { - ft.setSimilarity(new BM25SimilarityProvider("foo", Settings.EMPTY)); + ft.setSimilarity(new BM25SimilarityProvider("foo", Settings.EMPTY, INDEX_SETTINGS)); } @Override public void normalizeOther(MappedFieldType other) { - other.setSimilarity(new BM25SimilarityProvider("bar", Settings.EMPTY)); + other.setSimilarity(new BM25SimilarityProvider("bar", Settings.EMPTY, INDEX_SETTINGS)); } }, new Modifier("eager_global_ordinals", true) { diff --git a/core/src/test/java/org/elasticsearch/index/mapper/UpdateMappingTests.java b/core/src/test/java/org/elasticsearch/index/mapper/UpdateMappingTests.java index ee92f255d4384..9321801d1f439 100644 --- a/core/src/test/java/org/elasticsearch/index/mapper/UpdateMappingTests.java +++ b/core/src/test/java/org/elasticsearch/index/mapper/UpdateMappingTests.java @@ -53,13 +53,29 @@ private void testNoConflictWhileMergingAndMappingChanged(XContentBuilder mapping public void testConflictFieldsMapping(String fieldName) throws Exception { //test store, ... all the parameters that are not to be changed just like in other fields - XContentBuilder mapping = XContentFactory.jsonBuilder().startObject().startObject("type") - .startObject(fieldName).field("enabled", true).field("store", "no").endObject() - .endObject().endObject(); - XContentBuilder mappingUpdate = XContentFactory.jsonBuilder().startObject().startObject("type") - .startObject(fieldName).field("enabled", true).field("store", "yes").endObject() - .startObject("properties").startObject("text").field("type", "text").endObject().endObject() - .endObject().endObject(); + XContentBuilder mapping = XContentFactory.jsonBuilder() + .startObject() + .startObject("type") + .startObject(fieldName) + .field("enabled", true) + .field("store", false) + .endObject() + .endObject() + .endObject(); + XContentBuilder mappingUpdate = XContentFactory.jsonBuilder() + .startObject() + .startObject("type") + .startObject(fieldName) + .field("enabled", true) + .field("store", true) + .endObject() + .startObject("properties") + .startObject("text") + .field("type", "text") + .endObject() + .endObject() + .endObject() + .endObject(); testConflictWhileMergingAndMappingUnchanged(mapping, mappingUpdate); } diff --git a/core/src/test/java/org/elasticsearch/index/query/HasChildQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/HasChildQueryBuilderTests.java index ac5c93604d8ee..032ebc392cbcb 100644 --- a/core/src/test/java/org/elasticsearch/index/query/HasChildQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/HasChildQueryBuilderTests.java @@ -31,7 +31,9 @@ import org.apache.lucene.search.similarities.PerFieldSimilarityWrapper; import org.apache.lucene.search.similarities.Similarity; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.Version; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; +import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.common.compress.CompressedXContent; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.mapper.MapperService; @@ -273,7 +275,9 @@ public void testNonDefaultSimilarity() throws Exception { QueryShardContext shardContext = createShardContext(); HasChildQueryBuilder hasChildQueryBuilder = QueryBuilders.hasChildQuery(CHILD_TYPE, new TermQueryBuilder("custom_string", "value"), ScoreMode.None); HasChildQueryBuilder.LateParsingQuery query = (HasChildQueryBuilder.LateParsingQuery) hasChildQueryBuilder.toQuery(shardContext); - Similarity expected = SimilarityService.BUILT_IN.get(similarity).apply(similarity, Settings.EMPTY).get(); + Similarity expected = SimilarityService.BUILT_IN.get(similarity) + .apply(similarity, Settings.EMPTY, Settings.builder().put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT).build()) + .get(); assertThat(((PerFieldSimilarityWrapper) query.getSimilarity()).get("custom_string"), instanceOf(expected.getClass())); } diff --git a/core/src/test/java/org/elasticsearch/indices/analysis/AnalysisModuleTests.java b/core/src/test/java/org/elasticsearch/indices/analysis/AnalysisModuleTests.java index b568ae9276d43..012fae17f5c8d 100644 --- a/core/src/test/java/org/elasticsearch/indices/analysis/AnalysisModuleTests.java +++ b/core/src/test/java/org/elasticsearch/indices/analysis/AnalysisModuleTests.java @@ -306,7 +306,7 @@ private void testSimpleConfiguration(Settings settings) throws IOException { // assertThat(dictionaryDecompounderAnalyze.tokenFilters().length, equalTo(1)); // assertThat(dictionaryDecompounderAnalyze.tokenFilters()[0], instanceOf(DictionaryCompoundWordTokenFilterFactory.class)); - Set wordList = Analysis.getWordSet(null, settings, "index.analysis.filter.dict_dec.word_list"); + Set wordList = Analysis.getWordSet(null, Version.CURRENT, settings, "index.analysis.filter.dict_dec.word_list"); MatcherAssert.assertThat(wordList.size(), equalTo(6)); // MatcherAssert.assertThat(wordList, hasItems("donau", "dampf", "schiff", "spargel", "creme", "suppe")); } @@ -321,7 +321,7 @@ public void testWordListPath() throws Exception { Path wordListFile = generateWordList(words); settings = Settings.builder().loadFromSource("index: \n word_list_path: " + wordListFile.toAbsolutePath()).build(); - Set wordList = Analysis.getWordSet(env, settings, "index.word_list"); + Set wordList = Analysis.getWordSet(env, Version.CURRENT, settings, "index.word_list"); MatcherAssert.assertThat(wordList.size(), equalTo(6)); // MatcherAssert.assertThat(wordList, hasItems(words)); Files.delete(wordListFile); diff --git a/core/src/test/java/org/elasticsearch/indices/template/SimpleIndexTemplateIT.java b/core/src/test/java/org/elasticsearch/indices/template/SimpleIndexTemplateIT.java index 521446583c878..6469b660f0b98 100644 --- a/core/src/test/java/org/elasticsearch/indices/template/SimpleIndexTemplateIT.java +++ b/core/src/test/java/org/elasticsearch/indices/template/SimpleIndexTemplateIT.java @@ -154,18 +154,37 @@ public void testDeleteIndexTemplate() throws Exception { client().admin().indices().preparePutTemplate("template_1") .setPatterns(Collections.singletonList("te*")) .setOrder(0) - .addMapping("type1", XContentFactory.jsonBuilder().startObject().startObject("type1").startObject("properties") - .startObject("field1").field("type", "text").field("store", true).endObject() - .startObject("field2").field("type", "text").field("store", true).endObject() - .endObject().endObject().endObject()) + .addMapping("type1", XContentFactory.jsonBuilder() + .startObject() + .startObject("type1") + .startObject("properties") + .startObject("field1") + .field("type", "text") + .field("store", true) + .endObject() + .startObject("field2") + .field("type", "text") + .field("store", true) + .endObject() + .endObject() + .endObject() + .endObject()) .execute().actionGet(); client().admin().indices().preparePutTemplate("template_2") .setPatterns(Collections.singletonList("test*")) .setOrder(1) - .addMapping("type1", XContentFactory.jsonBuilder().startObject().startObject("type1").startObject("properties") - .startObject("field2").field("type", "text").field("store", "no").endObject() - .endObject().endObject().endObject()) + .addMapping("type1", XContentFactory.jsonBuilder() + .startObject() + .startObject("type1") + .startObject("properties") + .startObject("field2") + .field("type", "text") + .field("store", false) + .endObject() + .endObject() + .endObject() + .endObject()) .execute().actionGet(); logger.info("--> explicitly delete template_1"); diff --git a/core/src/test/java/org/elasticsearch/rest/BaseRestHandlerTests.java b/core/src/test/java/org/elasticsearch/rest/BaseRestHandlerTests.java index 3e3d310b33ce4..80ee4dd6d0de8 100644 --- a/core/src/test/java/org/elasticsearch/rest/BaseRestHandlerTests.java +++ b/core/src/test/java/org/elasticsearch/rest/BaseRestHandlerTests.java @@ -160,8 +160,8 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli final HashMap params = new HashMap<>(); params.put("format", randomAsciiOfLength(8)); params.put("filter_path", randomAsciiOfLength(8)); - params.put("pretty", randomAsciiOfLength(8)); - params.put("human", randomAsciiOfLength(8)); + params.put("pretty", randomFrom("true", "false", "", null)); + params.put("human", null); RestRequest request = new FakeRestRequest.Builder(xContentRegistry()).withParams(params).build(); RestChannel channel = new FakeRestChannel(request, randomBoolean(), 1); handler.handleRequest(request, channel, mock(NodeClient.class)); diff --git a/core/src/test/java/org/elasticsearch/rest/action/cat/RestTableTests.java b/core/src/test/java/org/elasticsearch/rest/action/cat/RestTableTests.java index cf42f2b1b3c0a..38ed76cae5249 100644 --- a/core/src/test/java/org/elasticsearch/rest/action/cat/RestTableTests.java +++ b/core/src/test/java/org/elasticsearch/rest/action/cat/RestTableTests.java @@ -139,7 +139,7 @@ public void testIgnoreContentType() throws Exception { public void testThatDisplayHeadersWithoutTimestamp() throws Exception { restRequest.params().put("h", "timestamp,epoch,bulk*"); - restRequest.params().put("ts", "0"); + restRequest.params().put("ts", "false"); List headers = buildDisplayHeaders(table, restRequest); List headerNames = getHeaderNames(headers); diff --git a/core/src/test/java/org/elasticsearch/script/ScriptContextTests.java b/core/src/test/java/org/elasticsearch/script/ScriptContextTests.java index 9578e0c628155..d961fd677aa0a 100644 --- a/core/src/test/java/org/elasticsearch/script/ScriptContextTests.java +++ b/core/src/test/java/org/elasticsearch/script/ScriptContextTests.java @@ -37,7 +37,7 @@ ScriptService makeScriptService() throws Exception { Settings settings = Settings.builder() .put(Environment.PATH_HOME_SETTING.getKey(), createTempDir()) // no file watching, so we don't need a ResourceWatcherService - .put(ScriptService.SCRIPT_AUTO_RELOAD_ENABLED_SETTING.getKey(), "off") + .put(ScriptService.SCRIPT_AUTO_RELOAD_ENABLED_SETTING.getKey(), "false") .put("script." + PLUGIN_NAME + "_custom_globally_disabled_op", "false") .put("script.engine." + MockScriptEngine.NAME + ".inline." + PLUGIN_NAME + "_custom_exp_disabled_op", "false") .build(); diff --git a/core/src/test/java/org/elasticsearch/snapshots/SharedClusterSnapshotRestoreIT.java b/core/src/test/java/org/elasticsearch/snapshots/SharedClusterSnapshotRestoreIT.java index ef6275e2ccd8f..acc896708250d 100644 --- a/core/src/test/java/org/elasticsearch/snapshots/SharedClusterSnapshotRestoreIT.java +++ b/core/src/test/java/org/elasticsearch/snapshots/SharedClusterSnapshotRestoreIT.java @@ -445,10 +445,25 @@ public void testRestoreTemplates() throws Exception { .setType("fs").setSettings(Settings.builder().put("location", randomRepoPath()))); logger.info("--> creating test template"); - assertThat(client.admin().indices().preparePutTemplate("test-template").setPatterns(Collections.singletonList("te*")).addMapping("test-mapping", XContentFactory.jsonBuilder().startObject().startObject("test-mapping").startObject("properties") - .startObject("field1").field("type", "text").field("store", "yes").endObject() - .startObject("field2").field("type", "keyword").field("store", "yes").endObject() - .endObject().endObject().endObject()).get().isAcknowledged(), equalTo(true)); + assertThat(client.admin().indices() + .preparePutTemplate("test-template") + .setPatterns(Collections.singletonList("te*")) + .addMapping("test-mapping", XContentFactory.jsonBuilder() + .startObject() + .startObject("test-mapping") + .startObject("properties") + .startObject("field1") + .field("type", "text") + .field("store", true) + .endObject() + .startObject("field2") + .field("type", "keyword") + .field("store", true) + .endObject() + .endObject() + .endObject() + .endObject()) + .get().isAcknowledged(), equalTo(true)); logger.info("--> snapshot"); CreateSnapshotResponse createSnapshotResponse = client.admin().cluster().prepareCreateSnapshot("test-repo", "test-snap").setIndices().setWaitForCompletion(true).get(); @@ -486,10 +501,25 @@ public void testIncludeGlobalState() throws Exception { if(testTemplate) { logger.info("--> creating test template"); - assertThat(client.admin().indices().preparePutTemplate("test-template").setPatterns(Collections.singletonList("te*")).addMapping("test-mapping", XContentFactory.jsonBuilder().startObject().startObject("test-mapping").startObject("properties") - .startObject("field1").field("type", "text").field("store", "yes").endObject() - .startObject("field2").field("type", "keyword").field("store", "yes").endObject() - .endObject().endObject().endObject()).get().isAcknowledged(), equalTo(true)); + assertThat(client.admin().indices() + .preparePutTemplate("test-template") + .setPatterns(Collections.singletonList("te*")) + .addMapping("test-mapping", XContentFactory.jsonBuilder() + .startObject() + .startObject("test-mapping") + .startObject("properties") + .startObject("field1") + .field("type", "text") + .field("store", true) + .endObject() + .startObject("field2") + .field("type", "keyword") + .field("store", true) + .endObject() + .endObject() + .endObject() + .endObject()) + .get().isAcknowledged(), equalTo(true)); } if(testPipeline) { diff --git a/core/src/test/resources/indices/bwc/index-5.1.1.zip b/core/src/test/resources/indices/bwc/index-5.1.1.zip index ab13e00b66e46..49e89e6ccd3bc 100644 Binary files a/core/src/test/resources/indices/bwc/index-5.1.1.zip and b/core/src/test/resources/indices/bwc/index-5.1.1.zip differ diff --git a/core/src/test/resources/indices/bwc/repo-5.1.1.zip b/core/src/test/resources/indices/bwc/repo-5.1.1.zip index 01a9645e55ec7..9fef3e730a79d 100644 Binary files a/core/src/test/resources/indices/bwc/repo-5.1.1.zip and b/core/src/test/resources/indices/bwc/repo-5.1.1.zip differ diff --git a/dev-tools/create_bwc_index.py b/dev-tools/create_bwc_index.py index a6814e52f8fe9..4703759e1234f 100644 --- a/dev-tools/create_bwc_index.py +++ b/dev-tools/create_bwc_index.py @@ -48,6 +48,28 @@ def rarely(): def frequently(): return not rarely() +def capabilities_of(version): + current_version = parse_version(version) + + return { + 'warmers': current_version < parse_version('2.0.0-alpha1'), + 'dots_in_field_names': current_version >= parse_version('2.4.0'), + 'lenient_booleans': current_version < parse_version('6.0.0-alpha1') + } + + +def falsy(lenient): + return random.choice(['off', 'no', '0', 0, 'false', False]) if lenient else False + + +def truthy(lenient): + return random.choice(['on', 'yes', '1', 1, 'true', True]) if lenient else True + + +def random_bool(lenient): + return random.choice([falsy, truthy])(lenient) + + # asserts the correctness of the given hits given they are sorted asc def assert_sort(hits): values = [hit['sort'] for hit in hits['hits']['hits']] @@ -59,19 +81,23 @@ def assert_sort(hits): # Indexes the given number of document into the given index # and randomly runs refresh, optimize and flush commands -def index_documents(es, index_name, type, num_docs, supports_dots_in_field_names): +def index_documents(es, index_name, type, num_docs, capabilities): logging.info('Indexing %s docs' % num_docs) - index(es, index_name, type, num_docs, supports_dots_in_field_names, True) + index(es, index_name, type, num_docs, capabilities, flush=True) logging.info('Flushing index') es.indices.flush(index=index_name) -def index(es, index_name, type, num_docs, supports_dots_in_field_names, flush=False): +def index(es, index_name, type, num_docs, capabilities, flush=False): for id in range(0, num_docs): - body = {'string': str(random.randint(0, 100)), - 'long_sort': random.randint(0, 100), - 'double_sort' : float(random.randint(0, 100)), - 'bool' : random.choice([True, False])} - if supports_dots_in_field_names: + lenient_bool = capabilities['lenient_booleans'] + body = { + 'string': str(random.randint(0, 100)), + 'long_sort': random.randint(0, 100), + 'double_sort': float(random.randint(0, 100)), + # be sure to create a "proper" boolean (True, False) for the first document so that automapping is correct + 'bool': random_bool(lenient_bool) if id > 0 else random.choice([True, False]) + } + if capabilities['dots_in_field_names']: body['field.with.dots'] = str(random.randint(0, 100)) body['binary'] = base64.b64encode(bytearray(random.getrandbits(8) for _ in range(16))).decode('ascii') @@ -83,10 +109,14 @@ def index(es, index_name, type, num_docs, supports_dots_in_field_names, flush=Fa if rarely() and flush: es.indices.flush(index=index_name, force=frequently()) -def reindex_docs(es, index_name, type, num_docs, supports_dots_in_field_names): +def reindex_docs(es, index_name, type, num_docs, capabilities): logging.info('Re-indexing %s docs' % num_docs) + # TODO: Translog recovery fails on mixed representation of booleans as strings / booleans (e.g. "true", true) + # (see gradle :core:test -Dtests.seed=AF7BB7B3FA387AAE -Dtests.class=org.elasticsearch.index.engine.InternalEngineTests + # -Dtests.method="testUpgradeOldIndex") + capabilities['lenient_booleans'] = False # reindex some docs after the flush such that we have something in the translog - index(es, index_name, type, num_docs, supports_dots_in_field_names) + index(es, index_name, type, num_docs, capabilities) def delete_by_query(es, version, index_name, doc_type): @@ -200,9 +230,12 @@ def generate_index(client, version, index_name): client.indices.delete(index=index_name, ignore=404) logging.info('Create single shard test index') + capabilities = capabilities_of(version) + lenient_booleans = capabilities['lenient_booleans'] + mappings = {} warmers = {} - if parse_version(version) < parse_version('2.0.0-alpha1'): + if capabilities['warmers']: warmers['warmer1'] = { 'source': { 'query': { @@ -249,7 +282,7 @@ def generate_index(client, version, index_name): } mappings['meta_fields'] = { '_routing': { - 'required': 'false' + 'required': falsy(lenient_booleans) }, } mappings['custom_formats'] = { @@ -266,13 +299,12 @@ def generate_index(client, version, index_name): } mappings['auto_boost'] = { '_all': { - 'auto_boost': True + 'auto_boost': truthy(lenient_booleans) } } mappings['doc'] = {'properties' : {}} - supports_dots_in_field_names = parse_version(version) >= parse_version("2.4.0") - if supports_dots_in_field_names: + if capabilities['dots_in_field_names']: if parse_version(version) < parse_version("5.0.0-alpha1"): mappings["doc"]['properties'].update({ 'field.with.dots': { @@ -320,7 +352,7 @@ def generate_index(client, version, index_name): 'properties': { 'string_with_norms_disabled': { 'type': 'text', - 'norms' : False + 'norms': False }, 'string_with_norms_enabled': { 'type': 'keyword', @@ -340,7 +372,7 @@ def generate_index(client, version, index_name): # test back-compat of stored binary fields mappings['doc']['properties']['binary'] = { 'type': 'binary', - 'store': True, + 'store': truthy(lenient_booleans), } settings = { @@ -372,13 +404,13 @@ def generate_index(client, version, index_name): # lighter index for it to keep bw tests reasonable # see https://github.com/elastic/elasticsearch/issues/5817 num_docs = int(num_docs / 10) - index_documents(client, index_name, 'doc', num_docs, supports_dots_in_field_names) + index_documents(client, index_name, 'doc', num_docs, capabilities) if parse_version(version) < parse_version('5.1.0'): logging.info("Adding a alias that can't be created in 5.1+ so we can assert that we can still use it") client.indices.put_alias(index=index_name, name='#' + index_name) logging.info('Running basic asserts on the data added') run_basic_asserts(client, version, index_name, 'doc', num_docs) - return num_docs, supports_dots_in_field_names + return num_docs, capabilities def snapshot_index(client, version, repo_dir): persistent = { @@ -400,7 +432,9 @@ def snapshot_index(client, version, repo_dir): }, "mappings": { "type1": { - "_source": { "enabled" : False } + "_source": { + "enabled": falsy(capabilities_of(version)['lenient_booleans']) + } } }, "aliases": { @@ -488,7 +522,7 @@ def create_bwc_index(cfg, version): node = start_node(version, release_dir, data_dir, repo_dir, cfg.tcp_port, cfg.http_port) client = create_client(cfg.http_port) index_name = 'index-%s' % version.lower() - num_docs, supports_dots_in_field_names = generate_index(client, version, index_name) + num_docs, capabilities = generate_index(client, version, index_name) if snapshot_supported: snapshot_index(client, version, repo_dir) @@ -497,7 +531,7 @@ def create_bwc_index(cfg, version): # will already have the deletions applied on upgrade. if version.startswith('0.') or version.startswith('1.'): delete_by_query(client, version, index_name, 'doc') - reindex_docs(client, index_name, 'doc', min(100, num_docs), supports_dots_in_field_names) + reindex_docs(client, index_name, 'doc', min(100, num_docs), capabilities) shutdown_node(node) node = None diff --git a/docs/reference/analysis/tokenfilters/pattern-capture-tokenfilter.asciidoc b/docs/reference/analysis/tokenfilters/pattern-capture-tokenfilter.asciidoc index ccde46a3fd2ad..b233081d54049 100644 --- a/docs/reference/analysis/tokenfilters/pattern-capture-tokenfilter.asciidoc +++ b/docs/reference/analysis/tokenfilters/pattern-capture-tokenfilter.asciidoc @@ -53,7 +53,7 @@ curl -XPUT localhost:9200/test/ -d ' "filter" : { "code" : { "type" : "pattern_capture", - "preserve_original" : 1, + "preserve_original" : true, "patterns" : [ "(\\p{Ll}+|\\p{Lu}\\p{Ll}+|\\p{Lu}+)", "(\\d+)" @@ -94,7 +94,7 @@ curl -XPUT localhost:9200/test/ -d ' "filter" : { "email" : { "type" : "pattern_capture", - "preserve_original" : 1, + "preserve_original" : true, "patterns" : [ "([^@]+)", "(\\p{L}+)", diff --git a/docs/reference/api-conventions.asciidoc b/docs/reference/api-conventions.asciidoc index efec2efe1a4a0..712a7969a0517 100644 --- a/docs/reference/api-conventions.asciidoc +++ b/docs/reference/api-conventions.asciidoc @@ -476,9 +476,8 @@ convention of using underscore casing. === Boolean Values All REST APIs parameters (both request parameters and JSON body) support -providing boolean "false" as the values: `false`, `0`, `no` and `off`. -All other values are considered "true". Note, this is not related to -fields within a document indexed treated as boolean fields. +providing boolean "false" as the value `false` and boolean "true" as the +value `true`. All other values will raise an error. [float] === Number Values diff --git a/docs/reference/cat/health.asciidoc b/docs/reference/cat/health.asciidoc index cca24c66a3612..a87fe4e5e4a6a 100644 --- a/docs/reference/cat/health.asciidoc +++ b/docs/reference/cat/health.asciidoc @@ -22,7 +22,7 @@ It has one option `ts` to disable the timestamping: [source,js] -------------------------------------------------- -GET /_cat/health?v&ts=0 +GET /_cat/health?v&ts=false -------------------------------------------------- // CONSOLE // TEST[s/^/PUT twitter\n{"settings":{"number_of_replicas": 0}}\n/] diff --git a/docs/reference/mapping/types/boolean.asciidoc b/docs/reference/mapping/types/boolean.asciidoc index d273dddb27ddd..5f521922655c5 100644 --- a/docs/reference/mapping/types/boolean.asciidoc +++ b/docs/reference/mapping/types/boolean.asciidoc @@ -2,16 +2,16 @@ === Boolean datatype Boolean fields accept JSON `true` and `false` values, but can also accept -strings and numbers which are interpreted as either true or false: +strings which are interpreted as either true or false: [horizontal] False values:: - `false`, `"false"`, `"off"`, `"no"`, `"0"`, `""` (empty string), `0`, `0.0` + `false`, `"false"` True values:: - Anything that isn't false. + `true`, `"true"` For example: @@ -32,7 +32,7 @@ PUT my_index POST my_index/my_type/1 { - "is_published": 1 <1> + "is_published": "true" <1> } GET my_index/_search @@ -45,7 +45,7 @@ GET my_index/_search } -------------------------------------------------- // CONSOLE -<1> Indexing a document with `1`, which is interpreted as `true`. +<1> Indexing a document with `"true"`, which is interpreted as `true`. <2> Searching for documents with a JSON `true`. Aggregations like the < stopWords = Analysis.parseStopWords(env, settings, JapaneseAnalyzer.getDefaultStopSet()); + final Set stopWords = Analysis.parseStopWords( + env, indexSettings.getIndexVersionCreated(), settings, JapaneseAnalyzer.getDefaultStopSet()); final JapaneseTokenizer.Mode mode = KuromojiTokenizerFactory.getMode(settings); final UserDictionary userDictionary = KuromojiTokenizerFactory.getUserDictionary(env, settings); analyzer = new JapaneseAnalyzer(userDictionary, mode, CharArraySet.copy(stopWords), JapaneseAnalyzer.getDefaultStopTags()); diff --git a/plugins/analysis-kuromoji/src/main/java/org/elasticsearch/index/analysis/KuromojiIterationMarkCharFilterFactory.java b/plugins/analysis-kuromoji/src/main/java/org/elasticsearch/index/analysis/KuromojiIterationMarkCharFilterFactory.java index 836dbbdfae219..21387f1982d2f 100644 --- a/plugins/analysis-kuromoji/src/main/java/org/elasticsearch/index/analysis/KuromojiIterationMarkCharFilterFactory.java +++ b/plugins/analysis-kuromoji/src/main/java/org/elasticsearch/index/analysis/KuromojiIterationMarkCharFilterFactory.java @@ -33,8 +33,10 @@ public class KuromojiIterationMarkCharFilterFactory extends AbstractCharFilterFa public KuromojiIterationMarkCharFilterFactory(IndexSettings indexSettings, Environment env, String name, Settings settings) { super(indexSettings, name); - normalizeKanji = settings.getAsBoolean("normalize_kanji", JapaneseIterationMarkCharFilter.NORMALIZE_KANJI_DEFAULT); - normalizeKana = settings.getAsBoolean("normalize_kana", JapaneseIterationMarkCharFilter.NORMALIZE_KANA_DEFAULT); + normalizeKanji = settings.getAsBooleanLenientForPreEs6Indices(indexSettings.getIndexVersionCreated(), "normalize_kanji", + JapaneseIterationMarkCharFilter.NORMALIZE_KANJI_DEFAULT); + normalizeKana = settings.getAsBooleanLenientForPreEs6Indices(indexSettings.getIndexVersionCreated(), "normalize_kana", + JapaneseIterationMarkCharFilter.NORMALIZE_KANA_DEFAULT); } @Override diff --git a/plugins/analysis-kuromoji/src/main/java/org/elasticsearch/index/analysis/KuromojiReadingFormFilterFactory.java b/plugins/analysis-kuromoji/src/main/java/org/elasticsearch/index/analysis/KuromojiReadingFormFilterFactory.java index d0eb0cecdb93a..ae9247db9c6b0 100644 --- a/plugins/analysis-kuromoji/src/main/java/org/elasticsearch/index/analysis/KuromojiReadingFormFilterFactory.java +++ b/plugins/analysis-kuromoji/src/main/java/org/elasticsearch/index/analysis/KuromojiReadingFormFilterFactory.java @@ -31,7 +31,7 @@ public class KuromojiReadingFormFilterFactory extends AbstractTokenFilterFactory public KuromojiReadingFormFilterFactory(IndexSettings indexSettings, Environment environment, String name, Settings settings) { super(indexSettings, name, settings); - useRomaji = settings.getAsBoolean("use_romaji", false); + useRomaji = settings.getAsBooleanLenientForPreEs6Indices(indexSettings.getIndexVersionCreated(), "use_romaji", false); } @Override diff --git a/plugins/analysis-kuromoji/src/main/java/org/elasticsearch/index/analysis/KuromojiTokenizerFactory.java b/plugins/analysis-kuromoji/src/main/java/org/elasticsearch/index/analysis/KuromojiTokenizerFactory.java index 2f00e68a75ebc..39dfc4ccc0798 100644 --- a/plugins/analysis-kuromoji/src/main/java/org/elasticsearch/index/analysis/KuromojiTokenizerFactory.java +++ b/plugins/analysis-kuromoji/src/main/java/org/elasticsearch/index/analysis/KuromojiTokenizerFactory.java @@ -48,7 +48,8 @@ public KuromojiTokenizerFactory(IndexSettings indexSettings, Environment env, St super(indexSettings, name, settings); mode = getMode(settings); userDictionary = getUserDictionary(env, settings); - discartPunctuation = settings.getAsBoolean("discard_punctuation", true); + discartPunctuation = settings + .getAsBooleanLenientForPreEs6Indices(indexSettings.getIndexVersionCreated(), "discard_punctuation", true); nBestCost = settings.getAsInt(NBEST_COST, -1); nBestExamples = settings.get(NBEST_EXAMPLES); } diff --git a/plugins/analysis-phonetic/src/main/java/org/elasticsearch/index/analysis/PhoneticTokenFilterFactory.java b/plugins/analysis-phonetic/src/main/java/org/elasticsearch/index/analysis/PhoneticTokenFilterFactory.java index ff4ab4943e30f..93f68000ad228 100644 --- a/plugins/analysis-phonetic/src/main/java/org/elasticsearch/index/analysis/PhoneticTokenFilterFactory.java +++ b/plugins/analysis-phonetic/src/main/java/org/elasticsearch/index/analysis/PhoneticTokenFilterFactory.java @@ -60,7 +60,7 @@ public PhoneticTokenFilterFactory(IndexSettings indexSettings, Environment envir this.nametype = null; this.ruletype = null; this.maxcodelength = 0; - this.replace = settings.getAsBoolean("replace", true); + this.replace = settings.getAsBooleanLenientForPreEs6Indices(indexSettings.getIndexVersionCreated(), "replace", true); // weird, encoder is null at last step in SimplePhoneticAnalysisTests, so we set it to metaphone as default String encodername = settings.get("encoder", "metaphone"); if ("metaphone".equalsIgnoreCase(encodername)) { diff --git a/plugins/analysis-ukrainian/src/main/java/org/elasticsearch/index/analysis/UkrainianAnalyzerProvider.java b/plugins/analysis-ukrainian/src/main/java/org/elasticsearch/index/analysis/UkrainianAnalyzerProvider.java index 45bf27b954bff..0a00b752b9978 100644 --- a/plugins/analysis-ukrainian/src/main/java/org/elasticsearch/index/analysis/UkrainianAnalyzerProvider.java +++ b/plugins/analysis-ukrainian/src/main/java/org/elasticsearch/index/analysis/UkrainianAnalyzerProvider.java @@ -24,8 +24,6 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; import org.elasticsearch.index.IndexSettings; -import org.elasticsearch.index.analysis.AbstractIndexAnalyzerProvider; -import org.elasticsearch.index.analysis.Analysis; public class UkrainianAnalyzerProvider extends AbstractIndexAnalyzerProvider { @@ -33,8 +31,10 @@ public class UkrainianAnalyzerProvider extends AbstractIndexAnalyzerProvider