forked from elastic/elasticsearch
-
Notifications
You must be signed in to change notification settings - Fork 1
WIP media type registry with singleton instance #24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
pgomulka
wants to merge
7
commits into
compat_plugin_inside_rest_request
Choose a base branch
from
compat/media_type_registry
base: compat_plugin_inside_rest_request
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from 1 commit
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
ed14aae
media type registry with singleton instance
pgomulka 1b0c1d2
pull supported media types, but push down registry
pgomulka 7bdf64f
cleanup
pgomulka ff93fd2
remove mediatypedefinition
pgomulka f5c60ff
passing a mediatyperegistry to plugin, but keeping the signature the …
pgomulka 5ad227a
do not use global media type registry in sql
pgomulka 58d1103
Merge branch 'compat/pull_supported_media_types' into compat/media_ty…
pgomulka File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
54 changes: 54 additions & 0 deletions
54
libs/x-content/src/main/java/org/elasticsearch/common/xcontent/MediaTypeRegistry.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| /* | ||
| * Licensed to Elasticsearch under one or more contributor | ||
| * license agreements. See the NOTICE file distributed with | ||
| * this work for additional information regarding copyright | ||
| * ownership. Elasticsearch licenses this file to you under | ||
| * the Apache License, Version 2.0 (the "License"); you may | ||
| * not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, | ||
| * software distributed under the License is distributed on an | ||
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| * KIND, either express or implied. See the License for the | ||
| * specific language governing permissions and limitations | ||
| * under the License. | ||
| */ | ||
|
|
||
| package org.elasticsearch.common.xcontent; | ||
|
|
||
| import java.util.Map; | ||
| import java.util.concurrent.ConcurrentHashMap; | ||
| import java.util.regex.Pattern; | ||
|
|
||
| public class MediaTypeRegistry { | ||
| private static final MediaTypeRegistry INSTANCE = new MediaTypeRegistry(); | ||
| private Map<String, MediaType> formatToMediaType = new ConcurrentHashMap<>(); | ||
| private Map<String, MediaType> typeWithSubtypeToMediaType = new ConcurrentHashMap<>(); | ||
| private Map<String, Map<String, Pattern>> parametersMap= new ConcurrentHashMap<>(); | ||
|
|
||
| public static MediaTypeRegistry getInstance() { | ||
| return INSTANCE; | ||
| } | ||
|
|
||
| public <T extends MediaType> void register(Map<String, T> formatToMediaType, Map<String, T> typeWithSubtypeToMediaType, Map<String, Map<String, Pattern>> parametersMap) { | ||
| this.formatToMediaType.putAll(formatToMediaType); | ||
| this.typeWithSubtypeToMediaType.putAll(typeWithSubtypeToMediaType); | ||
| this.parametersMap.putAll(parametersMap); | ||
| } | ||
|
|
||
|
|
||
| public MediaType formatToMediaType(String format) { | ||
| return formatToMediaType.get(format); | ||
| } | ||
|
|
||
| public MediaType typeWithSubtypeToMediaType(String typeWithSubtype) { | ||
| return typeWithSubtypeToMediaType.get(typeWithSubtype); | ||
| } | ||
|
|
||
| public Map<String, Pattern> parametersFor(String typeWithSubtype) { | ||
| return parametersMap.get(typeWithSubtype); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks like it works..
do plugins' classloader inherit classloader from main server?
but I am not super sure about the design of this too. It is a static common instance. Probably not ideal.
But on the other hand I don't want to try injecting this from Node class..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not a big fan of the singleton, nor a static approach. Globals should generally be avoided.
yeah, they are children and can see the main loader, but not other plugins
Taking a step back ... we really trying to take a string and find the associated mime type and all the associated parameters. However, not all mime types are valid for all APIs ... for example, we don't want to support application/txt for _search, and need to avoid registering application/txt such that a request coming through for _search would be valid. Since we are heading to a more strict support, i believe that strict support needs to be tightly coupled to the
Routeie. /_search vs. /_sql. Therefor, I think the concept of a registry needs to be associated with the route and the backing state probably in BaseRestHandler or RestControler.We can probably default the standard and compat media types to avoid too much copy,pasta but it would allow per route to opt-in/out of compatibility. There might be some mimatch in the supported accept vs. supported content-type's ...but I would not worry about that for now.
This requires moving where the header -> ParsedMedia type happens, for that I am not sure ... it can happen really early in the processing , even before handleRequest. maybe in dispacthRequest (request.addParsedMediaType(mediaParser.parse(handler.getSupportedMediaTypes())))?
I think by "registering" the supported media types that is tightly coupled to the Route will help in the long term with stricter parsing.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think mapping of media types with API endpoints is something in addition to a "media type registry"
Correlating allowed media types with routes would be a bigger refactoring. It would fit into Make media type parsing strict #63080
The compatible api plugin PR (which requires a media type registry) and Make media type parsing strict I feel are separate. It is a question if this should be worked on first?
On the registry and where it should live:
Problem with making it an instance within RestController or BaseRestHandler would require to pass that registry instance to many other places (wherever XContentType/TextFormat are created)
I agree that making it static is not great, but XContentType is an enum and its creation methods are static (
fromFormatorfromMediaType) . Because of this, registry will have to be accessed from a static context anyway.XContentTypecan access a static field (like in this PR - a staticMediaTypeParserfield on XcontentType access a static field onMediaTypeRegistry)or from a
Nodeclass will set a static field on aXContentType.WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My take is that we should not introduce a global static like this and to keep the concerns separate.
For registration of media types, we can have a registry but this should never be passed to plugins; instead we should pull from plugins. This may mean there are inefficiencies but I think we will be much happier with the code.
For plugins, we pull additional media types:
For rest handlers we define supported media types:
For parsing, we maintain a
MediaTypeParserthat is built from the values pulled from plugins and XContentType and put the parsed values (MediaType) on the request for both content type and accept (output type). Our code will now need to map fromMediaTypetoXContentTypeorTextFormat. Those mappings should be handled withinXContentTypeandTextFormatwith afromMediaType(MediaType)method.In terms of other changes that may make sense with this suggestion, I would consider changing the compatible plugin API to use the parsed values for media type rather than the raw strings.
Once we start enforcing what we accept for these values including parameters, then the RestController can check this against the set of values defined by the handler.
I think there are some holes in my idea, but if you like it I am happy to chat more about it.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I see what you mean.
In your idea I think we still miss the part where we share the instance of MediaTypeRegistry with other
"clients"(XContentType or TextFormat or CompatibleVersionPlugin).The idea looks similar to what we do with DiscoveryNode.additionalRoles
This mean that we still have to maintain a static global variable where we will store all of the additional media types. (may be encapsulated within MediaTypeRegistry). It is easy to set this on
XContentTypein aNodeclass with sth like XContentType.setMediaTypeRegistry (invoked very early in the Node constructor)That means that XContentType would have to have a static variable to store a MediaTypeRegistry
TextFormatwould have to reach to the same instance of media type registry (XContentTYpe.getMediaTypeRgistry ?).The same applies to
CompatibleVersionPluginwhere we don't define a new media types, but we want to have access to all defined media types (including additional ones from other plugins like sql)Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CompatibleVersionPlugin has to be able to parse all the media types, including those defined in other plugins.
For instance.
plain/textmedia type is defined in SQL plugin, we can pull it from it from that plugin on startup usinggetAdditionalMediaTypes.To allow
CompatibleVersionPluginto perform all the validations it is doing now, it has to be able to parse media types defined by SQLWhy you wanted to avoid sharing MediaTypeRegistry ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mainly to avoid having one more class passed around everywhere.
I understand that
CompatibleVersionPluginneeds the media types; could we not pass it theParsedMediaTypeobjects and have it operate off of that? This way we keep our media type parsing out of this as well and only the output object is consumed by theCompatibleVersionPlugin?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will give it a go and create a draft pr
to me it looks it very similar. Instead of passing down
MediaTypeRegistryto a plugin we would have to pass it down toRestController.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jaymode I updated current PR with the approach where we pull the supported media types.
I no longer set them on a plugin with just a setter. I have changed the plugin to expect a media type registry.
This is not visible as I have hidden that when creating a lambda that is passed under
CompatibleVersioninterfaceLet me know what you think
This of course does not addresses @jakelandis points on per route parsing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I opened #27 as a idea of what I think we can do to just use the parsed values