Skip to content

Commit a04dcfb

Browse files
authored
Introduce XContentParser#namedObject (#22003)
Introduces `XContentParser#namedObject which works a little like `StreamInput#readNamedWriteable`: on startup components register parsers under names and a superclass. At runtime we look up the parser and call it to parse the object. Right now the parsers take a context object they use to help with the parsing but I hope to be able to eliminate the need for this context as most what it is used for at this point is to move around parser registries which should be replaced by this method eventually. I make no effort to do so in this PR because it is big enough already. This is meant to the a start down a road that allows us to remove classes like `QueryParseContext`, `AggregatorParsers`, `IndicesQueriesRegistry`, and `ParseFieldRegistry`. The goal here is to reduce the amount of plumbing required to allow parsing pluggable things. With this you don't have to pass registries all over the place. Instead you must pass a super registry to fewer places and use it to wrap the reader. This is the same tradeoff that we use for NamedWriteable and it allows much, much simpler binary serialization. We think we want that same thing for xcontent serialization. The only parsing actually converted to this method is parsing `ScoreFunctions` inside of `FunctionScoreQuery`. I chose this because it is relatively self contained.
1 parent 7332056 commit a04dcfb

File tree

161 files changed

+1196
-638
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

161 files changed

+1196
-638
lines changed

core/src/main/java/org/elasticsearch/ElasticsearchException.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -787,7 +787,9 @@ enum ElasticsearchExceptionHandle {
787787
TASK_CANCELLED_EXCEPTION(org.elasticsearch.tasks.TaskCancelledException.class,
788788
org.elasticsearch.tasks.TaskCancelledException::new, 146, Version.V_5_1_1_UNRELEASED),
789789
SHARD_LOCK_OBTAIN_FAILED_EXCEPTION(org.elasticsearch.env.ShardLockObtainFailedException.class,
790-
org.elasticsearch.env.ShardLockObtainFailedException::new, 147, Version.V_5_0_2);
790+
org.elasticsearch.env.ShardLockObtainFailedException::new, 147, Version.V_5_0_2),
791+
UNKNOWN_NAMED_OBJECT_EXCEPTION(org.elasticsearch.common.xcontent.NamedXContentRegistry.UnknownNamedObjectException.class,
792+
org.elasticsearch.common.xcontent.NamedXContentRegistry.UnknownNamedObjectException::new, 148, Version.V_5_2_0_UNRELEASED);
791793

792794
final Class<? extends ElasticsearchException> exceptionClass;
793795
final FunctionThatThrowsIOException<StreamInput, ? extends ElasticsearchException> constructor;

core/src/main/java/org/elasticsearch/ElasticsearchParseException.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424

2525
import java.io.IOException;
2626

