org.elasticsearch.rest.RestHandler Maven / Gradle / Ivy
Show all versions of elasticsearch Show documentation
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
package org.elasticsearch.rest;
import org.apache.logging.log4j.Level;
import org.elasticsearch.client.internal.node.NodeClient;
import org.elasticsearch.core.Nullable;
import org.elasticsearch.core.RestApiVersion;
import org.elasticsearch.rest.RestRequest.Method;
import org.elasticsearch.xcontent.XContent;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
/**
* Handler for REST requests
*/
@FunctionalInterface
public interface RestHandler {
/**
* Handles a rest request.
* @param request The request to handle
* @param channel The channel to write the request response to
* @param client A client to use to make internal requests on behalf of the original request
*/
void handleRequest(RestRequest request, RestChannel channel, NodeClient client) throws Exception;
default boolean canTripCircuitBreaker() {
return true;
}
/**
* Indicates if the RestHandler supports content as a stream. A stream would be multiple objects delineated by
* {@link XContent#streamSeparator()}. If a handler returns true this will affect the types of content that can be sent to
* this endpoint.
*/
default boolean supportsContentStream() {
return false;
}
/**
* Returns the concrete RestHandler for this RestHandler. That is, if this is a delegating RestHandler it returns the delegate.
* Otherwise it returns itself.
* @return The underlying RestHandler
*/
default RestHandler getConcreteRestHandler() {
return this;
}
/**
* Returns the serverless Scope of this RestHandler. This is only meaningful when running in a servlerless environment. If a
* RestHandler has no ServerlessScope annotation, then this method returns null, meaning that this RestHandler is not visible at all in
* Serverless mode.
* @return The Scope for this handler, or null if there is no ServerlessScope annotation
*/
default Scope getServerlessScope() {
ServerlessScope serverlessScope = getConcreteRestHandler().getClass().getAnnotation(ServerlessScope.class);
return serverlessScope == null ? null : serverlessScope.value();
}
/**
* Indicates if the RestHandler supports working with pooled buffers. If the request handler will not escape the return
* {@link RestRequest#content()} or any buffers extracted from it then there is no need to make a copies of any pooled buffers in the
* {@link RestRequest} instance before passing a request to this handler. If this instance does not support pooled/unsafe buffers
* {@link RestRequest#ensureSafeBuffers()} should be called on any request before passing it to {@link #handleRequest}.
*
* @return true iff the handler supports requests that make use of pooled buffers
*/
default boolean allowsUnsafeBuffers() {
return false;
}
/**
* The list of {@link Route}s that this RestHandler is responsible for handling.
*/
default List routes() {
return Collections.emptyList();
}
/**
* Controls whether requests handled by this class are allowed to to access system indices by default.
* @return {@code true} if requests handled by this class should be allowed to access system indices.
*/
default boolean allowSystemIndexAccessByDefault() {
return false;
}
default boolean mediaTypesValid(RestRequest request) {
return request.getXContentType() != null;
}
class Route {
private final Method method;
private final String path;
private final RestApiVersion restApiVersion;
private final String deprecationMessage;
@Nullable
private final Level deprecationLevel;
private final Route replacedRoute;
private Route(
Method method,
String path,
RestApiVersion restApiVersion,
String deprecationMessage,
Level deprecationLevel,
Route replacedRoute
) {
this.method = Objects.requireNonNull(method);
this.path = Objects.requireNonNull(path);
this.restApiVersion = Objects.requireNonNull(restApiVersion);
// a deprecated route will have a deprecation message, and the restApiVersion
// will represent the version when the route was deprecated
this.deprecationMessage = deprecationMessage;
this.deprecationLevel = deprecationLevel;
// a route that replaces another route will have a reference to the route that was replaced
this.replacedRoute = replacedRoute;
}
/**
* Constructs a Route that pairs an HTTP method with an associated path.
*
* This is sufficient for most routes in Elasticsearch, like "GET /", "PUT /_cluster/settings", or "POST my_index/_close".
*
* @param method the method, e.g. GET
* @param path the path, e.g. "/"
*/
public Route(Method method, String path) {
this(method, path, RestApiVersion.current(), null, null, null);
}
public static class RouteBuilder {
private final Method method;
private final String path;
private RestApiVersion restApiVersion;
private String deprecationMessage;
@Nullable
private Level deprecationLevel;
private Route replacedRoute;
private RouteBuilder(Method method, String path) {
this.method = Objects.requireNonNull(method);
this.path = Objects.requireNonNull(path);
this.restApiVersion = RestApiVersion.current();
}
/**
* Marks that the route being built has been deprecated (for some reason -- the deprecationMessage), and notes the major
* version in which that deprecation occurred.
*
* For example:
*
{@code
* Route.builder(GET, "_upgrade")
* .deprecated("The _upgrade API is no longer useful and will be removed.", RestApiVersion.V_7)
* .build()}
*
* @param deprecationMessage the user-visible explanation of this deprecation
* @param deprecatedInVersion the major version in which the deprecation occurred
* @return a reference to this object.
*/
public RouteBuilder deprecated(String deprecationMessage, RestApiVersion deprecatedInVersion) {
assert this.replacedRoute == null;
this.restApiVersion = Objects.requireNonNull(deprecatedInVersion);
this.deprecationMessage = Objects.requireNonNull(deprecationMessage);
return this;
}
/**
* Marks that the route being built has been deprecated (for some reason -- the deprecationMessage), and notes the major
* version in which that deprecation occurred.
*
* For example:
*
{@code
* Route.builder(GET, "_upgrade")
* .deprecated("The _upgrade API is no longer useful and will be removed.", RestApiVersion.V_7)
* .build()}
*
* @param deprecationMessage the user-visible explanation of this deprecation
* @param deprecationLevel the level at which to log the deprecation
* @param deprecatedInVersion the major version in which the deprecation occurred
* @return a reference to this object.
*/
public RouteBuilder deprecated(String deprecationMessage, Level deprecationLevel, RestApiVersion deprecatedInVersion) {
assert this.replacedRoute == null;
this.restApiVersion = Objects.requireNonNull(deprecatedInVersion);
this.deprecationMessage = Objects.requireNonNull(deprecationMessage);
this.deprecationLevel = deprecationLevel;
return this;
}
/**
* Marks that the route being built replaces another route, and notes the major version in which that replacement occurred.
*
* For example:
*
{@code
* Route.builder(GET, "/_security/user/")
* .replaces(GET, "/_xpack/security/user/", RestApiVersion.V_7).build()}
*
* @param method the method being replaced
* @param path the path being replaced
* @param replacedInVersion the major version in which the replacement occurred
* @return a reference to this object.
*/
public RouteBuilder replaces(Method method, String path, RestApiVersion replacedInVersion) {
assert this.deprecationMessage == null;
this.replacedRoute = new Route(method, path, replacedInVersion, null, null, null);
return this;
}
public Route build() {
if (replacedRoute != null) {
return new Route(method, path, restApiVersion, null, null, replacedRoute);
} else if (deprecationMessage != null) {
return new Route(method, path, restApiVersion, deprecationMessage, deprecationLevel, null);
} else {
// this is a little silly, but perfectly legal
return new Route(method, path, restApiVersion, null, null, null);
}
}
}
public static RouteBuilder builder(Method method, String path) {
return new RouteBuilder(method, path);
}
public String getPath() {
return path;
}
public Method getMethod() {
return method;
}
public RestApiVersion getRestApiVersion() {
return restApiVersion;
}
public String getDeprecationMessage() {
return deprecationMessage;
}
@Nullable
public Level getDeprecationLevel() {
return deprecationLevel;
}
public boolean isDeprecated() {
return deprecationMessage != null;
}
public Route getReplacedRoute() {
return replacedRoute;
}
public boolean isReplacement() {
return replacedRoute != null;
}
}
}