Skip to content
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

[Backport 2.x] Register MediaTypes through SPI #9045

Merged
merged 1 commit into from
Aug 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,16 @@

package org.opensearch.core.xcontent;

import org.opensearch.core.xcontent.spi.MediaTypeProvider;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
* Parses supported internet media types
Expand All @@ -48,7 +55,25 @@ public final class MediaTypeRegistry {
// Default mediaType singleton
private static MediaType DEFAULT_MEDIA_TYPE;

public static void register(MediaType[] acceptedMediaTypes, Map<String, MediaType> additionalMediaTypes) {
// JSON is a core type, so we create a static instance for implementations that require JSON format (e.g., tests)
// todo we should explore moving the concrete JSON implementation from the xcontent library to core
public static final MediaType JSON;

static {
List<MediaType> mediaTypes = new ArrayList<>();
Map<String, MediaType> amt = new HashMap<>();
for (MediaTypeProvider provider : ServiceLoader.load(MediaTypeProvider.class, MediaTypeProvider.class.getClassLoader())) {
mediaTypes.addAll(provider.getMediaTypes());
amt = Stream.of(amt, provider.getAdditionalMediaTypes())
.flatMap(map -> map.entrySet().stream())
.collect(Collectors.toUnmodifiableMap(Map.Entry::getKey, Map.Entry::getValue));
}
register(mediaTypes.toArray(new MediaType[0]), amt);
JSON = fromMediaType("application/json");
setDefaultMediaType(JSON);
}

private static void register(MediaType[] acceptedMediaTypes, Map<String, MediaType> additionalMediaTypes) {
// ensures the map is not overwritten:
Map<String, MediaType> typeMap = new HashMap<>(typeWithSubtypeToMediaType);
Map<String, MediaType> formatMap = new HashMap<>(formatToMediaType);
Expand Down Expand Up @@ -150,7 +175,7 @@ public Map<String, String> getParameters() {
}
}

public static void setDefaultMediaType(final MediaType mediaType) {
private static void setDefaultMediaType(final MediaType mediaType) {
if (DEFAULT_MEDIA_TYPE != null) {
throw new RuntimeException(
"unable to reset the default media type from current default [" + DEFAULT_MEDIA_TYPE + "] to [" + mediaType + "]"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.core.xcontent.spi;

import org.opensearch.core.xcontent.MediaType;

import java.util.List;
import java.util.Map;

/**
* Service Provider Interface for plugins, modules, extensions providing
* their own Media Types
*
* @opensearch.experimental
* @opensearch.api
*/
public interface MediaTypeProvider {
/** Extensions that implement their own concrete {@link MediaType}s provide them through this interface method */
List<MediaType> getMediaTypes();

/** Extensions that implement additional {@link MediaType} aliases provide them through this interface method */
Map<String, MediaType> getAdditionalMediaTypes();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

/** Service Provider Interface for extensible media types */
package org.opensearch.core.xcontent.spi;
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,9 @@
import org.opensearch.common.xcontent.yaml.YamlXContent;
import org.opensearch.core.common.io.stream.StreamOutput;
import org.opensearch.core.xcontent.MediaType;
import org.opensearch.core.xcontent.MediaTypeRegistry;
import org.opensearch.core.xcontent.XContent;

import java.io.IOException;
import java.util.Map;

/**
* The content type of {@link XContent}.
Expand Down Expand Up @@ -131,11 +129,6 @@ public XContent xContent() {
}
};

static {
/** a parser of media types */
MediaTypeRegistry.register(XContentType.values(), Map.of("application/*", JSON, "application/x-ndjson", JSON));
}

private int index;

XContentType(int index) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.common.xcontent.spi;

import org.opensearch.common.xcontent.XContentType;
import org.opensearch.core.xcontent.MediaType;
import org.opensearch.core.xcontent.spi.MediaTypeProvider;

import java.util.List;
import java.util.Map;

/**
* Media Type implementations provided by xcontent library
*
* @opensearch.internal
*/
public class XContentProvider implements MediaTypeProvider {
/** Returns the concrete {@link MediaType} provided by the xcontent library */
@Override
public List<MediaType> getMediaTypes() {
return List.of(XContentType.values());
}

/** Returns the additional {@link MediaType} aliases provided by the xcontent library */
@Override
public Map<String, MediaType> getAdditionalMediaTypes() {
return Map.of("application/*", XContentType.JSON, "application/x-ndjson", XContentType.JSON);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

/** SPI implementation for the xcontent library */
package org.opensearch.common.xcontent.spi;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#
# SPDX-License-Identifier: Apache-2.0
#
# The OpenSearch Contributors require contributions made to
# this file be licensed under the Apache-2.0 license or a
# compatible open source license.
#

org.opensearch.common.xcontent.spi.XContentProvider
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,8 @@
import org.opensearch.common.util.concurrent.ThreadContext;
import org.opensearch.common.util.io.IOUtils;
import org.opensearch.common.lease.Releasable;
import org.opensearch.common.xcontent.XContentType;
import org.opensearch.core.common.Strings;
import org.opensearch.core.concurrency.OpenSearchRejectedExecutionException;
import org.opensearch.core.xcontent.MediaTypeRegistry;
import org.opensearch.node.NodeClosedException;
import org.opensearch.node.ReportingService;
import org.opensearch.tasks.Task;
Expand Down Expand Up @@ -176,8 +174,6 @@ public void close() {}
Streamables.registerStreamables();
/** Registers OpenSearch server specific exceptions (exceptions outside of core library) */
OpenSearchServerException.registerExceptions();
// set the default media type to JSON (fallback if a media type is not specified)
MediaTypeRegistry.setDefaultMediaType(XContentType.JSON);
}

/** does nothing. easy way to ensure class is loaded so the above static block is called to register the streamables */
Expand Down