27+
/**
28+
* Unchecked exception that is translated into a {@code 400 BAD REQUEST} error when it bubbles out over HTTP.
29+
*/
2730
public class ElasticsearchParseException extends ElasticsearchException {
2831

2932
public ElasticsearchParseException(String msg, Object... args) {

core/src/main/java/org/elasticsearch/action/admin/cluster/node/tasks/get/TransportGetTaskAction.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.elasticsearch.common.inject.Inject;
3636
import org.elasticsearch.common.settings.Settings;
3737
import org.elasticsearch.common.util.concurrent.AbstractRunnable;
38+
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
3839
import org.elasticsearch.common.xcontent.XContentHelper;
3940
import org.elasticsearch.common.xcontent.XContentParser;
4041
import org.elasticsearch.index.IndexNotFoundException;
@@ -67,14 +68,17 @@ public class TransportGetTaskAction extends HandledTransportAction<GetTaskReques
6768
private final ClusterService clusterService;
6869
private final TransportService transportService;
6970
private final Client client;
71+
private final NamedXContentRegistry xContentRegistry;
7072

7173
@Inject
7274
public TransportGetTaskAction(Settings settings, ThreadPool threadPool, TransportService transportService, ActionFilters actionFilters,
73-
IndexNameExpressionResolver indexNameExpressionResolver, ClusterService clusterService, Client client) {
75+
IndexNameExpressionResolver indexNameExpressionResolver, ClusterService clusterService, Client client,
76+
NamedXContentRegistry xContentRegistry) {
7477
super(settings, GetTaskAction.NAME, threadPool, transportService, actionFilters, indexNameExpressionResolver, GetTaskRequest::new);
7578
this.clusterService = clusterService;
7679
this.transportService = transportService;
7780
this.client = client;
81+
this.xContentRegistry = xContentRegistry;
7882
}
7983

8084
@Override
@@ -246,7 +250,7 @@ void onGetFinishedTaskFromIndex(GetResponse response, ActionListener<GetTaskResp
246250
listener.onFailure(new ElasticsearchException("Stored task status for [{}] didn't contain any source!", response.getId()));
247251
return;
248252
}
249-
try (XContentParser parser = XContentHelper.createParser(response.getSourceAsBytesRef())) {
253+
try (XContentParser parser = XContentHelper.createParser(xContentRegistry, response.getSourceAsBytesRef())) {
250254
TaskResult result = TaskResult.PARSER.apply(parser, () -> ParseFieldMatcher.STRICT);
251255
listener.onResponse(new GetTaskResponse(result));
252256
}

core/src/main/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequest.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.elasticsearch.common.io.stream.StreamInput;
3636
import org.elasticsearch.common.io.stream.StreamOutput;
3737
import org.elasticsearch.common.settings.Settings;
38+
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
3839
import org.elasticsearch.common.xcontent.XContentBuilder;
3940
import org.elasticsearch.common.xcontent.XContentFactory;
4041
import org.elasticsearch.common.xcontent.XContentHelper;
@@ -307,7 +308,8 @@ public CreateIndexRequest aliases(String source) {
307308
* Sets the aliases that will be associated with the index when it gets created
308309
*/
309310
public CreateIndexRequest aliases(BytesReference source) {
310-
try (XContentParser parser = XContentHelper.createParser(source)) {
311+
// EMPTY is safe here because we never call namedObject
312+
try (XContentParser parser = XContentHelper.createParser(NamedXContentRegistry.EMPTY, source)) {
311313
//move to the first alias
312314
parser.nextToken();
313315
while ((parser.nextToken()) != XContentParser.Token.END_OBJECT) {
@@ -361,11 +363,7 @@ public CreateIndexRequest source(byte[] source, int offset, int length) {
361363
public CreateIndexRequest source(BytesReference source) {
362364
XContentType xContentType = XContentFactory.xContentType(source);
363365
if (xContentType != null) {
364-
try (XContentParser parser = XContentFactory.xContent(xContentType).createParser(source)) {
365-
source(parser.map());
366-
} catch (IOException e) {
367-
throw new ElasticsearchParseException("failed to parse source for create index", e);
368-
}
366+
source(XContentHelper.convertToMap(source, false).v2());
369367
} else {
370368
settings(source.utf8ToString());
371369
}

core/src/main/java/org/elasticsearch/action/admin/indices/template/put/PutIndexTemplateRequest.java

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.elasticsearch.common.logging.DeprecationLogger;
3737
import org.elasticsearch.common.logging.Loggers;
3838
import org.elasticsearch.common.settings.Settings;
39+
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
3940
import org.elasticsearch.common.xcontent.XContentBuilder;
4041
import org.elasticsearch.common.xcontent.XContentFactory;
4142
import org.elasticsearch.common.xcontent.XContentHelper;
@@ -351,11 +352,7 @@ public PutIndexTemplateRequest source(Map templateSource) {
351352
* The template source definition.
352353
*/
353354
public PutIndexTemplateRequest source(String templateSource) {
354-
try (XContentParser parser = XContentFactory.xContent(templateSource).createParser(templateSource)) {
355-
return source(parser.mapOrdered());
356-
} catch (Exception e) {
357-
throw new IllegalArgumentException("failed to parse template source [" + templateSource + "]", e);
358-
}
355+
return source(XContentHelper.convertToMap(XContentFactory.xContent(templateSource), templateSource, true));
359356
}
360357

361358
/**
@@ -369,22 +366,14 @@ public PutIndexTemplateRequest source(byte[] source) {
369366
* The template source definition.
370367
*/
371368
public PutIndexTemplateRequest source(byte[] source, int offset, int length) {
372-
try (XContentParser parser = XContentFactory.xContent(source, offset, length).createParser(source, offset, length)) {
373-
return source(parser.mapOrdered());
374-
} catch (IOException e) {
375-
throw new IllegalArgumentException("failed to parse template source", e);
376-
}
369+
return source(new BytesArray(source, offset, length));
377370
}
378371

379372
/**
380373
* The template source definition.
381374
*/
382375
public PutIndexTemplateRequest source(BytesReference source) {
383-
try (XContentParser parser = XContentFactory.xContent(source).createParser(source)) {
384-
return source(parser.mapOrdered());
385-
} catch (IOException e) {
386-
throw new IllegalArgumentException("failed to parse template source", e);
387-
}
376+
return source(XContentHelper.convertToMap(source, true).v2());
388377
}
389378

390379
public PutIndexTemplateRequest custom(IndexMetaData.Custom custom) {
@@ -432,7 +421,8 @@ public PutIndexTemplateRequest aliases(String source) {
432421
* Sets the aliases that will be associated with the index when it gets created
433422
*/
434423
public PutIndexTemplateRequest aliases(BytesReference source) {
435-
try (XContentParser parser = XContentHelper.createParser(source)) {
424+
// EMPTY is safe here because we never call namedObject
425+
try (XContentParser parser = XContentHelper.createParser(NamedXContentRegistry.EMPTY, source)) {
436426
//move to the first alias
437427
parser.nextToken();
438428
while ((parser.nextToken()) != XContentParser.Token.END_OBJECT) {

core/src/main/java/org/elasticsearch/action/bulk/BulkRequest.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.elasticsearch.common.logging.Loggers;
4040
import org.elasticsearch.common.lucene.uid.Versions;
4141
import org.elasticsearch.common.unit.TimeValue;
42+
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
4243
import org.elasticsearch.common.xcontent.XContent;
4344
import org.elasticsearch.common.xcontent.XContentFactory;
4445
import org.elasticsearch.common.xcontent.XContentParser;
@@ -283,7 +284,8 @@ public BulkRequest add(BytesReference data, @Nullable String defaultIndex, @Null
283284
line++;
284285

285286
// now parse the action
286-
try (XContentParser parser = xContent.createParser(data.slice(from, nextMarker - from))) {
287+
// EMPTY is safe here because we never call namedObject
288+
try (XContentParser parser = xContent.createParser(NamedXContentRegistry.EMPTY, data.slice(from, nextMarker - from))) {
287289
// move pointers
288290
from = nextMarker + 1;
289291

@@ -400,7 +402,8 @@ public BulkRequest add(BytesReference data, @Nullable String defaultIndex, @Null
400402
.version(version).versionType(versionType)
401403
.routing(routing)
402404
.parent(parent);
403-
try (XContentParser sliceParser = xContent.createParser(data.slice(from, nextMarker - from))) {
405+
// EMPTY is safe here because we never call namedObject
406+
try (XContentParser sliceParser = xContent.createParser(NamedXContentRegistry.EMPTY, data.slice(from, nextMarker - from))) {
404407
updateRequest.fromXContent(sliceParser);
405408
}
406409
if (fetchSourceContext != null) {

core/src/main/java/org/elasticsearch/client/transport/TransportClient.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import org.elasticsearch.common.transport.TransportAddress;
4242
import org.elasticsearch.common.unit.TimeValue;
4343
import org.elasticsearch.common.util.BigArrays;
44+
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
4445
import org.elasticsearch.indices.breaker.CircuitBreakerService;
4546
import org.elasticsearch.node.Node;
4647
import org.elasticsearch.node.internal.InternalSettingsPreparer;
@@ -63,8 +64,11 @@
6364
import java.util.Collections;
6465
import java.util.List;
6566
import java.util.concurrent.TimeUnit;
67+
import java.util.function.Function;
6668
import java.util.stream.Collectors;
69+
import java.util.stream.Stream;
6770

71+
import static java.util.stream.Collectors.toList;
6872
import static org.elasticsearch.common.unit.TimeValue.timeValueSeconds;
6973

7074
/**
@@ -140,6 +144,11 @@ private static ClientTemplate buildTemplate(Settings providedSettings, Settings
140144
.flatMap(p -> p.getNamedWriteables().stream())
141145
.collect(Collectors.toList()));
142146
NamedWriteableRegistry namedWriteableRegistry = new NamedWriteableRegistry(entries);
147+
NamedXContentRegistry xContentRegistry = new NamedXContentRegistry(Stream.of(
148+
searchModule.getNamedXContents().stream(),
149+
pluginsService.filterPlugins(Plugin.class).stream()
150+
.flatMap(p -> p.getNamedXContent().stream())
151+
).flatMap(Function.identity()).collect(toList()));
143152

144153
ModulesBuilder modules = new ModulesBuilder();
145154
// plugin modules must be added here, before others or we can get crazy injection errors...
@@ -158,7 +167,7 @@ private static ClientTemplate buildTemplate(Settings providedSettings, Settings
158167
resourcesToClose.add(bigArrays);
159168
modules.add(settingsModule);
160169
NetworkModule networkModule = new NetworkModule(settings, true, pluginsService.filterPlugins(NetworkPlugin.class), threadPool,
161-
bigArrays, circuitBreakerService, namedWriteableRegistry, networkService);
170+
bigArrays, circuitBreakerService, namedWriteableRegistry, xContentRegistry, networkService);
162171
final Transport transport = networkModule.getTransportSupplier().get();
163172
final TransportService transportService = new TransportService(settings, transport, threadPool,
164173
networkModule.getTransportInterceptor(), null);

core/src/main/java/org/elasticsearch/cluster/ClusterState.java

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.carrotsearch.hppc.cursors.IntObjectCursor;
2323
import com.carrotsearch.hppc.cursors.ObjectCursor;
2424
import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
25+
2526
import org.elasticsearch.cluster.block.ClusterBlock;
2627
import org.elasticsearch.cluster.block.ClusterBlocks;
2728
import org.elasticsearch.cluster.metadata.IndexMetaData;
@@ -40,6 +41,7 @@
4041
import org.elasticsearch.common.Nullable;
4142
import org.elasticsearch.common.Strings;
4243
import org.elasticsearch.common.UUIDs;
44+
import org.elasticsearch.common.bytes.BytesArray;
4345
import org.elasticsearch.common.bytes.BytesReference;
4446
import org.elasticsearch.common.collect.ImmutableOpenMap;
4547
import org.elasticsearch.common.compress.CompressedXContent;
@@ -49,8 +51,7 @@
4951
import org.elasticsearch.common.settings.Settings;
5052
import org.elasticsearch.common.xcontent.ToXContent;
5153
import org.elasticsearch.common.xcontent.XContentBuilder;
52-
import org.elasticsearch.common.xcontent.XContentFactory;
53-
import org.elasticsearch.common.xcontent.XContentParser;
54+
import org.elasticsearch.common.xcontent.XContentHelper;
5455
import org.elasticsearch.discovery.Discovery;
5556
import org.elasticsearch.discovery.zen.PublishClusterStateAction;
5657

@@ -403,11 +404,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
403404

404405
builder.startObject("mappings");
405406
for (ObjectObjectCursor<String, CompressedXContent> cursor1 : templateMetaData.mappings()) {
406-
byte[] mappingSource = cursor1.value.uncompressed();
407-
Map<String, Object> mapping;
408-
try (XContentParser parser = XContentFactory.xContent(mappingSource).createParser(mappingSource)) {
409-
mapping = parser.map();
410-
}
407+
Map<String, Object> mapping = XContentHelper.convertToMap(new BytesArray(cursor1.value.uncompressed()), false).v2();
411408
if (mapping.size() == 1 && mapping.containsKey(cursor1.key)) {
412409
// the type name is the root value, reduce it
413410
mapping = (Map<String, Object>) mapping.get(cursor1.key);
@@ -435,11 +432,8 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
435432

436433
builder.startObject("mappings");
437434
for (ObjectObjectCursor<String, MappingMetaData> cursor : indexMetaData.getMappings()) {
438-
byte[] mappingSource = cursor.value.source().uncompressed();
439-
Map<String, Object> mapping;
440-
try (XContentParser parser = XContentFactory.xContent(mappingSource).createParser(mappingSource)) {
441-
mapping = parser.map();
442-
}
435+
Map<String, Object> mapping = XContentHelper
436+
.convertToMap(new BytesArray(cursor.value.source().uncompressed()), false).v2();
443437
if (mapping.size() == 1 && mapping.containsKey(cursor.key)) {
444438
// the type name is the root value, reduce it
445439
mapping = (Map<String, Object>) mapping.get(cursor.key);

core/src/main/java/org/elasticsearch/cluster/metadata/AliasMetaData.java

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@
2222
import org.elasticsearch.ElasticsearchGenerationException;
2323
import org.elasticsearch.cluster.AbstractDiffable;
2424
import org.elasticsearch.common.Strings;
25+
import org.elasticsearch.common.bytes.BytesArray;
2526
import org.elasticsearch.common.compress.CompressedXContent;
2627
import org.elasticsearch.common.io.stream.StreamInput;
2728
import org.elasticsearch.common.io.stream.StreamOutput;
2829
import org.elasticsearch.common.xcontent.ToXContent;
2930
import org.elasticsearch.common.xcontent.XContentBuilder;
3031
import org.elasticsearch.common.xcontent.XContentFactory;
32+
import org.elasticsearch.common.xcontent.XContentHelper;
3133
import org.elasticsearch.common.xcontent.XContentParser;
3234

3335
import java.io.IOException;
@@ -225,14 +227,7 @@ public Builder filter(String filter) {
225227
this.filter = null;
226228
return this;
227229
}
228-
try {
229-
try (XContentParser parser = XContentFactory.xContent(filter).createParser(filter)) {
230-
filter(parser.mapOrdered());
231-
}
232-
return this;
233-
} catch (IOException e) {
234-
throw new ElasticsearchGenerationException("Failed to generate [" + filter + "]", e);
235-
}
230+
return filter(XContentHelper.convertToMap(XContentFactory.xContent(filter), filter, true));
236231
}
237232

238233
public Builder filter(Map<String, Object> filter) {
@@ -286,11 +281,7 @@ public static void toXContent(AliasMetaData aliasMetaData, XContentBuilder build
286281
if (binary) {
287282
builder.field("filter", aliasMetaData.filter.compressed());
288283
} else {
289-
byte[] data = aliasMetaData.filter().uncompressed();
290-
try (XContentParser parser = XContentFactory.xContent(data).createParser(data)) {
291-
Map<String, Object> filter = parser.mapOrdered();
292-
builder.field("filter", filter);
293-
}
284+
builder.field("filter", XContentHelper.convertToMap(new BytesArray(aliasMetaData.filter().uncompressed()), true).v2());
294285
}
295286
}
296287
if (aliasMetaData.indexRouting() != null) {

0 commit comments

Comments
 (0)