io.servicetalk.grpc.api.GrpcRoutes Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of servicetalk-grpc-api Show documentation
Show all versions of servicetalk-grpc-api Show documentation
A networking framework that evolves with your application
/*
* Copyright © 2019 Apple Inc. and the ServiceTalk project authors
*
* Licensed 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 io.servicetalk.grpc.api;
import io.servicetalk.concurrent.BlockingIterable;
import io.servicetalk.concurrent.GracefulAutoCloseable;
import io.servicetalk.concurrent.api.AsyncCloseable;
import io.servicetalk.concurrent.api.Completable;
import io.servicetalk.concurrent.api.Publisher;
import io.servicetalk.concurrent.api.Single;
import io.servicetalk.grpc.api.GrpcRouter.RouteProviders;
import io.servicetalk.grpc.api.GrpcServiceFactory.ServerBinder;
import io.servicetalk.http.api.HttpExecutionStrategies;
import io.servicetalk.router.api.RouteExecutionStrategy;
import io.servicetalk.router.api.RouteExecutionStrategyFactory;
import io.servicetalk.transport.api.ExecutionContext;
import io.servicetalk.transport.api.ServerContext;
import java.lang.reflect.Method;
import java.util.Set;
import java.util.TreeSet;
import javax.annotation.Nullable;
import static io.servicetalk.concurrent.api.Completable.completed;
import static io.servicetalk.grpc.api.GrpcExecutionStrategies.noOffloadsStrategy;
import static io.servicetalk.router.utils.internal.DefaultRouteExecutionStrategyFactory.defaultStrategyFactory;
import static io.servicetalk.router.utils.internal.RouteExecutionStrategyUtils.getAndValidateRouteExecutionStrategyAnnotationIfPresent;
import static io.servicetalk.utils.internal.ReflectionUtils.retrieveMethod;
/**
* A holder of gRPC routes that constitutes a service.
*
* @param Type for service that these routes represent.
*/
public abstract class GrpcRoutes {
private static final GrpcExecutionStrategy NULL = new DefaultGrpcExecutionStrategy(
HttpExecutionStrategies.noOffloadsStrategy());
private final GrpcRouter.Builder routeBuilder;
private final Set errors;
private final RouteExecutionStrategyFactory strategyFactory;
/**
* Create a new instance.
*/
protected GrpcRoutes() {
this(defaultStrategyFactory());
}
/**
* Create new instance.
*
* @param strategyFactory a
* {@link RouteExecutionStrategyFactory RouteExecutionStrategyFactory<GrpcExecutionStrategy>} for creating
* {@link GrpcExecutionStrategy} instances that can be used for offloading the handling of request to resource
* methods, as specified via {@link RouteExecutionStrategy} annotation
*/
protected GrpcRoutes(final RouteExecutionStrategyFactory strategyFactory) {
routeBuilder = new GrpcRouter.Builder();
errors = new TreeSet<>();
this.strategyFactory = strategyFactory;
}
private GrpcRoutes(final GrpcRouter.Builder routeBuilder, final Set errors) {
this.routeBuilder = routeBuilder;
this.errors = errors;
strategyFactory = defaultStrategyFactory();
}
/**
* Use the passed {@link ServerBinder} to bind an appropriate
* gRPC service for the server.
*
* @param binder {@link ServerBinder} to bind gRPC service to the server.
* @param executionContext {@link ExecutionContext} to use for the service.
* @return A {@link Single} that completes when the server is successfully started or terminates with an error if
* the server could not be started.
*/
final Single bind(final ServerBinder binder, final ExecutionContext executionContext) {
if (!errors.isEmpty()) {
throw new IllegalStateException("Invalid execution strategy configuration found:\n" + errors);
}
return routeBuilder.build().bind(binder, executionContext);
}
/**
* Register all routes contained in the passed {@link Service}.
*
* @param service {@link Service} for which routes have to be registered.
*/
protected abstract void registerRoutes(Service service);
/**
* Create a new {@link Service} from the passed {@link AllGrpcRoutes}.
*
* @param routes {@link AllGrpcRoutes} for which a {@link Service} has to be created.
* @return {@link Service} containing all the passed routes.
*/
protected abstract Service newServiceFromRoutes(AllGrpcRoutes routes);
/**
* Returns a {@link AllGrpcRoutes} representing this {@link GrpcRoutes}. Any route registered that is not a
* {@link StreamingRoute} will be converted to a {@link StreamingRoute}.
* @return {@link AllGrpcRoutes} representing this {@link GrpcRoutes}.
*/
AllGrpcRoutes drainToStreamingRoutes() {
final RouteProviders routeProviders = routeBuilder.drainRoutes();
return new AllGrpcRoutes() {
@Override
public StreamingRoute streamingRouteFor(
final String path) throws IllegalArgumentException {
return routeProviders.routeProvider(path).asStreamingRoute();
}
@Override
public Route routeFor(final String path)
throws IllegalArgumentException {
return routeProviders.routeProvider(path).asRoute();
}
@Override
public RequestStreamingRoute
requestStreamingRouteFor(final String path) throws IllegalArgumentException {
return routeProviders.routeProvider(path).asRequestStreamingRoute();
}
@Override
public ResponseStreamingRoute
responseStreamingRouteFor(final String path) throws IllegalArgumentException {
return routeProviders.routeProvider(path).asResponseStreamingRoute();
}
@Override
public Completable closeAsync() {
return routeProviders.closeAsync();
}
@Override
public Completable closeAsyncGracefully() {
return routeProviders.closeAsyncGracefully();
}
};
}
static GrpcRoutes merge(GrpcRoutes... allRoutes) {
final GrpcRouter.Builder[] builders = new GrpcRouter.Builder[allRoutes.length];
final Set errors = new TreeSet<>();
for (int i = 0; i < allRoutes.length; i++) {
builders[i] = allRoutes[i].routeBuilder;
errors.addAll(allRoutes[i].errors);
}
return new GrpcRoutes(GrpcRouter.Builder.merge(builders), errors) {
@Override
protected void registerRoutes(final GrpcService service) {
throw new UnsupportedOperationException("Merged service factory can not register routes.");
}
@Override
protected GrpcService newServiceFromRoutes(final AllGrpcRoutes routes) {
throw new UnsupportedOperationException("Merged service factory can not create new service.");
}
};
}
@Nullable
private GrpcExecutionStrategy executionStrategy(final String path, final Method method, final Class clazz) {
// Check if we already have a computed GrpcExecutionStrategy for this path. This happens when we re-register
// filtered routes and have to use the original execution strategy for the route instead of analysing
// annotations on a service-filter class. Because previously registered strategy could be null (if user did not
// configure it using ServiceFactory.Builder methods or via @RouteExecutionStrategy annotation), we use NULL
// object as a marker to understand there was no strategy for this path.
final GrpcExecutionStrategy saved = routeBuilder.executionStrategyFor(path, NULL);
if (saved != NULL) {
return saved;
}
return getAndValidateRouteExecutionStrategyAnnotationIfPresent(method, clazz, strategyFactory, errors,
noOffloadsStrategy());
}
/**
* Adds a {@link Route} to this factory.
*
* @param path for this route.
* @param serviceClass {@link Class} of the gRPC service.
* @param methodName the name of gRPC method.
* @param route {@link Route} to add.
* @param requestClass {@link Class} for the request object.
* @param responseClass {@link Class} for the response object.
* @param serializationProvider {@link GrpcSerializationProvider} for the route.
* @param Type of request.
* @param Type of response.
*/
protected final void addRoute(
final String path, final Class serviceClass, final String methodName, final Route route,
final Class requestClass, final Class responseClass,
final GrpcSerializationProvider serializationProvider) {
final Method method = retrieveMethod(serviceClass, methodName, GrpcServiceContext.class, requestClass);
routeBuilder.addRoute(path, executionStrategy(path, method, serviceClass), route,
requestClass, responseClass, serializationProvider);
}
/**
* Adds a {@link Route} to this factory.
*
* @param path for this route.
* @param executionStrategy {@link GrpcExecutionStrategy} to use.
* @param route {@link Route} to add.
* @param requestClass {@link Class} for the request object.
* @param responseClass {@link Class} for the response object.
* @param serializationProvider {@link GrpcSerializationProvider} for the route.
* @param Type of request.
* @param Type of response.
*/
protected final void addRoute(
final String path, final GrpcExecutionStrategy executionStrategy, final Route route,
final Class requestClass, final Class responseClass,
final GrpcSerializationProvider serializationProvider) {
routeBuilder.addRoute(path, executionStrategy, route, requestClass, responseClass,
serializationProvider);
}
/**
* Adds a {@link StreamingRoute} to this factory.
*
* @param path for this route.
* @param serviceClass {@link Class} of the gRPC service.
* @param methodName the name of gRPC method.
* @param route {@link StreamingRoute} to add.
* @param requestClass {@link Class} for the request object.
* @param responseClass {@link Class} for the response object.
* @param serializationProvider {@link GrpcSerializationProvider} for the route.
* @param Type of request.
* @param Type of response.
*/
protected final void addStreamingRoute(
final String path, final Class serviceClass, final String methodName,
final StreamingRoute route, final Class requestClass, final Class responseClass,
final GrpcSerializationProvider serializationProvider) {
final Method method = retrieveMethod(serviceClass, methodName, GrpcServiceContext.class, Publisher.class);
routeBuilder.addStreamingRoute(path, executionStrategy(path, method, serviceClass), route,
requestClass, responseClass, serializationProvider);
}
/**
* Adds a {@link StreamingRoute} to this factory.
*
* @param path for this route.
* @param executionStrategy {@link GrpcExecutionStrategy} to use.
* @param route {@link StreamingRoute} to add.
* @param requestClass {@link Class} for the request object.
* @param responseClass {@link Class} for the response object.
* @param serializationProvider {@link GrpcSerializationProvider} for the route.
* @param Type of request.
* @param Type of response.
*/
protected final void addStreamingRoute(
final String path, final GrpcExecutionStrategy executionStrategy,
final StreamingRoute route, final Class requestClass,
final Class responseClass, final GrpcSerializationProvider serializationProvider) {
routeBuilder.addStreamingRoute(path, executionStrategy, route, requestClass, responseClass,
serializationProvider);
}
/**
* Adds a {@link RequestStreamingRoute} to this factory.
*
* @param path for this route.
* @param serviceClass {@link Class} of the gRPC service.
* @param methodName the name of gRPC method.
* @param route {@link RequestStreamingRoute} to add.
* @param requestClass {@link Class} for the request object.
* @param responseClass {@link Class} for the response object.
* @param serializationProvider {@link GrpcSerializationProvider} for the route.
* @param Type of request.
* @param Type of response.
*/
protected final void addRequestStreamingRoute(
final String path, final Class serviceClass, final String methodName,
final RequestStreamingRoute route, final Class requestClass,
final Class responseClass, final GrpcSerializationProvider serializationProvider) {
final Method method = retrieveMethod(serviceClass, methodName, GrpcServiceContext.class, Publisher.class);
routeBuilder.addRequestStreamingRoute(path, executionStrategy(path, method, serviceClass),
route, requestClass, responseClass, serializationProvider);
}
/**
* Adds a {@link RequestStreamingRoute} to this factory.
*
* @param path for this route.
* @param executionStrategy {@link GrpcExecutionStrategy} to use.
* @param route {@link RequestStreamingRoute} to add.
* @param requestClass {@link Class} for the request object.
* @param responseClass {@link Class} for the response object.
* @param serializationProvider {@link GrpcSerializationProvider} for the route.
* @param Type of request.
* @param Type of response.
*/
protected final void addRequestStreamingRoute(
final String path, final GrpcExecutionStrategy executionStrategy,
final RequestStreamingRoute route, final Class requestClass,
final Class responseClass, final GrpcSerializationProvider serializationProvider) {
routeBuilder.addRequestStreamingRoute(path, executionStrategy, route, requestClass,
responseClass, serializationProvider);
}
/**
* Adds a {@link ResponseStreamingRoute} to this factory.
*
* @param path for this route.
* @param serviceClass {@link Class} of the gRPC service.
* @param methodName the name of gRPC method.
* @param route {@link ResponseStreamingRoute} to add.
* @param requestClass {@link Class} for the request object.
* @param responseClass {@link Class} for the response object.
* @param serializationProvider {@link GrpcSerializationProvider} for the route.
* @param Type of request.
* @param Type of response.
*/
protected final void addResponseStreamingRoute(
final String path, final Class serviceClass, final String methodName,
final ResponseStreamingRoute route, final Class requestClass,
final Class responseClass, final GrpcSerializationProvider serializationProvider) {
final Method method = retrieveMethod(serviceClass, methodName, GrpcServiceContext.class, requestClass);
routeBuilder.addResponseStreamingRoute(path, executionStrategy(path, method, serviceClass),
route, requestClass, responseClass, serializationProvider);
}
/**
* Adds a {@link ResponseStreamingRoute} to this factory.
*
* @param path for this route.
* @param executionStrategy {@link GrpcExecutionStrategy} to use.
* @param route {@link ResponseStreamingRoute} to add.
* @param requestClass {@link Class} for the request object.
* @param responseClass {@link Class} for the response object.
* @param serializationProvider {@link GrpcSerializationProvider} for the route.
* @param Type of request.
* @param Type of response.
*/
protected final void addResponseStreamingRoute(
final String path, final GrpcExecutionStrategy executionStrategy,
final ResponseStreamingRoute route, final Class requestClass,
final Class responseClass, final GrpcSerializationProvider serializationProvider) {
routeBuilder.addResponseStreamingRoute(path, executionStrategy, route, requestClass,
responseClass, serializationProvider);
}
/**
* Adds a {@link BlockingRoute} to this factory.
*
* @param path for this route.
* @param serviceClass {@link Class} of the gRPC service.
* @param methodName the name of gRPC method.
* @param route {@link BlockingRoute} to add.
* @param requestClass {@link Class} for the request object.
* @param responseClass {@link Class} for the response object.
* @param serializationProvider {@link GrpcSerializationProvider} for the route.
* @param Type of request.
* @param Type of response.
*/
protected final void addBlockingRoute(
final String path, final Class serviceClass, final String methodName,
final BlockingRoute route, final Class requestClass, final Class responseClass,
final GrpcSerializationProvider serializationProvider) {
final Method method = retrieveMethod(serviceClass, methodName, GrpcServiceContext.class, requestClass);
routeBuilder.addBlockingRoute(path, executionStrategy(path, method, serviceClass), route,
requestClass, responseClass, serializationProvider);
}
/**
* Adds a {@link BlockingRoute} to this factory.
*
* @param path for this route.
* @param executionStrategy {@link GrpcExecutionStrategy} to use.
* @param route {@link BlockingRoute} to add.
* @param requestClass {@link Class} for the request object.
* @param responseClass {@link Class} for the response object.
* @param serializationProvider {@link GrpcSerializationProvider} for the route.
* @param Type of request.
* @param Type of response.
*/
protected final void addBlockingRoute(
final String path, final GrpcExecutionStrategy executionStrategy, final BlockingRoute route,
final Class requestClass, final Class responseClass,
final GrpcSerializationProvider serializationProvider) {
routeBuilder.addBlockingRoute(path, executionStrategy, route, requestClass, responseClass,
serializationProvider);
}
/**
* Adds a {@link BlockingStreamingRoute} to this factory.
*
* @param path for this route.
* @param serviceClass {@link Class} of the gRPC service.
* @param methodName the name of gRPC method.
* @param route {@link BlockingStreamingRoute} to add.
* @param requestClass {@link Class} for the request object.
* @param responseClass {@link Class} for the response object.
* @param serializationProvider {@link GrpcSerializationProvider} for the route.
* @param Type of request.
* @param Type of response.
*/
protected final void addBlockingStreamingRoute(
final String path, final Class serviceClass, final String methodName,
final BlockingStreamingRoute route, final Class requestClass,
final Class responseClass, final GrpcSerializationProvider serializationProvider) {
final Method method = retrieveMethod(serviceClass, methodName, GrpcServiceContext.class, BlockingIterable.class,
GrpcPayloadWriter.class);
routeBuilder.addBlockingStreamingRoute(path, executionStrategy(path, method, serviceClass),
route, requestClass, responseClass, serializationProvider);
}
/**
* Adds a {@link BlockingStreamingRoute} to this factory.
*
* @param path for this route.
* @param executionStrategy {@link GrpcExecutionStrategy} to use.
* @param route {@link BlockingStreamingRoute} to add.
* @param requestClass {@link Class} for the request object.
* @param responseClass {@link Class} for the response object.
* @param serializationProvider {@link GrpcSerializationProvider} for the route.
* @param Type of request.
* @param Type of response.
*/
protected final void addBlockingStreamingRoute(
final String path, final GrpcExecutionStrategy executionStrategy,
final BlockingStreamingRoute route, final Class requestClass,
final Class responseClass, final GrpcSerializationProvider serializationProvider) {
routeBuilder.addBlockingStreamingRoute(path, executionStrategy, route, requestClass,
responseClass, serializationProvider);
}
/**
* Adds a {@link BlockingRequestStreamingRoute} to this factory.
*
* @param path for this route.
* @param serviceClass {@link Class} of the gRPC service.
* @param methodName the name of gRPC method.
* @param route {@link BlockingRequestStreamingRoute} to add.
* @param requestClass {@link Class} for the request object.
* @param responseClass {@link Class} for the response object.
* @param serializationProvider {@link GrpcSerializationProvider} for the route.
* @param Type of request.
* @param Type of response.
*/
protected final void addBlockingRequestStreamingRoute(
final String path, final Class serviceClass, final String methodName,
final BlockingRequestStreamingRoute route, final Class requestClass,
final Class responseClass, final GrpcSerializationProvider serializationProvider) {
final Method method = retrieveMethod(serviceClass, methodName, GrpcServiceContext.class,
BlockingIterable.class);
routeBuilder.addBlockingRequestStreamingRoute(path, executionStrategy(path, method, serviceClass),
route, requestClass, responseClass, serializationProvider);
}
/**
* Adds a {@link BlockingRequestStreamingRoute} to this factory.
*
* @param path for this route.
* @param executionStrategy {@link GrpcExecutionStrategy} to use.
* @param route {@link BlockingRequestStreamingRoute} to add.
* @param requestClass {@link Class} for the request object.
* @param responseClass {@link Class} for the response object.
* @param serializationProvider {@link GrpcSerializationProvider} for the route.
* @param Type of request.
* @param Type of response.
*/
protected final void addBlockingRequestStreamingRoute(
final String path, final GrpcExecutionStrategy executionStrategy,
final BlockingRequestStreamingRoute route, final Class requestClass,
final Class responseClass, final GrpcSerializationProvider serializationProvider) {
routeBuilder.addBlockingRequestStreamingRoute(path, executionStrategy, route, requestClass,
responseClass, serializationProvider);
}
/**
* Adds a {@link BlockingResponseStreamingRoute} to this factory.
*
* @param path for this route.
* @param serviceClass {@link Class} of the gRPC service.
* @param methodName the name of gRPC method.
* @param route {@link BlockingResponseStreamingRoute} to add.
* @param requestClass {@link Class} for the request object.
* @param responseClass {@link Class} for the response object.
* @param serializationProvider {@link GrpcSerializationProvider} for the route.
* @param Type of request.
* @param Type of response.
*/
protected final void addBlockingResponseStreamingRoute(
final String path, final Class serviceClass, final String methodName,
final BlockingResponseStreamingRoute route, final Class requestClass,
final Class responseClass, final GrpcSerializationProvider serializationProvider) {
final Method method = retrieveMethod(serviceClass, methodName, GrpcServiceContext.class, requestClass,
GrpcPayloadWriter.class);
routeBuilder.addBlockingResponseStreamingRoute(path, executionStrategy(path, method, serviceClass),
route, requestClass, responseClass, serializationProvider);
}
/**
* Adds a {@link BlockingResponseStreamingRoute} to this factory.
*
* @param path for this route.
* @param executionStrategy {@link GrpcExecutionStrategy} to use.
* @param route {@link BlockingResponseStreamingRoute} to add.
* @param requestClass {@link Class} for the request object.
* @param responseClass {@link Class} for the response object.
* @param serializationProvider {@link GrpcSerializationProvider} for the route.
* @param Type of request.
* @param Type of response.
*/
protected final void addBlockingResponseStreamingRoute(
final String path, final GrpcExecutionStrategy executionStrategy,
final BlockingResponseStreamingRoute route, final Class requestClass,
final Class responseClass, final GrpcSerializationProvider serializationProvider) {
routeBuilder.addBlockingResponseStreamingRoute(path, executionStrategy, route, requestClass,
responseClass, serializationProvider);
}
/**
* An asynchronous gRPC route.
*
* @param Type of request.
* @param Type of response.
*/
@FunctionalInterface
protected interface Route extends AsyncCloseable {
/**
* Handles the passed {@link Req}.
*
* @param ctx {@link GrpcServiceContext} for this call.
* @param request {@link Req} to handle.
* @return {@link Single} containing the response.
*/
Single handle(GrpcServiceContext ctx, Req request);
@Override
default Completable closeAsync() {
return completed();
}
/**
* Convenience method to wrap a raw {@link Route} instance with a passed detached close implementation
* of {@link AsyncCloseable}.
*
* @param rawRoute {@link Route} instance that has a detached close implementation.
* @param closeable {@link AsyncCloseable} implementation for the passed {@code rawRoute}.
* @param Type of request.
* @param Type of response.
* @return A new {@link Route} that attaches the passed {@code closeable} to the passed {@code rawRoute}.
*/
static Route wrap(final Route rawRoute, final AsyncCloseable closeable) {
return new Route() {
@Override
public Single handle(final GrpcServiceContext ctx, final Req request) {
return rawRoute.handle(ctx, request);
}
@Override
public Completable closeAsync() {
return closeable.closeAsync();
}
@Override
public Completable closeAsyncGracefully() {
return closeable.closeAsyncGracefully();
}
};
}
}
/**
* An asynchronous gRPC route with bi-directional streaming.
*
* @param Type of request.
* @param Type of response.
*/
@FunctionalInterface
protected interface StreamingRoute extends AsyncCloseable {
/**
* Handles the passed {@link Req}.
*
* @param ctx {@link GrpcServiceContext} for this call.
* @param request {@link Publisher} of {@link Req} to handle.
* @return {@link Single} containing the response.
*/
Publisher handle(GrpcServiceContext ctx, Publisher request);
@Override
default Completable closeAsync() {
return completed();
}
/**
* Convenience method to wrap a raw {@link StreamingRoute} instance with a passed detached close implementation
* of {@link AsyncCloseable}.
*
* @param rawRoute {@link StreamingRoute} instance that has a detached close implementation.
* @param closeable {@link AsyncCloseable} implementation for the passed {@code rawRoute}.
* @param Type of request.
* @param Type of response.
* @return A new {@link StreamingRoute} that attaches the passed {@code closeable} to the passed
* {@code rawRoute}.
*/
static StreamingRoute wrap(final StreamingRoute rawRoute,
final AsyncCloseable closeable) {
return new StreamingRoute() {
@Override
public Publisher handle(final GrpcServiceContext ctx, final Publisher request) {
return rawRoute.handle(ctx, request);
}
@Override
public Completable closeAsync() {
return closeable.closeAsync();
}
@Override
public Completable closeAsyncGracefully() {
return closeable.closeAsyncGracefully();
}
};
}
}
/**
* An asynchronous gRPC route with request streaming.
*
* @param Type of request.
* @param Type of response.
*/
@FunctionalInterface
protected interface RequestStreamingRoute
extends AsyncCloseable {
/**
* Handles the passed {@link Req}.
*
* @param ctx {@link GrpcServiceContext} for this call.
* @param request {@link Publisher} of {@link Req} to handle.
* @return {@link Single} containing the response.
*/
Single handle(GrpcServiceContext ctx, Publisher request);
@Override
default Completable closeAsync() {
return completed();
}
/**
* Convenience method to wrap a raw {@link RequestStreamingRoute} instance with a passed detached close
* implementation of {@link AsyncCloseable}.
*
* @param rawRoute {@link RequestStreamingRoute} instance that has a detached close implementation.
* @param closeable {@link AsyncCloseable} implementation for the passed {@code rawRoute}.
* @param Type of request.
* @param Type of response.
* @return A new {@link RequestStreamingRoute} that attaches the passed {@code closeable} to the passed
* {@code rawRoute}.
*/
static RequestStreamingRoute wrap(final RequestStreamingRoute rawRoute,
final AsyncCloseable closeable) {
return new RequestStreamingRoute() {
@Override
public Single handle(final GrpcServiceContext ctx, final Publisher request) {
return rawRoute.handle(ctx, request);
}
@Override
public Completable closeAsync() {
return closeable.closeAsync();
}
@Override
public Completable closeAsyncGracefully() {
return closeable.closeAsyncGracefully();
}
};
}
}
/**
* An asynchronous gRPC route with response streaming.
*
* @param Type of request.
* @param Type of response.
*/
@FunctionalInterface
protected interface ResponseStreamingRoute
extends AsyncCloseable {
/**
* Handles the passed {@link Req}.
*
* @param ctx {@link GrpcServiceContext} for this call.
* @param request {@link Req} to handle.
* @return {@link Publisher} containing the response.
*/
Publisher handle(GrpcServiceContext ctx, Req request);
@Override
default Completable closeAsync() {
return completed();
}
/**
* Convenience method to wrap a raw {@link ResponseStreamingRoute} instance with a passed detached close
* implementation of {@link AsyncCloseable}.
*
* @param rawRoute {@link ResponseStreamingRoute} instance that has a detached close implementation.
* @param closeable {@link AsyncCloseable} implementation for the passed {@code rawRoute}.
* @param Type of request.
* @param Type of response.
* @return A new {@link ResponseStreamingRoute} that attaches the passed {@code closeable} to the passed
* {@code rawRoute}.
*/
static ResponseStreamingRoute wrap(final ResponseStreamingRoute rawRoute,
final AsyncCloseable closeable) {
return new ResponseStreamingRoute() {
@Override
public Publisher handle(final GrpcServiceContext ctx, final Req request) {
return rawRoute.handle(ctx, request);
}
@Override
public Completable closeAsync() {
return closeable.closeAsync();
}
@Override
public Completable closeAsyncGracefully() {
return closeable.closeAsyncGracefully();
}
};
}
}
/**
* A blocking gRPC route.
*
* @param Type of request.
* @param Type of response.
*/
@FunctionalInterface
protected interface BlockingRoute
extends GracefulAutoCloseable {
/**
* Handles the passed {@link Req}.
*
* @param ctx {@link GrpcServiceContext} for this call.
* @param request {@link Req} to handle.
* @return The response.
* @throws Exception If an exception occurs during request processing.
*/
Resp handle(GrpcServiceContext ctx, Req request) throws Exception;
@Override
default void close() throws Exception {
// No op
}
/**
* Convenience method to wrap a raw {@link BlockingRoute} instance with a passed detached close
* implementation of {@link GracefulAutoCloseable}.
*
* @param rawRoute {@link BlockingRoute} instance that has a detached close implementation.
* @param closeable {@link GracefulAutoCloseable} implementation for the passed {@code rawRoute}.
* @param Type of request.
* @param Type of response.
* @return A new {@link BlockingRoute} that attaches the passed {@code closeable} to the passed
* {@code rawRoute}.
*/
static BlockingRoute wrap(final BlockingRoute rawRoute,
final GracefulAutoCloseable closeable) {
return new BlockingRoute() {
@Override
public Resp handle(final GrpcServiceContext ctx, final Req request) throws Exception {
return rawRoute.handle(ctx, request);
}
@Override
public void close() throws Exception {
closeable.close();
}
@Override
public void closeGracefully() throws Exception {
closeable.closeGracefully();
}
};
}
}
/**
* A blocking gRPC route with bi-directional streaming.
*
* @param Type of request.
* @param Type of response.
*/
@FunctionalInterface
protected interface BlockingStreamingRoute
extends GracefulAutoCloseable {
/**
* Handles the passed {@link Req}.
*
* @param ctx {@link GrpcServiceContext} for this call.
* @param request {@link BlockingIterable} of {@link Req} to handle.
* @param responseWriter {@link GrpcPayloadWriter} to write the response.
* @throws Exception If an exception occurs during request processing.
*/
void handle(GrpcServiceContext ctx, BlockingIterable request,
GrpcPayloadWriter responseWriter) throws Exception;
@Override
default void close() throws Exception {
// No op
}
/**
* Convenience method to wrap a raw {@link BlockingStreamingRoute} instance with a passed detached close
* implementation of {@link GracefulAutoCloseable}.
*
* @param rawRoute {@link BlockingStreamingRoute} instance that has a detached close implementation.
* @param closeable {@link GracefulAutoCloseable} implementation for the passed {@code rawRoute}.
* @param Type of request.
* @param Type of response.
* @return A new {@link BlockingStreamingRoute} that attaches the passed {@code closeable} to the passed
* {@code rawRoute}.
*/
static BlockingStreamingRoute wrap(final BlockingStreamingRoute rawRoute,
final GracefulAutoCloseable closeable) {
return new BlockingStreamingRoute() {
@Override
public void handle(final GrpcServiceContext ctx, final BlockingIterable request,
final GrpcPayloadWriter responseWriter) throws Exception {
rawRoute.handle(ctx, request, responseWriter);
}
@Override
public void close() throws Exception {
closeable.close();
}
@Override
public void closeGracefully() throws Exception {
closeable.closeGracefully();
}
};
}
}
/**
* A blocking gRPC route with request streaming.
*
* @param Type of request.
* @param Type of response.
*/
@FunctionalInterface
protected interface BlockingRequestStreamingRoute
extends GracefulAutoCloseable {
/**
* Handles the passed {@link Req}.
*
* @param ctx {@link GrpcServiceContext} for this call.
* @param request {@link BlockingIterable} of {@link Req} to handle.
* @return The response.
* @throws Exception If an exception occurs during request processing.
*/
Resp handle(GrpcServiceContext ctx, BlockingIterable request) throws Exception;
@Override
default void close() throws Exception {
// No op
}
/**
* Convenience method to wrap a raw {@link BlockingRequestStreamingRoute} instance with a passed detached close
* implementation of {@link GracefulAutoCloseable}.
*
* @param rawRoute {@link BlockingRequestStreamingRoute} instance that has a detached close implementation.
* @param closeable {@link GracefulAutoCloseable} implementation for the passed {@code rawRoute}.
* @param Type of request.
* @param Type of response.
* @return A new {@link BlockingRequestStreamingRoute} that attaches the passed {@code closeable} to the passed
* {@code rawRoute}.
*/
static BlockingRequestStreamingRoute wrap(
final BlockingRequestStreamingRoute rawRoute, final GracefulAutoCloseable closeable) {
return new BlockingRequestStreamingRoute() {
@Override
public Resp handle(final GrpcServiceContext ctx, final BlockingIterable request) throws Exception {
return rawRoute.handle(ctx, request);
}
@Override
public void close() throws Exception {
closeable.close();
}
@Override
public void closeGracefully() throws Exception {
closeable.closeGracefully();
}
};
}
}
/**
* A blocking gRPC route with response streaming.
*
* @param Type of request.
* @param Type of response.
*/
@FunctionalInterface
protected interface BlockingResponseStreamingRoute
extends GracefulAutoCloseable {
/**
* Handles the passed {@link Req}.
*
* @param ctx {@link GrpcServiceContext} for this call.
* @param request {@link Req} to handle.
* @param responseWriter {@link GrpcPayloadWriter} to write the response.
* @throws Exception If an exception occurs during request processing.
*/
void handle(GrpcServiceContext ctx, Req request, GrpcPayloadWriter responseWriter) throws Exception;
@Override
default void close() throws Exception {
// No op
}
/**
* Convenience method to wrap a raw {@link BlockingResponseStreamingRoute} instance with a passed detached close
* implementation of {@link GracefulAutoCloseable}.
*
* @param rawRoute {@link BlockingResponseStreamingRoute} instance that has a detached close implementation.
* @param closeable {@link GracefulAutoCloseable} implementation for the passed {@code rawRoute}.
* @param Type of request.
* @param Type of response.
* @return A new {@link BlockingResponseStreamingRoute} that attaches the passed {@code closeable} to the passed
* {@code rawRoute}.
*/
static BlockingResponseStreamingRoute wrap(
final BlockingResponseStreamingRoute rawRoute, final GracefulAutoCloseable closeable) {
return new BlockingResponseStreamingRoute() {
@Override
public void handle(final GrpcServiceContext ctx, final Req request,
final GrpcPayloadWriter responseWriter) throws Exception {
rawRoute.handle(ctx, request, responseWriter);
}
@Override
public void close() throws Exception {
closeable.close();
}
@Override
public void closeGracefully() throws Exception {
closeable.closeGracefully();
}
};
}
}
/**
* A collection of route corresponding to the enclosing {@link GrpcRoutes}.
*/
protected interface AllGrpcRoutes extends AsyncCloseable {
/**
* Returns the registered {@link StreamingRoute} for the passed {@code path}. If a route with a different
* programming model is registered, it will be converted to a {@link StreamingRoute}.
*
* @param path for the route.
* @param Type of request.
* @param Type of response.
* @return Registered {@link StreamingRoute} for the passed {@code path}.
* @throws IllegalArgumentException If the route does not exist.
*/
StreamingRoute streamingRouteFor(String path)
throws IllegalArgumentException;
/**
* Returns the registered {@link Route} for the passed {@code path}. If a route with a different
* programming model is registered, it will be converted to a {@link Route}.
*
* @param path for the route.
* @param Type of request.
* @param Type of response.
* @return Registered {@link Route} for the passed {@code path}.
* @throws IllegalArgumentException If the route does not exist.
*/
Route routeFor(String path)
throws IllegalArgumentException;
/**
* Returns the registered {@link RequestStreamingRoute} for the passed {@code path}. If a route with a different
* programming model is registered, it will be converted to a {@link RequestStreamingRoute}.
*
* @param path for the route.
* @param Type of request.
* @param Type of response.
* @return Registered {@link RequestStreamingRoute} for the passed {@code path}.
* @throws IllegalArgumentException If the route does not exist.
*/
RequestStreamingRoute requestStreamingRouteFor(String path)
throws IllegalArgumentException;
/**
* Returns the registered {@link ResponseStreamingRoute} for the passed {@code path}. If a route with a
* different programming model is registered, it will be converted to a {@link ResponseStreamingRoute}.
*
* @param path for the route.
* @param Type of request.
* @param Type of response.
* @return Registered {@link ResponseStreamingRoute} for the passed {@code path}.
* @throws IllegalArgumentException If the route does not exist.
*/
ResponseStreamingRoute responseStreamingRouteFor(String path)
throws IllegalArgumentException;
}
}