diff --git a/core/src/main/java/org/elasticsearch/common/property/PropertyPlaceholder.java b/core/src/main/java/org/elasticsearch/common/property/PropertyPlaceholder.java index 5b4515f7b96..a4b067e1cea 100644 --- a/core/src/main/java/org/elasticsearch/common/property/PropertyPlaceholder.java +++ b/core/src/main/java/org/elasticsearch/common/property/PropertyPlaceholder.java @@ -109,7 +109,11 @@ public class PropertyPlaceholder { propVal = defaultValue; } if (propVal == null && placeholderResolver.shouldIgnoreMissing(placeholder)) { - propVal = ""; + if (placeholderResolver.shouldRemoveMissingPlaceholder(placeholder)) { + propVal = ""; + } else { + return strVal; + } } if (propVal != null) { // Recursive invocation, parsing placeholders contained in the @@ -170,5 +174,13 @@ public class PropertyPlaceholder { String resolvePlaceholder(String placeholderName); boolean shouldIgnoreMissing(String placeholderName); + + /** + * Allows for special handling for ignored missing placeholders that may be resolved elsewhere + * + * @param placeholderName the name of the placeholder to resolve. + * @return true if the placeholder should be replaced with a empty string + */ + boolean shouldRemoveMissingPlaceholder(String placeholderName); } } 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 a5929d5fa90..24743afe980 100644 --- a/core/src/main/java/org/elasticsearch/common/settings/Settings.java +++ b/core/src/main/java/org/elasticsearch/common/settings/Settings.java @@ -1245,7 +1245,7 @@ public final class Settings implements ToXContent { * tries and resolve it against an environment variable ({@link System#getenv(String)}), and last, tries * and replace it with another setting already set on this builder. */ - public Builder replacePropertyPlaceholders(String... ignoredValues) { + public Builder replacePropertyPlaceholders() { PropertyPlaceholder propertyPlaceholder = new PropertyPlaceholder("${", "}", false); PropertyPlaceholder.PlaceholderResolver placeholderResolver = new PropertyPlaceholder.PlaceholderResolver() { @Override @@ -1268,26 +1268,22 @@ public final class Settings implements ToXContent { @Override public boolean shouldIgnoreMissing(String placeholderName) { // if its an explicit env var, we are ok with not having a value for it and treat it as optional - if (placeholderName.startsWith("env.")) { + if (placeholderName.startsWith("env.") || placeholderName.startsWith("prompt.")) { return true; } return false; } + + @Override + public boolean shouldRemoveMissingPlaceholder(String placeholderName) { + if (placeholderName.startsWith("prompt.")) { + return false; + } + return true; + } }; for (Map.Entry entry : Maps.newHashMap(map).entrySet()) { - String possiblePlaceholder = entry.getValue(); - boolean ignored = false; - for (String ignoredValue : ignoredValues) { - if (ignoredValue.equals(possiblePlaceholder)) { - ignored = true; - break; - } - } - if (ignored) { - continue; - } - - String value = propertyPlaceholder.replacePlaceholders(possiblePlaceholder, placeholderResolver); + String value = propertyPlaceholder.replacePlaceholders(entry.getValue(), placeholderResolver); // if the values exists and has length, we should maintain it in the map // otherwise, the replace process resolved into removing it if (Strings.hasLength(value)) { diff --git a/core/src/main/java/org/elasticsearch/index/query/IndexQueryParserModule.java b/core/src/main/java/org/elasticsearch/index/query/IndexQueryParserModule.java deleted file mode 100644 index 0953b4f04a6..00000000000 --- a/core/src/main/java/org/elasticsearch/index/query/IndexQueryParserModule.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * 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.index.query; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import org.elasticsearch.common.inject.AbstractModule; -import org.elasticsearch.common.inject.Scopes; -import org.elasticsearch.common.inject.assistedinject.FactoryProvider; -import org.elasticsearch.common.inject.multibindings.MapBinder; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.index.query.support.InnerHitsQueryParserHelper; - -import java.util.LinkedList; -import java.util.Map; - -/** - * - */ -public class IndexQueryParserModule extends AbstractModule { - - /** - * A custom processor that can be extended to process and bind custom implementations of - * {@link QueryParserFactory}, and {@link FilterParser}. - */ - public static class QueryParsersProcessor { - - /** - * Extension point to bind a custom {@link QueryParserFactory}. - */ - public void processXContentQueryParsers(XContentQueryParsersBindings bindings) { - - } - - public static class XContentQueryParsersBindings { - - private final MapBinder binder; - private final Map groupSettings; - - public XContentQueryParsersBindings(MapBinder binder, Map groupSettings) { - this.binder = binder; - this.groupSettings = groupSettings; - } - - public MapBinder binder() { - return binder; - } - - public Map groupSettings() { - return groupSettings; - } - - public void processXContentQueryParser(String name, Class xcontentQueryParser) { - if (!groupSettings.containsKey(name)) { - binder.addBinding(name).toProvider(FactoryProvider.newFactory(QueryParserFactory.class, xcontentQueryParser)).in(Scopes.SINGLETON); - } - } - } - - } - - private final Settings settings; - - private final LinkedList processors = Lists.newLinkedList(); - - private final Map> queries = Maps.newHashMap(); - - public IndexQueryParserModule(Settings settings) { - this.settings = settings; - } - - /** - * Adds a custom query parser. - * - * @param name The name of the query parser - * @param queryParser the class of the query parser - */ - public void addQueryParser(String name, Class queryParser) { - queries.put(name, queryParser); - } - - public IndexQueryParserModule addProcessor(QueryParsersProcessor processor) { - processors.addFirst(processor); - return this; - } - - @Override - protected void configure() { - - bind(IndexQueryParserService.class).asEagerSingleton(); - bind(InnerHitsQueryParserHelper.class).asEagerSingleton(); - - // handle XContenQueryParsers - MapBinder queryBinder - = MapBinder.newMapBinder(binder(), String.class, QueryParserFactory.class); - Map xContentQueryParserGroups = settings.getGroups(IndexQueryParserService.Defaults.QUERY_PREFIX); - for (Map.Entry entry : xContentQueryParserGroups.entrySet()) { - String qName = entry.getKey(); - Settings qSettings = entry.getValue(); - Class type = qSettings.getAsClass("type", null); - if (type == null) { - throw new IllegalArgumentException("Query Parser [" + qName + "] must be provided with a type"); - } - queryBinder.addBinding(qName).toProvider(FactoryProvider.newFactory(QueryParserFactory.class, - qSettings.getAsClass("type", null))).in(Scopes.SINGLETON); - } - - QueryParsersProcessor.XContentQueryParsersBindings xContentQueryParsersBindings = new QueryParsersProcessor.XContentQueryParsersBindings(queryBinder, xContentQueryParserGroups); - for (QueryParsersProcessor processor : processors) { - processor.processXContentQueryParsers(xContentQueryParsersBindings); - } - - for (Map.Entry> entry : queries.entrySet()) { - queryBinder.addBinding(entry.getKey()).toProvider(FactoryProvider.newFactory(QueryParserFactory.class, entry.getValue())).in(Scopes.SINGLETON); - } - } -} diff --git a/core/src/main/java/org/elasticsearch/index/query/IndexQueryParserService.java b/core/src/main/java/org/elasticsearch/index/query/IndexQueryParserService.java index a3684d379e6..5e0caccbe79 100644 --- a/core/src/main/java/org/elasticsearch/index/query/IndexQueryParserService.java +++ b/core/src/main/java/org/elasticsearch/index/query/IndexQueryParserService.java @@ -19,8 +19,6 @@ package org.elasticsearch.index.query; -import com.google.common.collect.ImmutableMap; - import org.apache.lucene.search.Query; import org.apache.lucene.util.CloseableThreadLocal; import org.elasticsearch.Version; @@ -48,23 +46,12 @@ import org.elasticsearch.script.ScriptService; import java.io.IOException; import java.util.EnumSet; -import java.util.List; -import java.util.Map; - -import static com.google.common.collect.Lists.newArrayList; -import static com.google.common.collect.Maps.newHashMap; -import static org.elasticsearch.common.settings.Settings.Builder.EMPTY_SETTINGS; /** * */ public class IndexQueryParserService extends AbstractIndexComponent { - public static final class Defaults { - public static final String QUERY_PREFIX = "index.queryparser.query"; - public static final String FILTER_PREFIX = "index.queryparser.filter"; - } - public static final String DEFAULT_FIELD = "index.query.default_field"; public static final String QUERY_STRING_LENIENT = "index.query_string.lenient"; public static final String PARSE_STRICT = "index.query.parse.strict"; @@ -91,7 +78,7 @@ public class IndexQueryParserService extends AbstractIndexComponent { final BitsetFilterCache bitsetFilterCache; - private final Map queryParsers; + private final IndicesQueriesRegistry indicesQueriesRegistry; private String defaultField; private boolean queryStringLenient; @@ -104,8 +91,7 @@ public class IndexQueryParserService extends AbstractIndexComponent { ScriptService scriptService, AnalysisService analysisService, MapperService mapperService, IndexCache indexCache, IndexFieldDataService fieldDataService, BitsetFilterCache bitsetFilterCache, - @Nullable SimilarityService similarityService, - @Nullable Map namedQueryParsers) { + @Nullable SimilarityService similarityService) { super(index, indexSettings); this.scriptService = scriptService; this.analysisService = analysisService; @@ -119,29 +105,7 @@ public class IndexQueryParserService extends AbstractIndexComponent { this.queryStringLenient = indexSettings.getAsBoolean(QUERY_STRING_LENIENT, false); this.strict = indexSettings.getAsBoolean(PARSE_STRICT, false); this.defaultAllowUnmappedFields = indexSettings.getAsBoolean(ALLOW_UNMAPPED, true); - - List queryParsers = newArrayList(); - if (namedQueryParsers != null) { - Map queryParserGroups = indexSettings.getGroups(IndexQueryParserService.Defaults.QUERY_PREFIX); - for (Map.Entry entry : namedQueryParsers.entrySet()) { - String queryParserName = entry.getKey(); - QueryParserFactory queryParserFactory = entry.getValue(); - Settings queryParserSettings = queryParserGroups.get(queryParserName); - if (queryParserSettings == null) { - queryParserSettings = EMPTY_SETTINGS; - } - queryParsers.add(queryParserFactory.create(queryParserName, queryParserSettings)); - } - } - - Map queryParsersMap = newHashMap(); - queryParsersMap.putAll(indicesQueriesRegistry.queryParsers()); - if (queryParsers != null) { - for (QueryParser queryParser : queryParsers) { - add(queryParsersMap, queryParser); - } - } - this.queryParsers = ImmutableMap.copyOf(queryParsersMap); + this.indicesQueriesRegistry = indicesQueriesRegistry; } public void close() { @@ -157,7 +121,7 @@ public class IndexQueryParserService extends AbstractIndexComponent { } public QueryParser queryParser(String name) { - return queryParsers.get(name); + return indicesQueriesRegistry.queryParsers().get(name); } public ParsedQuery parse(QueryBuilder queryBuilder) { @@ -349,10 +313,4 @@ public class IndexQueryParserService extends AbstractIndexComponent { parseContext.reset(null); } } - - private void add(Map map, QueryParser queryParser) { - for (String name : queryParser.names()) { - map.put(name.intern(), queryParser); - } - } } diff --git a/core/src/main/java/org/elasticsearch/index/query/QueryParserFactory.java b/core/src/main/java/org/elasticsearch/index/query/QueryParserFactory.java deleted file mode 100644 index fa280ffe7fa..00000000000 --- a/core/src/main/java/org/elasticsearch/index/query/QueryParserFactory.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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.index.query; - -import org.elasticsearch.common.settings.Settings; - -/** - * - */ -public interface QueryParserFactory { - - QueryParser create(String name, Settings settings); -} diff --git a/core/src/main/java/org/elasticsearch/indices/IndicesService.java b/core/src/main/java/org/elasticsearch/indices/IndicesService.java index 4f55237f7ca..ba0241a043d 100644 --- a/core/src/main/java/org/elasticsearch/indices/IndicesService.java +++ b/core/src/main/java/org/elasticsearch/indices/IndicesService.java @@ -57,7 +57,6 @@ import org.elasticsearch.index.indexing.IndexingStats; import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.mapper.MapperServiceModule; import org.elasticsearch.index.merge.MergeStats; -import org.elasticsearch.index.query.IndexQueryParserModule; import org.elasticsearch.index.query.IndexQueryParserService; import org.elasticsearch.index.recovery.RecoveryStats; import org.elasticsearch.index.refresh.RefreshStats; @@ -315,7 +314,6 @@ public class IndicesService extends AbstractLifecycleComponent i modules.add(new IndexCacheModule(indexSettings)); modules.add(new IndexFieldDataModule(indexSettings)); modules.add(new MapperServiceModule()); - modules.add(new IndexQueryParserModule(indexSettings)); modules.add(new IndexAliasesServiceModule()); modules.add(new IndexModule(indexSettings)); diff --git a/core/src/main/java/org/elasticsearch/indices/query/IndicesQueriesModule.java b/core/src/main/java/org/elasticsearch/indices/query/IndicesQueriesModule.java index 8e4ff94d87d..fb7ca1784e3 100644 --- a/core/src/main/java/org/elasticsearch/indices/query/IndicesQueriesModule.java +++ b/core/src/main/java/org/elasticsearch/indices/query/IndicesQueriesModule.java @@ -30,30 +30,21 @@ import java.util.Set; public class IndicesQueriesModule extends AbstractModule { - private Set> queryParsersClasses = Sets.newHashSet(); - private Set queryParsers = Sets.newHashSet(); + private Set> queryParsersClasses = Sets.newHashSet(); - public synchronized IndicesQueriesModule addQuery(Class queryParser) { + public synchronized IndicesQueriesModule addQuery(Class queryParser) { queryParsersClasses.add(queryParser); return this; } - public synchronized IndicesQueriesModule addQuery(QueryParser queryParser) { - queryParsers.add(queryParser); - return this; - } - @Override protected void configure() { bind(IndicesQueriesRegistry.class).asEagerSingleton(); Multibinder qpBinders = Multibinder.newSetBinder(binder(), QueryParser.class); - for (Class queryParser : queryParsersClasses) { + for (Class queryParser : queryParsersClasses) { qpBinders.addBinding().to(queryParser).asEagerSingleton(); } - for (QueryParser queryParser : queryParsers) { - qpBinders.addBinding().toInstance(queryParser); - } qpBinders.addBinding().to(MatchQueryParser.class).asEagerSingleton(); qpBinders.addBinding().to(MultiMatchQueryParser.class).asEagerSingleton(); qpBinders.addBinding().to(NestedQueryParser.class).asEagerSingleton(); diff --git a/core/src/main/java/org/elasticsearch/indices/query/IndicesQueriesRegistry.java b/core/src/main/java/org/elasticsearch/indices/query/IndicesQueriesRegistry.java index a4e3116b41a..7d13fe01975 100644 --- a/core/src/main/java/org/elasticsearch/indices/query/IndicesQueriesRegistry.java +++ b/core/src/main/java/org/elasticsearch/indices/query/IndicesQueriesRegistry.java @@ -30,9 +30,6 @@ import org.elasticsearch.index.query.QueryParser; import java.util.Map; import java.util.Set; -/** - * - */ public class IndicesQueriesRegistry extends AbstractComponent { private ImmutableMap queryParsers; @@ -42,27 +39,17 @@ public class IndicesQueriesRegistry extends AbstractComponent { super(settings); Map queryParsers = Maps.newHashMap(); for (QueryParser queryParser : injectedQueryParsers) { - addQueryParser(queryParsers, queryParser); + for (String name : queryParser.names()) { + queryParsers.put(name, queryParser); + } } this.queryParsers = ImmutableMap.copyOf(queryParsers); } /** - * Adds a global query parser. + * Returns all the registered query parsers */ - public synchronized void addQueryParser(QueryParser queryParser) { - Map queryParsers = Maps.newHashMap(this.queryParsers); - addQueryParser(queryParsers, queryParser); - this.queryParsers = ImmutableMap.copyOf(queryParsers); - } - public ImmutableMap queryParsers() { return queryParsers; } - - private void addQueryParser(Map queryParsers, QueryParser queryParser) { - for (String name : queryParser.names()) { - queryParsers.put(name, queryParser); - } - } } \ No newline at end of file diff --git a/core/src/main/java/org/elasticsearch/node/internal/InternalSettingsPreparer.java b/core/src/main/java/org/elasticsearch/node/internal/InternalSettingsPreparer.java index 324158f894a..dbdaa5a1aeb 100644 --- a/core/src/main/java/org/elasticsearch/node/internal/InternalSettingsPreparer.java +++ b/core/src/main/java/org/elasticsearch/node/internal/InternalSettingsPreparer.java @@ -44,8 +44,8 @@ public class InternalSettingsPreparer { static final List ALLOWED_SUFFIXES = ImmutableList.of(".yml", ".yaml", ".json", ".properties"); - public static final String SECRET_PROMPT_VALUE = "${prompt::secret}"; - public static final String TEXT_PROMPT_VALUE = "${prompt::text}"; + public static final String SECRET_PROMPT_VALUE = "${prompt.secret}"; + public static final String TEXT_PROMPT_VALUE = "${prompt.text}"; public static final String IGNORE_SYSTEM_PROPERTIES_SETTING = "config.ignore_system_properties"; /** @@ -72,9 +72,6 @@ public class InternalSettingsPreparer { public static Tuple prepareSettings(Settings pSettings, boolean loadConfigSettings, Terminal terminal) { // ignore this prefixes when getting properties from es. and elasticsearch. String[] ignorePrefixes = new String[]{"es.default.", "elasticsearch.default."}; - // ignore the special prompt placeholders since they have the same format as property placeholders and will be resolved - // as having a default value because of the ':' in the format - String[] ignoredPlaceholders = new String[] { SECRET_PROMPT_VALUE, TEXT_PROMPT_VALUE }; boolean useSystemProperties = !pSettings.getAsBoolean(IGNORE_SYSTEM_PROPERTIES_SETTING, false); // just create enough settings to build the environment Settings.Builder settingsBuilder = settingsBuilder().put(pSettings); @@ -84,7 +81,7 @@ public class InternalSettingsPreparer { .putProperties("elasticsearch.", System.getProperties(), ignorePrefixes) .putProperties("es.", System.getProperties(), ignorePrefixes); } - settingsBuilder.replacePropertyPlaceholders(ignoredPlaceholders); + settingsBuilder.replacePropertyPlaceholders(); Environment environment = new Environment(settingsBuilder.build()); @@ -122,7 +119,7 @@ public class InternalSettingsPreparer { settingsBuilder.putProperties("elasticsearch.", System.getProperties(), ignorePrefixes) .putProperties("es.", System.getProperties(), ignorePrefixes); } - settingsBuilder.replacePropertyPlaceholders(ignoredPlaceholders); + settingsBuilder.replacePropertyPlaceholders(); // allow to force set properties based on configuration of the settings provided for (Map.Entry entry : pSettings.getAsMap().entrySet()) { @@ -132,7 +129,7 @@ public class InternalSettingsPreparer { settingsBuilder.put(setting.substring("force.".length()), entry.getValue()); } } - settingsBuilder.replacePropertyPlaceholders(ignoredPlaceholders); + settingsBuilder.replacePropertyPlaceholders(); // generate the name if (settingsBuilder.get("name") == null) { diff --git a/core/src/main/java/org/elasticsearch/search/SearchService.java b/core/src/main/java/org/elasticsearch/search/SearchService.java index 15e0fa63069..2e03644b8d2 100644 --- a/core/src/main/java/org/elasticsearch/search/SearchService.java +++ b/core/src/main/java/org/elasticsearch/search/SearchService.java @@ -22,7 +22,6 @@ package org.elasticsearch.search; import com.carrotsearch.hppc.ObjectHashSet; import com.carrotsearch.hppc.ObjectSet; import com.carrotsearch.hppc.cursors.ObjectCursor; -import com.google.common.base.Charsets; import com.google.common.collect.ImmutableMap; import org.apache.lucene.index.IndexOptions; @@ -682,9 +681,10 @@ public class SearchService extends AbstractLifecycleComponent { private void parseTemplate(ShardSearchRequest request) { - final ExecutableScript executable; + BytesReference processedQuery; if (request.template() != null) { - executable = this.scriptService.executable(request.template(), ScriptContext.Standard.SEARCH); + ExecutableScript executable = this.scriptService.executable(request.template(), ScriptContext.Standard.SEARCH); + processedQuery = (BytesReference) executable.run(); } else { if (!hasLength(request.templateSource())) { return; @@ -700,13 +700,16 @@ public class SearchService extends AbstractLifecycleComponent { //Try to double parse for nested template id/file parser = null; try { - byte[] templateBytes = template.getScript().getBytes(Charsets.UTF_8); - parser = XContentFactory.xContent(templateBytes).createParser(templateBytes); + ExecutableScript executable = this.scriptService.executable(template, ScriptContext.Standard.SEARCH); + processedQuery = (BytesReference) executable.run(); + parser = XContentFactory.xContent(processedQuery).createParser(processedQuery); } catch (ElasticsearchParseException epe) { //This was an non-nested template, the parse failure was due to this, it is safe to assume this refers to a file //for backwards compatibility and keep going template = new Template(template.getScript(), ScriptService.ScriptType.FILE, MustacheScriptEngineService.NAME, null, template.getParams()); + ExecutableScript executable = this.scriptService.executable(template, ScriptContext.Standard.SEARCH); + processedQuery = (BytesReference) executable.run(); } if (parser != null) { try { @@ -715,11 +718,16 @@ public class SearchService extends AbstractLifecycleComponent { //An inner template referring to a filename or id template = new Template(innerTemplate.getScript(), innerTemplate.getType(), MustacheScriptEngineService.NAME, null, template.getParams()); + ExecutableScript executable = this.scriptService.executable(template, ScriptContext.Standard.SEARCH); + processedQuery = (BytesReference) executable.run(); } } catch (ScriptParseException e) { // No inner template found, use original template from above } } + } else { + ExecutableScript executable = this.scriptService.executable(template, ScriptContext.Standard.SEARCH); + processedQuery = (BytesReference) executable.run(); } } catch (IOException e) { throw new ElasticsearchParseException("Failed to parse template", e); @@ -730,10 +738,7 @@ public class SearchService extends AbstractLifecycleComponent { if (!hasLength(template.getScript())) { throw new ElasticsearchParseException("Template must have [template] field configured"); } - executable = this.scriptService.executable(template, ScriptContext.Standard.SEARCH); } - - BytesReference processedQuery = (BytesReference) executable.run(); request.source(processedQuery); } diff --git a/core/src/test/java/org/elasticsearch/common/property/PropertyPlaceholderTest.java b/core/src/test/java/org/elasticsearch/common/property/PropertyPlaceholderTest.java index c79d0917c16..3e4d3fffece 100644 --- a/core/src/test/java/org/elasticsearch/common/property/PropertyPlaceholderTest.java +++ b/core/src/test/java/org/elasticsearch/common/property/PropertyPlaceholderTest.java @@ -33,7 +33,7 @@ public class PropertyPlaceholderTest extends ElasticsearchTestCase { Map map = new LinkedHashMap<>(); map.put("foo1", "bar1"); map.put("foo2", "bar2"); - PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false); + PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false, true); assertEquals("bar1", propertyPlaceholder.replacePlaceholders("{foo1}", placeholderResolver)); assertEquals("a bar1b", propertyPlaceholder.replacePlaceholders("a {foo1}b", placeholderResolver)); assertEquals("bar1bar2", propertyPlaceholder.replacePlaceholders("{foo1}{foo2}", placeholderResolver)); @@ -48,7 +48,7 @@ public class PropertyPlaceholderTest extends ElasticsearchTestCase { PropertyPlaceholder ppShorterPrefix = new PropertyPlaceholder("{", "}}", false); Map map = new LinkedHashMap<>(); map.put("foo", "bar"); - PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false); + PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false, true); assertEquals("bar", ppEqualsPrefix.replacePlaceholders("{foo}", placeholderResolver)); assertEquals("bar", ppLongerPrefix.replacePlaceholders("${foo}", placeholderResolver)); assertEquals("bar", ppShorterPrefix.replacePlaceholders("{foo}}", placeholderResolver)); @@ -58,7 +58,7 @@ public class PropertyPlaceholderTest extends ElasticsearchTestCase { public void testDefaultValue() { PropertyPlaceholder propertyPlaceholder = new PropertyPlaceholder("${", "}", false); Map map = new LinkedHashMap<>(); - PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false); + PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false, true); assertEquals("bar", propertyPlaceholder.replacePlaceholders("${foo:bar}", placeholderResolver)); assertEquals("", propertyPlaceholder.replacePlaceholders("${foo:}", placeholderResolver)); } @@ -67,7 +67,7 @@ public class PropertyPlaceholderTest extends ElasticsearchTestCase { public void testIgnoredUnresolvedPlaceholder() { PropertyPlaceholder propertyPlaceholder = new PropertyPlaceholder("${", "}", true); Map map = new LinkedHashMap<>(); - PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false); + PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false, true); assertEquals("${foo}", propertyPlaceholder.replacePlaceholders("${foo}", placeholderResolver)); } @@ -75,7 +75,7 @@ public class PropertyPlaceholderTest extends ElasticsearchTestCase { public void testNotIgnoredUnresolvedPlaceholder() { PropertyPlaceholder propertyPlaceholder = new PropertyPlaceholder("${", "}", false); Map map = new LinkedHashMap<>(); - PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false); + PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false, true); propertyPlaceholder.replacePlaceholders("${foo}", placeholderResolver); } @@ -83,7 +83,7 @@ public class PropertyPlaceholderTest extends ElasticsearchTestCase { public void testShouldIgnoreMissing() { PropertyPlaceholder propertyPlaceholder = new PropertyPlaceholder("${", "}", false); Map map = new LinkedHashMap<>(); - PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, true); + PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, true, true); assertEquals("bar", propertyPlaceholder.replacePlaceholders("bar${foo}", placeholderResolver)); } @@ -94,7 +94,7 @@ public class PropertyPlaceholderTest extends ElasticsearchTestCase { map.put("foo", "${foo1}"); map.put("foo1", "${foo2}"); map.put("foo2", "bar"); - PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false); + PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false, true); assertEquals("bar", propertyPlaceholder.replacePlaceholders("${foo}", placeholderResolver)); assertEquals("abarb", propertyPlaceholder.replacePlaceholders("a${foo}b", placeholderResolver)); } @@ -107,7 +107,7 @@ public class PropertyPlaceholderTest extends ElasticsearchTestCase { map.put("foo1", "${foo2}"); map.put("foo2", "bar"); map.put("barbar", "baz"); - PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false); + PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false, true); assertEquals("baz", propertyPlaceholder.replacePlaceholders("${bar${foo}}", placeholderResolver)); } @@ -119,7 +119,7 @@ public class PropertyPlaceholderTest extends ElasticsearchTestCase { map.put("foo1", "{foo2}"); map.put("foo2", "bar"); map.put("barbar", "baz"); - PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false); + PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false, true); assertEquals("baz", propertyPlaceholder.replacePlaceholders("{bar{foo}}", placeholderResolver)); } @@ -131,7 +131,7 @@ public class PropertyPlaceholderTest extends ElasticsearchTestCase { map.put("foo1", "{foo2}}"); map.put("foo2", "bar"); map.put("barbar", "baz"); - PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false); + PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false, true); assertEquals("baz", propertyPlaceholder.replacePlaceholders("{bar{foo}}}}", placeholderResolver)); } @@ -141,17 +141,27 @@ public class PropertyPlaceholderTest extends ElasticsearchTestCase { Map map = new LinkedHashMap<>(); map.put("foo", "${bar}"); map.put("bar", "${foo}"); - PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false); + PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, false, true); propertyPlaceholder.replacePlaceholders("${foo}", placeholderResolver); } + @Test + public void testShouldRemoveMissing() { + PropertyPlaceholder propertyPlaceholder = new PropertyPlaceholder("${", "}", false); + Map map = new LinkedHashMap<>(); + PropertyPlaceholder.PlaceholderResolver placeholderResolver = new SimplePlaceholderResolver(map, true, false); + assertEquals("bar${foo}", propertyPlaceholder.replacePlaceholders("bar${foo}", placeholderResolver)); + } + private class SimplePlaceholderResolver implements PropertyPlaceholder.PlaceholderResolver { private Map map; private boolean shouldIgnoreMissing; + private boolean shouldRemoveMissing; - SimplePlaceholderResolver(Map map, boolean shouldIgnoreMissing) { + SimplePlaceholderResolver(Map map, boolean shouldIgnoreMissing, boolean shouldRemoveMissing) { this.map = map; this.shouldIgnoreMissing = shouldIgnoreMissing; + this.shouldRemoveMissing = shouldRemoveMissing; } @Override @@ -163,5 +173,10 @@ public class PropertyPlaceholderTest extends ElasticsearchTestCase { public boolean shouldIgnoreMissing(String placeholderName) { return shouldIgnoreMissing; } + + @Override + public boolean shouldRemoveMissingPlaceholder(String placeholderName) { + return shouldRemoveMissing; + } } } 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 1dbaf32f06c..cf76a01ee0b 100644 --- a/core/src/test/java/org/elasticsearch/common/settings/SettingsTests.java +++ b/core/src/test/java/org/elasticsearch/common/settings/SettingsTests.java @@ -138,14 +138,14 @@ public class SettingsTests extends ElasticsearchTestCase { } @Test - public void testReplacePropertiesPlaceholderIgnores() { + public void testReplacePropertiesPlaceholderIgnoresPrompt() { Settings settings = settingsBuilder() - .put("setting1", "${foo.bar}") - .put("setting2", "${foo.bar1}") - .replacePropertyPlaceholders("${foo.bar}", "${foo.bar1}") + .put("setting1", "${prompt.text}") + .put("setting2", "${prompt.secret}") + .replacePropertyPlaceholders() .build(); - assertThat(settings.get("setting1"), is("${foo.bar}")); - assertThat(settings.get("setting2"), is("${foo.bar1}")); + assertThat(settings.get("setting1"), is("${prompt.text}")); + assertThat(settings.get("setting2"), is("${prompt.secret}")); } @Test diff --git a/core/src/test/java/org/elasticsearch/index/query/BaseQueryTestCase.java b/core/src/test/java/org/elasticsearch/index/query/BaseQueryTestCase.java index 579ea2184f4..b94874f224f 100644 --- a/core/src/test/java/org/elasticsearch/index/query/BaseQueryTestCase.java +++ b/core/src/test/java/org/elasticsearch/index/query/BaseQueryTestCase.java @@ -113,7 +113,6 @@ public abstract class BaseQueryTestCase> extends Ela new AnalysisModule(settings), new SimilarityModule(settings), new IndexNameModule(index), - new IndexQueryParserModule(settings), new FunctionScoreModule(), new AbstractModule() { @Override diff --git a/core/src/test/java/org/elasticsearch/index/query/SimpleIndexQueryParserTests.java b/core/src/test/java/org/elasticsearch/index/query/SimpleIndexQueryParserTests.java index 01c1b71f099..5b465dfb9ab 100644 --- a/core/src/test/java/org/elasticsearch/index/query/SimpleIndexQueryParserTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/SimpleIndexQueryParserTests.java @@ -41,7 +41,6 @@ import org.elasticsearch.action.termvectors.*; import org.elasticsearch.common.Strings; import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.compress.CompressedXContent; -import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.lucene.search.MoreLikeThisQuery; import org.elasticsearch.common.lucene.search.Queries; import org.elasticsearch.common.lucene.search.function.BoostScoreFunction; @@ -50,12 +49,9 @@ import org.elasticsearch.common.lucene.search.function.WeightFactorFunction; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.DistanceUnit; import org.elasticsearch.common.unit.Fuzziness; -import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.index.AbstractIndexComponent; -import org.elasticsearch.index.Index; import org.elasticsearch.index.IndexService; import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.mapper.ParsedDocument; @@ -71,7 +67,6 @@ import org.junit.Before; import org.junit.Test; import java.io.IOException; -import java.util.Arrays; import java.util.EnumSet; import java.util.List; @@ -83,86 +78,13 @@ import static org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders. import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertBooleanSubQuery; import static org.hamcrest.Matchers.*; -/** - * - */ public class SimpleIndexQueryParserTests extends ElasticsearchSingleNodeTest { private IndexQueryParserService queryParser; - private static class DummyQuery extends Query { - - public boolean isFilter; - - @Override - public String toString(String field) { - return getClass().getSimpleName(); - } - - } - - public static class DummyQueryParser extends AbstractIndexComponent implements QueryParser { - - - - @Inject - public DummyQueryParser(Index index, Settings indexSettings) { - super(index, indexSettings); - } - - @Override - public String[] names() { - return new String[] {DummyQueryBuilder.NAME}; - } - - @Override - public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException { - return fromXContent(parseContext).toQuery(parseContext); - - } - - @Override - public QueryBuilder fromXContent(QueryParseContext parseContext) throws IOException, QueryParsingException { - assertEquals(XContentParser.Token.END_OBJECT, parseContext.parser().nextToken()); - return new DummyQueryBuilder(); - } - - @Override - public DummyQueryBuilder getBuilderPrototype() { - return new DummyQueryBuilder(); - } - } - - private static class DummyQueryBuilder extends QueryBuilder { - - public static final String NAME = "dummy"; - - @Override - protected void doXContent(XContentBuilder builder, Params params) throws IOException { - builder.startObject("dummy").endObject(); - } - - @Override - public Query toQuery(QueryParseContext parseContext) throws QueryParsingException, IOException { - DummyQuery query = new DummyQuery(); - query.isFilter = parseContext.isFilter(); - return query; - } - - @Override - public String queryId() { - return NAME; - } - } - - private static DummyQueryBuilder dummyQuery() { - return new DummyQueryBuilder(); - } - @Before public void setup() throws IOException { Settings settings = Settings.settingsBuilder() - .put("index.queryparser.query.dummy.type", DummyQueryParser.class) .put("index.cache.filter.type", "none") .put("name", "SimpleIndexQueryParserTests") .build(); @@ -1088,7 +1010,6 @@ public class SimpleIndexQueryParserTests extends ElasticsearchSingleNodeTest { assertThat(clauses[3].getOccur(), equalTo(BooleanClause.Occur.SHOULD)); } - @Test public void testBoolQuery() throws IOException { IndexQueryParserService queryParser = queryParser(); @@ -1989,7 +1910,6 @@ public class SimpleIndexQueryParserTests extends ElasticsearchSingleNodeTest { assertThat(filter.bottomRight().lon(), closeTo(-80, 0.00001)); } - @Test public void testGeoBoundingBoxFilter1() throws IOException { IndexQueryParserService queryParser = queryParser(); @@ -2489,72 +2409,11 @@ public class SimpleIndexQueryParserTests extends ElasticsearchSingleNodeTest { public void testTermsQueryFilter() throws Exception { // TermsQuery is tricky in that it parses differently as a query or a filter IndexQueryParserService queryParser = queryParser(); - Query q = queryParser.parse(termsQuery("foo", Arrays.asList("bar"))).query(); + Query q = queryParser.parse(termsQuery("foo", "bar")).query(); assertThat(q, instanceOf(BooleanQuery.class)); - ConstantScoreQuery csq = (ConstantScoreQuery) queryParser.parse(constantScoreQuery(termsQuery("foo", Arrays.asList("bar")))).query(); + ConstantScoreQuery csq = (ConstantScoreQuery) queryParser.parse(constantScoreQuery(termsQuery("foo", "bar"))).query(); q = csq.getQuery(); assertThat(q, instanceOf(TermsQuery.class)); } - - public void testConstantScoreParsesFilter() throws Exception { - IndexQueryParserService queryParser = queryParser(); - Query q = queryParser.parse(constantScoreQuery(dummyQuery())).query(); - Query inner = ((ConstantScoreQuery) q).getQuery(); - assertThat(inner, instanceOf(DummyQuery.class)); - assertEquals(true, ((DummyQuery) inner).isFilter); - } - - public void testBooleanParsesFilter() throws Exception { - IndexQueryParserService queryParser = queryParser(); - // single clause, serialized as inner object - Query q = queryParser.parse(boolQuery() - .should(dummyQuery()) - .must(dummyQuery()) - .filter(dummyQuery()) - .mustNot(dummyQuery())).query(); - assertThat(q, instanceOf(BooleanQuery.class)); - BooleanQuery bq = (BooleanQuery) q; - assertEquals(4, bq.clauses().size()); - for (BooleanClause clause : bq.clauses()) { - DummyQuery dummy = (DummyQuery) clause.getQuery(); - switch (clause.getOccur()) { - case FILTER: - case MUST_NOT: - assertEquals(true, dummy.isFilter); - break; - case MUST: - case SHOULD: - assertEquals(false, dummy.isFilter); - break; - default: - throw new AssertionError(); - } - } - - // multiple clauses, serialized as inner arrays - q = queryParser.parse(boolQuery() - .should(dummyQuery()).should(dummyQuery()) - .must(dummyQuery()).must(dummyQuery()) - .filter(dummyQuery()).filter(dummyQuery()) - .mustNot(dummyQuery()).mustNot(dummyQuery())).query(); - assertThat(q, instanceOf(BooleanQuery.class)); - bq = (BooleanQuery) q; - assertEquals(8, bq.clauses().size()); - for (BooleanClause clause : bq.clauses()) { - DummyQuery dummy = (DummyQuery) clause.getQuery(); - switch (clause.getOccur()) { - case FILTER: - case MUST_NOT: - assertEquals(true, dummy.isFilter); - break; - case MUST: - case SHOULD: - assertEquals(false, dummy.isFilter); - break; - default: - throw new AssertionError(); - } - } - } } diff --git a/core/src/test/java/org/elasticsearch/index/query/TemplateQueryParserTest.java b/core/src/test/java/org/elasticsearch/index/query/TemplateQueryParserTest.java index ad737fd797d..65174b3acea 100644 --- a/core/src/test/java/org/elasticsearch/index/query/TemplateQueryParserTest.java +++ b/core/src/test/java/org/elasticsearch/index/query/TemplateQueryParserTest.java @@ -83,7 +83,6 @@ public class TemplateQueryParserTest extends ElasticsearchTestCase { new AnalysisModule(settings), new SimilarityModule(settings), new IndexNameModule(index), - new IndexQueryParserModule(settings), new FunctionScoreModule(), new AbstractModule() { @Override @@ -118,6 +117,35 @@ public class TemplateQueryParserTest extends ElasticsearchTestCase { assertTrue("Parsing template query failed.", query instanceof MatchAllDocsQuery); } + @Test + public void testParseTemplateAsSingleStringWithConditionalClause() throws IOException { + String templateString = "{" + " \"inline\" : \"{ \\\"match_{{#use_it}}{{template}}{{/use_it}}\\\":{} }\"," + " \"params\":{" + + " \"template\":\"all\"," + " \"use_it\": true" + " }" + "}"; + XContentParser templateSourceParser = XContentFactory.xContent(templateString).createParser(templateString); + context.reset(templateSourceParser); + + TemplateQueryParser parser = injector.getInstance(TemplateQueryParser.class); + Query query = parser.parse(context); + assertTrue("Parsing template query failed.", query instanceof MatchAllDocsQuery); + } + + /** + * Test that the template query parser can parse and evaluate template + * expressed as a single string but still it expects only the query + * specification (thus this test should fail with specific exception). + */ + @Test(expected = QueryParsingException.class) + public void testParseTemplateFailsToParseCompleteQueryAsSingleString() throws IOException { + String templateString = "{" + " \"inline\" : \"{ \\\"size\\\": \\\"{{size}}\\\", \\\"query\\\":{\\\"match_all\\\":{}}}\"," + + " \"params\":{" + " \"size\":2" + " }\n" + "}"; + + XContentParser templateSourceParser = XContentFactory.xContent(templateString).createParser(templateString); + context.reset(templateSourceParser); + + TemplateQueryParser parser = injector.getInstance(TemplateQueryParser.class); + parser.parse(context); + } + @Test public void testParserCanExtractTemplateNames() throws Exception { String templateString = "{ \"file\": \"storedTemplate\" ,\"params\":{\"template\":\"all\" } } "; diff --git a/core/src/test/java/org/elasticsearch/index/query/TemplateQueryTest.java b/core/src/test/java/org/elasticsearch/index/query/TemplateQueryTest.java index 4ba9b010eb5..5f40004de3d 100644 --- a/core/src/test/java/org/elasticsearch/index/query/TemplateQueryTest.java +++ b/core/src/test/java/org/elasticsearch/index/query/TemplateQueryTest.java @@ -232,6 +232,67 @@ public class TemplateQueryTest extends ElasticsearchIntegrationTest { assertHitCount(searchResponse, 1); } + @Test + public void testSearchTemplateQueryFromFile() throws Exception { + SearchRequest searchRequest = new SearchRequest(); + searchRequest.indices("_all"); + String templateString = "{" + " \"file\": \"full-query-template\"," + " \"params\":{" + " \"mySize\": 2," + + " \"myField\": \"text\"," + " \"myValue\": \"value1\"" + " }" + "}"; + BytesReference bytesRef = new BytesArray(templateString); + searchRequest.templateSource(bytesRef); + SearchResponse searchResponse = client().search(searchRequest).get(); + assertThat(searchResponse.getHits().hits().length, equalTo(1)); + } + + /** + * Test that template can be expressed as a single escaped string. + */ + @Test + public void testTemplateQueryAsEscapedString() throws Exception { + SearchRequest searchRequest = new SearchRequest(); + searchRequest.indices("_all"); + String templateString = "{" + " \"template\" : \"{ \\\"size\\\": \\\"{{size}}\\\", \\\"query\\\":{\\\"match_all\\\":{}}}\"," + + " \"params\":{" + " \"size\": 1" + " }" + "}"; + BytesReference bytesRef = new BytesArray(templateString); + searchRequest.templateSource(bytesRef); + SearchResponse searchResponse = client().search(searchRequest).get(); + assertThat(searchResponse.getHits().hits().length, equalTo(1)); + } + + /** + * Test that template can contain conditional clause. In this case it is at + * the beginning of the string. + */ + @Test + public void testTemplateQueryAsEscapedStringStartingWithConditionalClause() throws Exception { + SearchRequest searchRequest = new SearchRequest(); + searchRequest.indices("_all"); + String templateString = "{" + + " \"template\" : \"{ {{#use_size}} \\\"size\\\": \\\"{{size}}\\\", {{/use_size}} \\\"query\\\":{\\\"match_all\\\":{}}}\"," + + " \"params\":{" + " \"size\": 1," + " \"use_size\": true" + " }" + "}"; + BytesReference bytesRef = new BytesArray(templateString); + searchRequest.templateSource(bytesRef); + SearchResponse searchResponse = client().search(searchRequest).get(); + assertThat(searchResponse.getHits().hits().length, equalTo(1)); + } + + /** + * Test that template can contain conditional clause. In this case it is at + * the end of the string. + */ + @Test + public void testTemplateQueryAsEscapedStringWithConditionalClauseAtEnd() throws Exception { + SearchRequest searchRequest = new SearchRequest(); + searchRequest.indices("_all"); + String templateString = "{" + + " \"inline\" : \"{ \\\"query\\\":{\\\"match_all\\\":{}} {{#use_size}}, \\\"size\\\": \\\"{{size}}\\\" {{/use_size}} }\"," + + " \"params\":{" + " \"size\": 1," + " \"use_size\": true" + " }" + "}"; + BytesReference bytesRef = new BytesArray(templateString); + searchRequest.templateSource(bytesRef); + SearchResponse searchResponse = client().search(searchRequest).get(); + assertThat(searchResponse.getHits().hits().length, equalTo(1)); + } + @Test(expected = SearchPhaseExecutionException.class) public void testIndexedTemplateClient() throws Exception { createIndex(ScriptService.SCRIPT_INDEX); diff --git a/core/src/test/java/org/elasticsearch/index/query/guice/IndexQueryParserModuleTests.java b/core/src/test/java/org/elasticsearch/index/query/guice/IndexQueryParserModuleTests.java deleted file mode 100644 index a26e233caf7..00000000000 --- a/core/src/test/java/org/elasticsearch/index/query/guice/IndexQueryParserModuleTests.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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.index.query.guice; - -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.index.query.IndexQueryParserService; -import org.elasticsearch.test.ElasticsearchSingleNodeTest; -import org.junit.Test; - -import static org.elasticsearch.common.settings.Settings.settingsBuilder; -import static org.hamcrest.Matchers.equalTo; - -/** - * - */ -public class IndexQueryParserModuleTests extends ElasticsearchSingleNodeTest { - - @Test - public void testCustomInjection() { - Settings settings = settingsBuilder() - .put("index.queryparser.query.my.type", MyJsonQueryParser.class) - .put("index.queryparser.query.my.param1", "value1") - .put("index.cache.filter.type", "none") - .put("name", "IndexQueryParserModuleTests") - .build(); - - IndexQueryParserService indexQueryParserService = createIndex("test", settings).queryParserService(); - - MyJsonQueryParser myJsonQueryParser = (MyJsonQueryParser) indexQueryParserService.queryParser("my"); - - assertThat(myJsonQueryParser.names()[0], equalTo("my")); - assertThat(myJsonQueryParser.settings().get("param1"), equalTo("value1")); - } -} diff --git a/core/src/test/java/org/elasticsearch/index/query/guice/MyJsonQueryParser.java b/core/src/test/java/org/elasticsearch/index/query/guice/MyJsonQueryParser.java deleted file mode 100644 index 13e99f3eff1..00000000000 --- a/core/src/test/java/org/elasticsearch/index/query/guice/MyJsonQueryParser.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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.index.query.guice; - -import org.apache.lucene.search.Query; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.inject.assistedinject.Assisted; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.index.AbstractIndexComponent; -import org.elasticsearch.index.Index; -import org.elasticsearch.index.query.QueryBuilder; -import org.elasticsearch.index.query.QueryParseContext; -import org.elasticsearch.index.query.QueryParser; -import org.elasticsearch.index.query.QueryParsingException; -import org.elasticsearch.index.query.QueryWrappingQueryBuilder; -import org.elasticsearch.index.settings.IndexSettings; - -import java.io.IOException; - -/** - * - */ -public class MyJsonQueryParser extends AbstractIndexComponent implements QueryParser { - - private final String name; - - private final Settings settings; - - @Inject - public MyJsonQueryParser(Index index, @IndexSettings Settings indexSettings, @Assisted String name, @Assisted Settings settings) { - super(index, indexSettings); - this.name = name; - this.settings = settings; - } - - @Override - public String[] names() { - return new String[]{this.name}; - } - - @Override - public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException { - return null; - } - - public Settings settings() { - return settings; - } - - @Override - public QueryBuilder fromXContent(QueryParseContext parseContext) throws IOException, QueryParsingException { - Query query = parse(parseContext); - return new QueryWrappingQueryBuilder(query); - } - - @Override - public QueryBuilder getBuilderPrototype() { - throw new UnsupportedOperationException("Not implemented in test class"); - } -} diff --git a/core/src/test/java/org/elasticsearch/index/query/plugin/IndexQueryParserPlugin2Tests.java b/core/src/test/java/org/elasticsearch/index/query/plugin/IndexQueryParserPlugin2Tests.java deleted file mode 100644 index 4e4420ca4af..00000000000 --- a/core/src/test/java/org/elasticsearch/index/query/plugin/IndexQueryParserPlugin2Tests.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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.index.query.plugin; - -import org.elasticsearch.Version; -import org.elasticsearch.cluster.ClusterService; -import org.elasticsearch.cluster.metadata.IndexMetaData; -import org.elasticsearch.common.inject.AbstractModule; -import org.elasticsearch.common.inject.Injector; -import org.elasticsearch.common.inject.ModulesBuilder; -import org.elasticsearch.common.inject.util.Providers; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.settings.SettingsModule; -import org.elasticsearch.env.Environment; -import org.elasticsearch.env.EnvironmentModule; -import org.elasticsearch.index.Index; -import org.elasticsearch.index.IndexNameModule; -import org.elasticsearch.index.analysis.AnalysisModule; -import org.elasticsearch.index.cache.IndexCacheModule; -import org.elasticsearch.index.query.IndexQueryParserModule; -import org.elasticsearch.index.query.IndexQueryParserService; -import org.elasticsearch.index.query.functionscore.FunctionScoreModule; -import org.elasticsearch.index.settings.IndexSettingsModule; -import org.elasticsearch.index.similarity.SimilarityModule; -import org.elasticsearch.indices.breaker.CircuitBreakerService; -import org.elasticsearch.indices.breaker.NoneCircuitBreakerService; -import org.elasticsearch.indices.query.IndicesQueriesModule; -import org.elasticsearch.script.ScriptModule; -import org.elasticsearch.test.ElasticsearchTestCase; -import org.elasticsearch.threadpool.ThreadPool; -import org.elasticsearch.threadpool.ThreadPoolModule; -import org.junit.Test; - -import static org.hamcrest.Matchers.equalTo; - -/** - * - */ -public class IndexQueryParserPlugin2Tests extends ElasticsearchTestCase { - - @Test - public void testCustomInjection() throws InterruptedException { - Settings settings = Settings.builder() - .put("name", "testCustomInjection") - .put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT) - .put("path.home", createTempDir()).build(); - - IndexQueryParserModule queryParserModule = new IndexQueryParserModule(settings); - queryParserModule.addQueryParser("my", PluginJsonQueryParser.class); - - Index index = new Index("test"); - Injector injector = new ModulesBuilder().add( - new EnvironmentModule(new Environment(settings)), - new SettingsModule(settings), - new ThreadPoolModule(new ThreadPool(settings)), - new IndicesQueriesModule(), - new ScriptModule(settings), - new IndexSettingsModule(index, settings), - new IndexCacheModule(settings), - new AnalysisModule(settings), - new SimilarityModule(settings), - queryParserModule, - new IndexNameModule(index), - new FunctionScoreModule(), - new AbstractModule() { - @Override - protected void configure() { - bind(ClusterService.class).toProvider(Providers.of((ClusterService) null)); - bind(CircuitBreakerService.class).to(NoneCircuitBreakerService.class); - } - } - ).createInjector(); - - IndexQueryParserService indexQueryParserService = injector.getInstance(IndexQueryParserService.class); - - PluginJsonQueryParser myJsonQueryParser = (PluginJsonQueryParser) indexQueryParserService.queryParser("my"); - - assertThat(myJsonQueryParser.names()[0], equalTo("my")); - - terminate(injector.getInstance(ThreadPool.class)); - } -} diff --git a/core/src/test/java/org/elasticsearch/index/query/plugin/IndexQueryParserPluginTests.java b/core/src/test/java/org/elasticsearch/index/query/plugin/IndexQueryParserPluginTests.java deleted file mode 100644 index 57a0d99741e..00000000000 --- a/core/src/test/java/org/elasticsearch/index/query/plugin/IndexQueryParserPluginTests.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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.index.query.plugin; - -import org.elasticsearch.Version; -import org.elasticsearch.cluster.ClusterService; -import org.elasticsearch.cluster.metadata.IndexMetaData; -import org.elasticsearch.common.inject.AbstractModule; -import org.elasticsearch.common.inject.Injector; -import org.elasticsearch.common.inject.ModulesBuilder; -import org.elasticsearch.common.inject.util.Providers; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.settings.SettingsModule; -import org.elasticsearch.env.Environment; -import org.elasticsearch.env.EnvironmentModule; -import org.elasticsearch.index.Index; -import org.elasticsearch.index.IndexNameModule; -import org.elasticsearch.index.analysis.AnalysisModule; -import org.elasticsearch.index.cache.IndexCacheModule; -import org.elasticsearch.index.query.IndexQueryParserModule; -import org.elasticsearch.index.query.IndexQueryParserService; -import org.elasticsearch.index.query.functionscore.FunctionScoreModule; -import org.elasticsearch.index.settings.IndexSettingsModule; -import org.elasticsearch.index.similarity.SimilarityModule; -import org.elasticsearch.indices.breaker.CircuitBreakerService; -import org.elasticsearch.indices.breaker.NoneCircuitBreakerService; -import org.elasticsearch.indices.query.IndicesQueriesModule; -import org.elasticsearch.script.ScriptModule; -import org.elasticsearch.test.ElasticsearchTestCase; -import org.elasticsearch.threadpool.ThreadPool; -import org.elasticsearch.threadpool.ThreadPoolModule; -import org.junit.Test; - -import static org.hamcrest.Matchers.equalTo; - -/** - * - */ -public class IndexQueryParserPluginTests extends ElasticsearchTestCase { - - @Test - public void testCustomInjection() throws InterruptedException { - Settings settings = Settings.builder() - .put("name", "testCustomInjection") - .put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT) - .put("path.home", createTempDir()).build(); - - IndexQueryParserModule queryParserModule = new IndexQueryParserModule(settings); - queryParserModule.addProcessor(new IndexQueryParserModule.QueryParsersProcessor() { - @Override - public void processXContentQueryParsers(XContentQueryParsersBindings bindings) { - bindings.processXContentQueryParser("my", PluginJsonQueryParser.class); - } - }); - - Index index = new Index("test"); - Injector injector = new ModulesBuilder().add( - new EnvironmentModule(new Environment(settings)), - new SettingsModule(settings), - new ThreadPoolModule(new ThreadPool(settings)), - new IndicesQueriesModule(), - new ScriptModule(settings), - new IndexSettingsModule(index, settings), - new IndexCacheModule(settings), - new AnalysisModule(settings), - new SimilarityModule(settings), - queryParserModule, - new IndexNameModule(index), - new FunctionScoreModule(), - new AbstractModule() { - @Override - protected void configure() { - bind(ClusterService.class).toProvider(Providers.of((ClusterService) null)); - bind(CircuitBreakerService.class).to(NoneCircuitBreakerService.class); - } - } - ).createInjector(); - - IndexQueryParserService indexQueryParserService = injector.getInstance(IndexQueryParserService.class); - - PluginJsonQueryParser myJsonQueryParser = (PluginJsonQueryParser) indexQueryParserService.queryParser("my"); - - assertThat(myJsonQueryParser.names()[0], equalTo("my")); - - terminate(injector.getInstance(ThreadPool.class)); - } -} diff --git a/core/src/test/java/org/elasticsearch/index/query/plugin/PluginJsonQueryParser.java b/core/src/test/java/org/elasticsearch/index/query/plugin/PluginJsonQueryParser.java deleted file mode 100644 index fdf1be4e9f5..00000000000 --- a/core/src/test/java/org/elasticsearch/index/query/plugin/PluginJsonQueryParser.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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.index.query.plugin; - -import org.apache.lucene.search.Query; -import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.inject.assistedinject.Assisted; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.index.AbstractIndexComponent; -import org.elasticsearch.index.Index; -import org.elasticsearch.index.query.QueryBuilder; -import org.elasticsearch.index.query.QueryParseContext; -import org.elasticsearch.index.query.QueryParser; -import org.elasticsearch.index.query.QueryParsingException; -import org.elasticsearch.index.query.QueryWrappingQueryBuilder; -import org.elasticsearch.index.settings.IndexSettings; - -import java.io.IOException; - -/** - * - */ -public class PluginJsonQueryParser extends AbstractIndexComponent implements QueryParser { - - private final String name; - - private final Settings settings; - - @Inject - public PluginJsonQueryParser(Index index, @IndexSettings Settings indexSettings, @Assisted String name, @Assisted Settings settings) { - super(index, indexSettings); - this.name = name; - this.settings = settings; - } - - @Override - public String[] names() { - return new String[]{this.name}; - } - - @Override - public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException { - return null; - } - - public Settings settings() { - return settings; - } - - @Override - public QueryBuilder fromXContent(QueryParseContext parseContext) throws IOException, QueryParsingException { - Query query = parse(parseContext); - return new QueryWrappingQueryBuilder(query); - } - - @Override - public QueryBuilder getBuilderPrototype() { - throw new UnsupportedOperationException("Not implemented in test class"); - } -} \ No newline at end of file diff --git a/docs/reference/migration/migrate_2_0.asciidoc b/docs/reference/migration/migrate_2_0.asciidoc index 6a12ac3bbbc..eff219c5887 100644 --- a/docs/reference/migration/migrate_2_0.asciidoc +++ b/docs/reference/migration/migrate_2_0.asciidoc @@ -490,6 +490,10 @@ ignored. Instead filters are always used as their own cache key and elasticsearc makes decisions by itself about whether it should cache filters based on how often they are used. +Java plugins that register custom queries can do so by using the +`IndicesQueriesModule#addQuery(Class)` method. Other +ways to register custom queries are not supported anymore. + ==== Query/filter merge Elasticsearch no longer makes a difference between queries and filters in the diff --git a/docs/reference/setup/configuration.asciidoc b/docs/reference/setup/configuration.asciidoc index 2fb985b39f3..5e43e9daf01 100644 --- a/docs/reference/setup/configuration.asciidoc +++ b/docs/reference/setup/configuration.asciidoc @@ -271,15 +271,15 @@ file which will resolve to an environment setting, for example: -------------------------------------------------- Additionally, for settings that you do not wish to store in the configuration -file, you can use the value `${prompt::text}` or `${prompt::secret}` and start -Elasticsearch in the foreground. `${prompt::secret}` has echoing disabled so -that the value entered will not be shown in your terminal; `${prompt::text}` +file, you can use the value `${prompt.text}` or `${prompt.secret}` and start +Elasticsearch in the foreground. `${prompt.secret}` has echoing disabled so +that the value entered will not be shown in your terminal; `${prompt.text}` will allow you to see the value as you type it in. For example: [source,yaml] -------------------------------------------------- node: - name: ${prompt::text} + name: ${prompt.text} -------------------------------------------------- On execution of the `elasticsearch` command, you will be prompted to enter @@ -290,7 +290,7 @@ the actual value like so: Enter value for [node.name]: -------------------------------------------------- -NOTE: Elasticsearch will not start if `${prompt::text}` or `${prompt::secret}` +NOTE: Elasticsearch will not start if `${prompt.text}` or `${prompt.secret}` is used in the settings and the process is run as a service or in the background. The location of the configuration file can be set externally using a diff --git a/plugins/cloud-azure/src/test/java/org/elasticsearch/discovery/azure/AzureTwoStartedNodesTest.java b/plugins/cloud-azure/src/test/java/org/elasticsearch/discovery/azure/AzureTwoStartedNodesTest.java index 49eb96e7cdb..890fa2d15c5 100644 --- a/plugins/cloud-azure/src/test/java/org/elasticsearch/discovery/azure/AzureTwoStartedNodesTest.java +++ b/plugins/cloud-azure/src/test/java/org/elasticsearch/discovery/azure/AzureTwoStartedNodesTest.java @@ -60,6 +60,7 @@ public class AzureTwoStartedNodesTest extends AbstractAzureComputeServiceTest { } @Test + @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/11533") public void two_nodes_should_run_using_public_ip() { Settings.Builder settings = Settings.settingsBuilder() .put(Management.SERVICE_NAME, "dummy") diff --git a/rest-api-spec/test/indices.flush/10_basic.yaml b/rest-api-spec/test/indices.flush/10_basic.yaml index 3c8d34be31a..659435ae196 100644 --- a/rest-api-spec/test/indices.flush/10_basic.yaml +++ b/rest-api-spec/test/indices.flush/10_basic.yaml @@ -3,10 +3,14 @@ - do: indices.create: index: testing + body: + settings: + index: + number_of_replicas: 0 - do: cluster.health: - wait_for_status: yellow + wait_for_status: green - do: indices.flush_synced: index: testing diff --git a/src/test/java/org/elasticsearch/index/query/plugin/CustomQueryParserTests.java b/src/test/java/org/elasticsearch/index/query/plugin/CustomQueryParserTests.java new file mode 100644 index 00000000000..9e396b7e8d1 --- /dev/null +++ b/src/test/java/org/elasticsearch/index/query/plugin/CustomQueryParserTests.java @@ -0,0 +1,138 @@ +/* + * 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.index.query.plugin; + +import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.ConstantScoreQuery; +import org.apache.lucene.search.Query; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.IndexQueryParserService; +import org.elasticsearch.indices.IndicesService; +import org.elasticsearch.test.ElasticsearchIntegrationTest; +import org.junit.Before; +import org.junit.Test; + +import static org.elasticsearch.index.query.QueryBuilders.boolQuery; +import static org.elasticsearch.index.query.QueryBuilders.constantScoreQuery; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; +import static org.hamcrest.Matchers.instanceOf; + +public class CustomQueryParserTests extends ElasticsearchIntegrationTest { + + @Override + protected Settings nodeSettings(int nodeOrdinal) { + return Settings.builder().put(super.nodeSettings(nodeOrdinal)) + .put("plugin.types", DummyQueryParserPlugin.class.getName()).build(); + } + + @Before + public void setUp() throws Exception { + super.setUp(); + createIndex("test"); + ensureGreen(); + client().prepareIndex("index", "type", "1").setSource("field", "value").get(); + refresh(); + } + + @Override + protected int numberOfShards() { + return cluster().numDataNodes(); + } + + @Test + public void testCustomDummyQuery() { + assertHitCount(client().prepareSearch("index").setQuery(new DummyQueryParserPlugin.DummyQueryBuilder()).get(), 1l); + } + + @Test + public void testCustomDummyQueryWithinBooleanQuery() { + assertHitCount(client().prepareSearch("index").setQuery(new BoolQueryBuilder().must(new DummyQueryParserPlugin.DummyQueryBuilder())).get(), 1l); + } + + private static IndexQueryParserService queryParser() { + IndicesService indicesService = internalCluster().getDataNodeInstance(IndicesService.class); + return indicesService.indexServiceSafe("index").queryParserService(); + } + + @Test //see #11120 + public void testConstantScoreParsesFilter() throws Exception { + IndexQueryParserService queryParser = queryParser(); + Query q = queryParser.parse(constantScoreQuery(new DummyQueryParserPlugin.DummyQueryBuilder())).query(); + Query inner = ((ConstantScoreQuery) q).getQuery(); + assertThat(inner, instanceOf(DummyQueryParserPlugin.DummyQuery.class)); + assertEquals(true, ((DummyQueryParserPlugin.DummyQuery) inner).isFilter); + } + + @Test //see #11120 + public void testBooleanParsesFilter() throws Exception { + IndexQueryParserService queryParser = queryParser(); + // single clause, serialized as inner object + Query q = queryParser.parse(boolQuery() + .should(new DummyQueryParserPlugin.DummyQueryBuilder()) + .must(new DummyQueryParserPlugin.DummyQueryBuilder()) + .filter(new DummyQueryParserPlugin.DummyQueryBuilder()) + .mustNot(new DummyQueryParserPlugin.DummyQueryBuilder())).query(); + assertThat(q, instanceOf(BooleanQuery.class)); + BooleanQuery bq = (BooleanQuery) q; + assertEquals(4, bq.clauses().size()); + for (BooleanClause clause : bq.clauses()) { + DummyQueryParserPlugin.DummyQuery dummy = (DummyQueryParserPlugin.DummyQuery) clause.getQuery(); + switch (clause.getOccur()) { + case FILTER: + case MUST_NOT: + assertEquals(true, dummy.isFilter); + break; + case MUST: + case SHOULD: + assertEquals(false, dummy.isFilter); + break; + default: + throw new AssertionError(); + } + } + + // multiple clauses, serialized as inner arrays + q = queryParser.parse(boolQuery() + .should(new DummyQueryParserPlugin.DummyQueryBuilder()).should(new DummyQueryParserPlugin.DummyQueryBuilder()) + .must(new DummyQueryParserPlugin.DummyQueryBuilder()).must(new DummyQueryParserPlugin.DummyQueryBuilder()) + .filter(new DummyQueryParserPlugin.DummyQueryBuilder()).filter(new DummyQueryParserPlugin.DummyQueryBuilder()) + .mustNot(new DummyQueryParserPlugin.DummyQueryBuilder()).mustNot(new DummyQueryParserPlugin.DummyQueryBuilder())).query(); + assertThat(q, instanceOf(BooleanQuery.class)); + bq = (BooleanQuery) q; + assertEquals(8, bq.clauses().size()); + for (BooleanClause clause : bq.clauses()) { + DummyQueryParserPlugin.DummyQuery dummy = (DummyQueryParserPlugin.DummyQuery) clause.getQuery(); + switch (clause.getOccur()) { + case FILTER: + case MUST_NOT: + assertEquals(true, dummy.isFilter); + break; + case MUST: + case SHOULD: + assertEquals(false, dummy.isFilter); + break; + default: + throw new AssertionError(); + } + } + } +} diff --git a/src/test/java/org/elasticsearch/index/query/plugin/DummyQueryParserPlugin.java b/src/test/java/org/elasticsearch/index/query/plugin/DummyQueryParserPlugin.java new file mode 100644 index 00000000000..b25668a06c8 --- /dev/null +++ b/src/test/java/org/elasticsearch/index/query/plugin/DummyQueryParserPlugin.java @@ -0,0 +1,102 @@ +/* + * 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.index.query.plugin; + +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.MatchAllDocsQuery; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.Weight; +import org.elasticsearch.common.inject.Module; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.QueryParseContext; +import org.elasticsearch.index.query.QueryParser; +import org.elasticsearch.index.query.QueryParsingException; +import org.elasticsearch.indices.query.IndicesQueriesModule; +import org.elasticsearch.plugins.AbstractPlugin; + +import java.io.IOException; + +public class DummyQueryParserPlugin extends AbstractPlugin { + + @Override + public String name() { + return "dummy"; + } + + @Override + public String description() { + return "dummy query"; + } + + @Override + public void processModule(Module module) { + if (module instanceof IndicesQueriesModule) { + IndicesQueriesModule indicesQueriesModule = (IndicesQueriesModule) module; + indicesQueriesModule.addQuery(DummyQueryParserPlugin.DummyQueryParser.class); + } + } + + public Settings settings() { + return Settings.EMPTY; + } + + public static class DummyQueryBuilder extends QueryBuilder { + @Override + protected void doXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject("dummy").endObject(); + } + } + + public static class DummyQueryParser implements QueryParser { + @Override + public String[] names() { + return new String[]{"dummy"}; + } + + @Override + public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException { + XContentParser.Token token = parseContext.parser().nextToken(); + assert token == XContentParser.Token.END_OBJECT; + return new DummyQuery(parseContext.isFilter()); + } + } + + public static class DummyQuery extends Query { + public final boolean isFilter; + private final Query matchAllDocsQuery = new MatchAllDocsQuery(); + + private DummyQuery(boolean isFilter) { + this.isFilter = isFilter; + } + + @Override + public String toString(String field) { + return getClass().getSimpleName(); + } + + @Override + public Weight createWeight(IndexSearcher searcher, boolean needsScores) throws IOException { + return matchAllDocsQuery.createWeight(searcher, needsScores); + } + } +} \ No newline at end of file