blob: d8796868ff0d5dac60b31e565311792b47837de4 [file]
@*
* Licensed to the Apache Software Foundation (ASF) under one or more
* license agreements; and to You under the Apache License, version 2.0:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* This file is part of the Apache Pekko project, which was derived from Akka.
*@
@*
* Copyright (C) 2018-2021 Lightbend Inc. <https://www.lightbend.com>
*@
@(service: org.apache.pekko.grpc.gen.javadsl.Service, powerApis: Boolean)
@org.apache.pekko.grpc.gen.Constants.DoNotEditComment
package @service.packageName;
import java.util.Iterator;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import org.apache.pekko.japi.function.Function;
import org.apache.pekko.actor.ActorSystem;
import org.apache.pekko.actor.ClassicActorSystemProvider;
import org.apache.pekko.annotation.ApiMayChange;
import org.apache.pekko.stream.Materializer;
import org.apache.pekko.stream.SystemMaterializer;
import org.apache.pekko.grpc.Trailers;
import org.apache.pekko.grpc.javadsl.GrpcMarshalling;
import org.apache.pekko.grpc.javadsl.GrpcExceptionHandler;
import org.apache.pekko.grpc.internal.TelemetryExtension;
import org.apache.pekko.grpc.internal.TelemetrySpi;
import org.apache.pekko.grpc.PekkoGrpcGenerated;
@{if (powerApis) "import org.apache.pekko.grpc.javadsl.Metadata;\nimport org.apache.pekko.grpc.javadsl.MetadataBuilder;" else ""}
import static @{service.packageName}.@{service.name}.Serializers.*;
@defining(if (powerApis) service.name + "PowerApi" else service.name) { serviceName =>
/*
* Generated by Pekko gRPC. DO NOT EDIT.
*
* The API of this class may still change in future Apache Pekko gRPC versions, see for instance
* https://github.com/akka/akka-grpc/issues/994
*/
@@ApiMayChange
@@PekkoGrpcGenerated
public class @{serviceName}HandlerFactory {
private static final CompletionStage<org.apache.pekko.http.javadsl.model.HttpResponse> notFound = CompletableFuture.completedFuture(
org.apache.pekko.http.javadsl.model.HttpResponse.create().withStatus(org.apache.pekko.http.javadsl.model.StatusCodes.NOT_FOUND));
private static final CompletionStage<org.apache.pekko.http.javadsl.model.HttpResponse> unsupportedMediaType = CompletableFuture.completedFuture(
org.apache.pekko.http.javadsl.model.HttpResponse.create().withStatus(org.apache.pekko.http.javadsl.model.StatusCodes.UNSUPPORTED_MEDIA_TYPE));
/**
* Creates a `HttpRequest` to `HttpResponse` handler that can be used in for example `Http().bindAndHandleAsync`
* for the generated partial function handler and ends with `StatusCodes.NotFound` if the request is not matching.
*
* Use {@@link org.apache.pekko.grpc.javadsl.ServiceHandler#concatOrNotFound} with {@@link @{service.name}HandlerFactory#partial} when combining
* several services.
*/
public static Function<org.apache.pekko.http.javadsl.model.HttpRequest, CompletionStage<org.apache.pekko.http.javadsl.model.HttpResponse>> create(@serviceName implementation, ClassicActorSystemProvider system) {
return create(implementation, @{service.name}.name, system);
}
/**
* Creates a `HttpRequest` to `HttpResponse` handler that can be used in for example `Http().bindAndHandleAsync`
* for the generated partial function handler and ends with `StatusCodes.NotFound` if the request is not matching.
*
* Use {@@link org.apache.pekko.grpc.javadsl.ServiceHandler#concatOrNotFound} with {@@link @{service.name}HandlerFactory#partial} when combining
* several services.
*/
public static Function<org.apache.pekko.http.javadsl.model.HttpRequest, CompletionStage<org.apache.pekko.http.javadsl.model.HttpResponse>> create(@serviceName implementation, org.apache.pekko.japi.function.Function<ActorSystem, org.apache.pekko.japi.function.Function<Throwable, Trailers>> eHandler, ClassicActorSystemProvider system) {
return create(implementation, @{service.name}.name, eHandler, system);
}
/**
* Creates a `HttpRequest` to `HttpResponse` handler that can be used in for example `Http().bindAndHandleAsync`
* for the generated partial function handler and ends with `StatusCodes.NotFound` if the request is not matching.
*
* Use {@@link org.apache.pekko.grpc.javadsl.ServiceHandler#concatOrNotFound} with {@@link @{service.name}HandlerFactory#partial} when combining
* several services.
*
* Registering a gRPC service under a custom prefix is not widely supported and strongly discouraged by the specification.
*/
public static Function<org.apache.pekko.http.javadsl.model.HttpRequest, CompletionStage<org.apache.pekko.http.javadsl.model.HttpResponse>> create(@serviceName implementation, String prefix, ClassicActorSystemProvider system) {
return partial(implementation, prefix, SystemMaterializer.get(system).materializer(), GrpcExceptionHandler.defaultMapper(), system);
}
/**
* Creates a `HttpRequest` to `HttpResponse` handler that can be used in for example `Http().bindAndHandleAsync`
* for the generated partial function handler and ends with `StatusCodes.NotFound` if the request is not matching.
*
* Use {@@link org.apache.pekko.grpc.javadsl.ServiceHandler#concatOrNotFound} with {@@link @{service.name}HandlerFactory#partial} when combining
* several services.
*
* Registering a gRPC service under a custom prefix is not widely supported and strongly discouraged by the specification.
*/
public static Function<org.apache.pekko.http.javadsl.model.HttpRequest, CompletionStage<org.apache.pekko.http.javadsl.model.HttpResponse>> create(@serviceName implementation, String prefix, org.apache.pekko.japi.function.Function<ActorSystem, org.apache.pekko.japi.function.Function<Throwable, Trailers>> eHandler, ClassicActorSystemProvider system) {
return partial(implementation, prefix, SystemMaterializer.get(system).materializer(), eHandler, system);
}
@if(serviceName != "ServerReflection") {
/**
* Creates a `HttpRequest` to `HttpResponse` handler that can be used in for example `Http().bindAndHandleAsync`
* for the generated partial function handler. The generated handler falls back to a reflection handlers for
* `@{service.name}` and ends with `StatusCodes.NotFound` if the request is not matching.
*
* Use {@@link org.apache.pekko.grpc.javadsl.ServiceHandler#concatOrNotFound} with {@@link @{service.name}HandlerFactory#partial} when combining
* several services.
*/
@@SuppressWarnings("unchecked")
public static Function<org.apache.pekko.http.javadsl.model.HttpRequest, CompletionStage<org.apache.pekko.http.javadsl.model.HttpResponse>> createWithServerReflection(@serviceName implementation, ClassicActorSystemProvider system) {
return org.apache.pekko.grpc.javadsl.ServiceHandler.concatOrNotFound(
@{serviceName}HandlerFactory.create(implementation, system),
org.apache.pekko.grpc.javadsl.ServerReflection.create(
java.util.Collections.singletonList(@{service.name}.description),
system));
}
}
/**
* Creates a `HttpRequest` to `HttpResponse` handler that can be used in for example
* `Http.get(system).bindAndHandleAsync`. It ends with `StatusCodes.NotFound` if the request is not matching.
*
* Use {@@link org.apache.pekko.grpc.javadsl.ServiceHandler#concatOrNotFound} when combining several services.
*/
public static Function<org.apache.pekko.http.javadsl.model.HttpRequest, CompletionStage<org.apache.pekko.http.javadsl.model.HttpResponse>> partial(@serviceName implementation, String prefix, ClassicActorSystemProvider system) {
return partial(implementation, prefix, SystemMaterializer.get(system).materializer(), GrpcExceptionHandler.defaultMapper(), system);
}
/**
* Creates a `HttpRequest` to `HttpResponse` handler that can be used in for example
* `Http.get(system).bindAndHandleAsync`. It ends with `StatusCodes.NotFound` if the request is not matching.
*
* Use {@@link org.apache.pekko.grpc.javadsl.ServiceHandler#concatOrNotFound} when combining several services.
*/
public static Function<org.apache.pekko.http.javadsl.model.HttpRequest, CompletionStage<org.apache.pekko.http.javadsl.model.HttpResponse>> partial(@serviceName implementation, String prefix, Materializer mat, org.apache.pekko.japi.function.Function<ActorSystem, org.apache.pekko.japi.function.Function<Throwable, Trailers>> eHandler, ClassicActorSystemProvider system) {
TelemetrySpi spi = TelemetryExtension.get(system).spi();
return (req -> {
Iterator<String> segments = req.getUri().pathSegments().iterator();
if (segments.hasNext() && segments.next().equals(prefix) && segments.hasNext()) {
String method = segments.next();
if (segments.hasNext()) return notFound; // we don't allow any random `/prefix/Method/anything/here
else {
return handle(spi.onRequest(prefix, method, req), method, implementation, mat, eHandler, system);
}
} else {
return notFound;
}
});
}
public String getServiceName() {
return @{service.name}.name;
}
private static CompletionStage<org.apache.pekko.http.javadsl.model.HttpResponse> handle(org.apache.pekko.http.javadsl.model.HttpRequest request, String method, @serviceName implementation, Materializer mat, org.apache.pekko.japi.function.Function<ActorSystem, org.apache.pekko.japi.function.Function<Throwable, Trailers>> eHandler, ClassicActorSystemProvider system) {
return GrpcMarshalling.negotiated(request, (reader, writer) -> {
CompletionStage<org.apache.pekko.http.javadsl.model.HttpResponse> response;
@{if(powerApis) { "Metadata metadata = MetadataBuilder.fromHeaders(request.getHeaders());" } else { "" }}
switch(method) {
@for(method <- service.methods) {
case "@method.grpcName": {
@if(method.methodType == org.apache.pekko.grpc.gen.Unary) {
final org.apache.pekko.http.javadsl.model.HttpEntity entity = request.entity();
if (entity instanceof org.apache.pekko.http.scaladsl.model.HttpEntity.Strict) {
final org.apache.pekko.http.scaladsl.model.HttpEntity.Strict strictEntity =
(org.apache.pekko.http.scaladsl.model.HttpEntity.Strict) entity;
try {
return GrpcMarshalling.handleUnaryResponse(
implementation.@{method.name}(@{method.deserializer.name}.deserialize(reader.decodeSingleFrame().apply(strictEntity.data()))@{if(powerApis) { ", metadata" } else { "" }}),
@method.serializer.name,
writer,
system,
eHandler);
} catch (Throwable e) {
return GrpcMarshalling.handleUnaryFailure(e, writer, system, eHandler);
}
} else {
return GrpcMarshalling.handleUnaryResponse(
GrpcMarshalling.unmarshal(request.entity(), @method.deserializer.name, mat, reader)
.thenCompose(e -> implementation.@{method.name}(e@{if(powerApis) { ", metadata" } else { "" }})),
@method.serializer.name,
writer,
system,
eHandler);
}
} else {
response = @{method.unmarshal}(request.entity(), @method.deserializer.name, mat, reader)
.@{if(method.outputStreaming) { "thenApply" } else { "thenCompose" }}(e -> implementation.@{method.name}(e@{if(powerApis) { ", metadata" } else { "" }}))
.thenApply(e -> @{method.marshal}(e, @method.serializer.name, writer, system, eHandler));
break;
}
}
}
default:
CompletableFuture<org.apache.pekko.http.javadsl.model.HttpResponse> result = new CompletableFuture<>();
result.completeExceptionally(new UnsupportedOperationException("Not implemented: " + method));
response = result;
}
return response.exceptionally(e -> GrpcExceptionHandler.standard(e, eHandler, writer, system));
})
.orElseGet(() -> unsupportedMediaType);
}
}
}