| @* |
| * 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); |
| } |
| } |
| } |