diff --git a/src/main/java/org/opensearch/sdk/ExtensionsRunner.java b/src/main/java/org/opensearch/sdk/ExtensionsRunner.java index 09bd50bd..e023b600 100644 --- a/src/main/java/org/opensearch/sdk/ExtensionsRunner.java +++ b/src/main/java/org/opensearch/sdk/ExtensionsRunner.java @@ -46,6 +46,7 @@ import org.opensearch.sdk.handlers.ExtensionsInitRequestHandler; import org.opensearch.sdk.handlers.ExtensionsRestRequestHandler; import org.opensearch.sdk.handlers.UpdateSettingsRequestHandler; +import org.opensearch.sdk.rest.ExtensionRestPathRegistry; import org.opensearch.tasks.TaskManager; import org.opensearch.threadpool.ExecutorBuilder; import org.opensearch.threadpool.RunnableTaskExecutionListener; diff --git a/src/main/java/org/opensearch/sdk/handlers/ExtensionsRestRequestHandler.java b/src/main/java/org/opensearch/sdk/handlers/ExtensionsRestRequestHandler.java index e0e5a741..a4380ad3 100644 --- a/src/main/java/org/opensearch/sdk/handlers/ExtensionsRestRequestHandler.java +++ b/src/main/java/org/opensearch/sdk/handlers/ExtensionsRestRequestHandler.java @@ -18,11 +18,10 @@ import org.opensearch.sdk.ExtensionRestHandler; import org.opensearch.sdk.ExtensionsRunner; import org.opensearch.sdk.SDKNamedXContentRegistry; +import org.opensearch.sdk.rest.ExtensionRestPathRegistry; import org.opensearch.sdk.rest.SDKHttpRequest; import org.opensearch.sdk.rest.SDKRestRequest; -import org.opensearch.sdk.ExtensionRestPathRegistry; - import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Collections.emptyMap; import static java.util.Collections.emptyList; diff --git a/src/main/java/org/opensearch/sdk/ExtensionRestPathRegistry.java b/src/main/java/org/opensearch/sdk/rest/ExtensionRestPathRegistry.java similarity index 71% rename from src/main/java/org/opensearch/sdk/ExtensionRestPathRegistry.java rename to src/main/java/org/opensearch/sdk/rest/ExtensionRestPathRegistry.java index 4b23da6e..ff947dd8 100644 --- a/src/main/java/org/opensearch/sdk/ExtensionRestPathRegistry.java +++ b/src/main/java/org/opensearch/sdk/rest/ExtensionRestPathRegistry.java @@ -7,14 +7,16 @@ * compatible open source license. */ -package org.opensearch.sdk; +package org.opensearch.sdk.rest; import java.util.ArrayList; import java.util.List; +import org.opensearch.common.Nullable; import org.opensearch.common.path.PathTrie; import org.opensearch.rest.RestUtils; import org.opensearch.rest.RestRequest.Method; +import org.opensearch.sdk.ExtensionRestHandler; /** * This class registers REST paths from extension Rest Handlers. @@ -22,7 +24,7 @@ public class ExtensionRestPathRegistry { // PathTrie to match paths to handlers - private PathTrie pathTrie = new PathTrie<>(RestUtils.REST_DECODER); + private PathTrie pathTrie = new PathTrie<>(RestUtils.REST_DECODER); // List to return registered handlers private List registeredPaths = new ArrayList<>(); @@ -34,20 +36,25 @@ public class ExtensionRestPathRegistry { * @param extensionRestHandler The RestHandler to handle this route */ public void registerHandler(Method method, String path, ExtensionRestHandler extensionRestHandler) { - String restPath = restPathToString(method, path); - pathTrie.insert(restPath, extensionRestHandler); - registeredPaths.add(restPath); + pathTrie.insertOrUpdate( + path, + new SDKMethodHandlers(path, extensionRestHandler, method), + (mHandlers, newMHandler) -> mHandlers.addMethods(extensionRestHandler, method) + ); + registeredPaths.add(restPathToString(method, path)); } /** - * Get the registered REST handler for the specified method and URI. + * Get the registered REST handler for the specified method and path. * * @param method the registered method. * @param path the registered path. - * @return The REST handler registered to handle this method and URI combination if found, null otherwise. + * @return The REST handler registered to handle this method and path combination if found, null otherwise. */ + @Nullable public ExtensionRestHandler getHandler(Method method, String path) { - return pathTrie.retrieve(restPathToString(method, path)); + SDKMethodHandlers mHandlers = pathTrie.retrieve(path); + return mHandlers == null ? null : mHandlers.getHandler(method); } /** @@ -60,7 +67,9 @@ public List getRegisteredPaths() { } /** - * Converts a REST method and path to a space delimited string to be used as a map lookup key. + * Converts a REST method and path to a space delimited string. + *

+ * This provides convenience for logging and serialization over transport. * * @param method the method. * @param path the path. diff --git a/src/main/java/org/opensearch/sdk/rest/SDKMethodHandlers.java b/src/main/java/org/opensearch/sdk/rest/SDKMethodHandlers.java new file mode 100644 index 00000000..0adcf7b9 --- /dev/null +++ b/src/main/java/org/opensearch/sdk/rest/SDKMethodHandlers.java @@ -0,0 +1,67 @@ +/* + * Copyright OpenSearch Contributors + * 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.sdk.rest; + +import org.opensearch.common.Nullable; +import org.opensearch.sdk.ExtensionRestHandler; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import static org.opensearch.rest.RestRequest.Method; + +/** + * Encapsulate multiple handlers for the same path, allowing different handlers for different HTTP verbs. + *

+ * Used in SDK to provide identical path-matching functionality as OpenSearch, with Extension-based classes. + */ +final class SDKMethodHandlers { + + private final String path; + private final Map methodHandlers; + + SDKMethodHandlers(String path, ExtensionRestHandler handler, Method... methods) { + this.path = path; + this.methodHandlers = new HashMap<>(methods.length); + for (Method method : methods) { + methodHandlers.put(method, handler); + } + } + + /** + * Add a handler for an additional array of methods. Note that {@code SDKMethodHandlers} + * does not allow replacing the handler for an already existing method. + */ + SDKMethodHandlers addMethods(ExtensionRestHandler handler, Method... methods) { + for (Method method : methods) { + ExtensionRestHandler existing = methodHandlers.putIfAbsent(method, handler); + if (existing != null) { + throw new IllegalArgumentException("Cannot replace existing handler for [" + path + "] for method: " + method); + } + } + return this; + } + + /** + * Returns the handler for the given method or {@code null} if none exists. + */ + @Nullable + ExtensionRestHandler getHandler(Method method) { + return methodHandlers.get(method); + } + + /** + * Return a set of all valid HTTP methods for the particular path + */ + Set getValidMethods() { + return methodHandlers.keySet(); + } +} diff --git a/src/test/java/org/opensearch/sdk/TestExtensionRestPathRegistry.java b/src/test/java/org/opensearch/sdk/TestExtensionRestPathRegistry.java index db28a733..a438eacc 100644 --- a/src/test/java/org/opensearch/sdk/TestExtensionRestPathRegistry.java +++ b/src/test/java/org/opensearch/sdk/TestExtensionRestPathRegistry.java @@ -17,6 +17,7 @@ import org.opensearch.rest.RestHandler.Route; import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestRequest.Method; +import org.opensearch.sdk.rest.ExtensionRestPathRegistry; import org.opensearch.test.OpenSearchTestCase; public class TestExtensionRestPathRegistry extends OpenSearchTestCase { @@ -73,10 +74,10 @@ public void setUp() throws Exception { public void testRegisterConflicts() { // Can't register same exact name assertThrows(IllegalArgumentException.class, () -> extensionRestPathRegistry.registerHandler(Method.GET, "/foo", fooHandler)); - // Can't register conflicting named wildcards + // Can't register conflicting named wildcards, even if method is different assertThrows( IllegalArgumentException.class, - () -> extensionRestPathRegistry.registerHandler(Method.PUT, "/bar/{none}", barHandler) + () -> extensionRestPathRegistry.registerHandler(Method.GET, "/bar/{none}", barHandler) ); } diff --git a/src/test/java/org/opensearch/sdk/TestExtensionsRunner.java b/src/test/java/org/opensearch/sdk/TestExtensionsRunner.java index 01f796a0..075d8894 100644 --- a/src/test/java/org/opensearch/sdk/TestExtensionsRunner.java +++ b/src/test/java/org/opensearch/sdk/TestExtensionsRunner.java @@ -56,6 +56,7 @@ import org.opensearch.sdk.handlers.EnvironmentSettingsResponseHandler; import org.opensearch.sdk.handlers.ExtensionsInitRequestHandler; import org.opensearch.sdk.handlers.ExtensionsRestRequestHandler; +import org.opensearch.sdk.rest.ExtensionRestPathRegistry; import org.opensearch.sdk.handlers.AcknowledgedResponseHandler; import org.opensearch.test.OpenSearchTestCase; import org.opensearch.transport.Transport;