instance = beanManager.createInstance();
+ GrpcRouting.Builder builder = GrpcRouting.builder();
+
+ // discover @Grpc annotated beans
+ // we use the bean manager to do this as we need the actual bean class
+ beanManager.getBeans(Object.class, Any.Literal.INSTANCE)
+ .stream()
+ .filter(this::hasGrpcQualifier)
+ .forEach(bean -> {
+ Class> beanClass = bean.getBeanClass();
+ Annotation[] qualifiers = bean.getQualifiers().toArray(new Annotation[0]);
+ Object service = instance.select(beanClass, qualifiers).get();
+ register(service, builder, beanClass, beanManager);
+ });
+
+ // discover beans of type GrpcService
+ beanManager.getBeans(GrpcService.class)
+ .forEach(bean -> {
+ Class> beanClass = bean.getBeanClass();
+ Annotation[] qualifiers = bean.getQualifiers().toArray(new Annotation[0]);
+ Object service = instance.select(beanClass, qualifiers).get();
+ builder.service((GrpcService) service);
+ });
+
+ // discover beans of type BindableService
+ beanManager.getBeans(BindableService.class)
+ .forEach(bean -> {
+ Class> beanClass = bean.getBeanClass();
+ Annotation[] qualifiers = bean.getQualifiers().toArray(new Annotation[0]);
+ Object service = instance.select(beanClass, qualifiers).get();
+ builder.service((BindableService) service);
+ });
+
+ return builder;
+ }
+
+ private boolean hasGrpcQualifier(Bean> bean) {
+ return bean.getQualifiers()
+ .stream()
+ .anyMatch(q -> Grpc.class.isAssignableFrom(q.annotationType()));
+ }
+
+ /**
+ * Register the service with the routing.
+ *
+ * The service is actually a CDI proxy so the real service.
+ *
+ * @param service the service to register
+ * @param builder the gRPC routing
+ * @param beanManager the {@link BeanManager} to use to locate beans required by the service
+ */
+ private void register(Object service, GrpcRouting.Builder builder, Class> cls, BeanManager beanManager) {
+ GrpcServiceBuilder serviceBuilder = GrpcServiceBuilder.create(cls, () -> service, beanManager);
+ if (serviceBuilder.isAnnotatedService()) {
+ builder.service(serviceBuilder.build());
+ } else {
+ LOGGER.log(Level.WARNING,
+ () -> "Discovered type is not a properly annotated gRPC service " + service.getClass());
+ }
+ }
+}
diff --git a/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/GrpcServer.java b/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/GrpcServer.java
deleted file mode 100644
index d3188d71342..00000000000
--- a/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/GrpcServer.java
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Copyright (c) 2019, 2024 Oracle and/or its affiliates.
- *
- * 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.helidon.microprofile.grpc.server;
-
-import java.util.Map;
-import java.util.Objects;
-import java.util.concurrent.CompletionStage;
-import java.util.function.Supplier;
-
-import io.helidon.common.context.Context;
-import io.helidon.grpc.core.WeightedBag;
-import io.helidon.webserver.grpc.GrpcRouting;
-import io.helidon.webserver.grpc.ServiceDescriptor;
-
-import io.grpc.ServerInterceptor;
-import org.eclipse.microprofile.health.HealthCheck;
-
-/**
- * Represents a immutably configured gRPC server.
- *
- * Provides a basic lifecycle and monitoring API.
- *
- * Instance can be created from {@link GrpcRouting} and optionally from {@link
- * GrpcServerConfiguration} using {@link #create(GrpcRouting)}, {@link
- * #create(GrpcServerConfiguration, GrpcRouting)} or {@link #builder(GrpcRouting)} methods
- * and their builder enabled overloads.
- */
-public interface GrpcServer {
- /**
- * Gets effective server configuration.
- *
- * @return Server configuration
- */
- GrpcServerConfiguration configuration();
-
- /**
- * Gets a {@link GrpcServer} context.
- *
- * @return a server context
- */
- Context context();
-
- /**
- * Starts the server. Has no effect if server is running.
- *
- * @return a completion stage of starting process
- */
- CompletionStage start();
-
- /**
- * Completion stage is completed when server is shut down.
- *
- * @return a completion stage of the server
- */
- CompletionStage whenShutdown();
-
- /**
- * Attempt to gracefully shutdown server. It is possible to use returned
- * {@link CompletionStage} to react.
- *
- * RequestMethod can be called periodically.
- *
- * @return to react on finished shutdown process
- * @see #start()
- */
- CompletionStage shutdown();
-
- /**
- * Return an array of health checks for this server.
- *
- * @return an array of {@link HealthCheck} instances for this server
- */
- HealthCheck[] healthChecks();
-
- /**
- * Obtain the deployed services.
- *
- * @return an immutable {@link Map} of deployed {@link ServiceDescriptor}s
- * keyed by service name
- */
- Map services();
-
- /**
- * Returns {@code true} if the server is currently running. A running server
- * in the stopping phase returns {@code true} until it is fully stopped.
- *
- * @return {@code true} if server is running
- */
- boolean isRunning();
-
- /**
- * Returns a port number the default server socket is bound to and is
- * listening on; or {@code -1} if unknown or not active.
- *
- * Only supported only when server is running.
- *
- * @return a listen port; or {@code -1} if unknown or the default server
- * socket is not active
- */
- int port();
-
- /**
- * Creates a new instance from a provided configuration and a GrpcRouting.
- *
- * @param configurationBuilder a server configuration builder that will be
- * built as a first step of this method
- * execution; may be {@code null}
- * @param routing a GrpcRouting instance
- * @return a new gRPC server instance
- * @throws IllegalStateException if none SPI implementation found
- * @throws NullPointerException if 'GrpcRouting' parameter is {@code null}
- */
- static GrpcServer create(Supplier extends GrpcServerConfiguration> configurationBuilder, GrpcRouting routing) {
- return create(configurationBuilder != null
- ? configurationBuilder.get()
- : null, routing);
- }
-
- /**
- * Creates new instance form provided configuration and GrpcRouting.
- *
- * @param configurationBuilder a server configuration builder that will be
- * built as a first step of this method
- * execution; may be {@code null}
- * @param routingBuilder a GrpcRouting builder that will be built as a
- * second step of this method execution
- * @return a new gRPC server instance
- * @throws IllegalStateException if none SPI implementation found
- * @throws NullPointerException if 'routingBuilder' parameter is {@code
- * null}
- */
- static GrpcServer create(Supplier extends GrpcServerConfiguration> configurationBuilder,
- Supplier extends GrpcRouting> routingBuilder) {
- Objects.requireNonNull(routingBuilder, "Parameter 'routingBuilder' must not be null!");
- return create(configurationBuilder != null
- ? configurationBuilder.get()
- : null, routingBuilder.get());
- }
-
- /**
- * Creates new instance form provided configuration and GrpcRouting.
- *
- * @param configuration a server configuration instance
- * @param routingBuilder a GrpcRouting builder that will be built as a second
- * step of this method execution
- * @return a new gRPC server instance
- * @throws IllegalStateException if none SPI implementation found
- * @throws NullPointerException if 'routingBuilder' parameter is {@code
- * null}
- */
- static GrpcServer create(
- GrpcServerConfiguration configuration,
- Supplier extends GrpcRouting> routingBuilder) {
- Objects.requireNonNull(routingBuilder, "Parameter 'routingBuilder' must not be null!");
- return create(configuration, routingBuilder.get());
- }
-
- /**
- * Creates new instance form provided GrpcRouting and default configuration.
- *
- * @param routing a GrpcRouting instance
- * @return a new gRPC server instance
- * @throws IllegalStateException if none SPI implementation found
- * @throws NullPointerException if 'routing' parameter is {@code null}
- */
- static GrpcServer create(GrpcRouting routing) {
- return create((GrpcServerConfiguration) null, routing);
- }
-
- /**
- * Creates new instance form provided configuration and GrpcRouting.
- *
- * @param configuration a server configuration instance
- * @param routing a GrpcRouting instance
- * @return a new gRPC server instance
- * @throws IllegalStateException if none SPI implementation found
- * @throws NullPointerException if 'GrpcRouting' parameter is {@code null}
- */
- static GrpcServer create(GrpcServerConfiguration configuration, GrpcRouting routing) {
- Objects.requireNonNull(routing, "Parameter 'routing' is null!");
-
- return builder(routing)
- .config(configuration)
- .build();
- }
-
- /**
- * Creates new instance form provided GrpcRouting and default configuration.
- *
- * @param routingBuilder a GrpcRouting builder instance that will be built as a
- * first step of this method execution
- * @return a new gRPC server instance
- * @throws IllegalStateException if none SPI implementation found
- * @throws NullPointerException if 'GrpcRouting' parameter is {@code null}
- */
- static GrpcServer create(Supplier extends GrpcRouting> routingBuilder) {
- Objects.requireNonNull(routingBuilder, "Parameter 'routingBuilder' must not be null!");
- return create(routingBuilder.get());
- }
-
- /**
- * Creates a builder of the {@link GrpcServer}.
- *
- * @param routingBuilder the GrpcRouting builder; must not be {@code null}
- * @return the builder
- */
- static Builder builder(Supplier extends GrpcRouting> routingBuilder) {
- Objects.requireNonNull(routingBuilder, "Parameter 'routingBuilder' must not be null!");
- return builder(routingBuilder.get());
- }
-
- /**
- * Creates a builder of the {@link GrpcServer}.
- *
- * @param routing the GrpcRouting; must not be {@code null}
- * @return the builder
- */
- static Builder builder(GrpcRouting routing) {
- return new Builder(GrpcServerConfiguration.create(), routing);
- }
-
- /**
- * GrpcServer builder class provides a convenient way to timed a
- * GrpcServer instance.
- */
- final class Builder implements io.helidon.common.Builder {
-
- private final GrpcRouting routing;
-
- private GrpcServerConfiguration configuration;
-
- private Builder(GrpcServerConfiguration configuration, GrpcRouting routing) {
- Objects.requireNonNull(configuration, "Parameter 'configuration' must not be null!");
- Objects.requireNonNull(routing, "Parameter 'routing' must not be null!");
-
- this.configuration = configuration;
- this.routing = routing;
- }
-
- /**
- * Set a configuration of the {@link GrpcServer}.
- *
- * @param configuration the configuration
- * @return an updated builder
- */
- public Builder config(GrpcServerConfiguration configuration) {
- this.configuration = configuration != null ? configuration : GrpcServerConfiguration.create();
- return this;
- }
-
- /**
- * Set a configuration of the {@link GrpcServer}.
- *
- * @param configurationBuilder the configuration builder
- * @return an updated builder
- */
- public Builder config(Supplier configurationBuilder) {
- this.configuration = configurationBuilder != null
- ? configurationBuilder.get()
- : GrpcServerConfiguration.create();
- return this;
- }
-
- /**
- * Builds the {@link GrpcServer} instance as configured by this builder
- * and its parameters.
- *
- * @return a ready to use {@link GrpcServer}
- */
- @Override
- public GrpcServer build() {
- WeightedBag interceptors = WeightedBag.create();
- GrpcServerImpl server = GrpcServerImpl.create(configuration);
-
- interceptors.add(ContextSettingServerInterceptor.create());
-
- // add the global interceptors from the routing AFTER the tracing interceptor
- // so that all of those interceptors are included in the trace timings
- interceptors.merge(routing.interceptors());
-
- for (ServiceDescriptor service : routing.services()) {
- server.deploy(service, interceptors);
- }
-
- return server;
- }
- }
-}
diff --git a/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/GrpcServerBasicConfig.java b/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/GrpcServerBasicConfig.java
deleted file mode 100644
index 798ef4679a9..00000000000
--- a/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/GrpcServerBasicConfig.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (c) 2019, 2024 Oracle and/or its affiliates.
- *
- * 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.helidon.microprofile.grpc.server;
-
-import java.time.Duration;
-
-import io.helidon.common.context.Context;
-
-/**
- * Configuration class for the {@link GrpcServer} implementations.
- */
-public class GrpcServerBasicConfig
- implements GrpcServerConfiguration {
-
- private final String name;
-
- private final int port;
-
- private final boolean nativeTransport;
-
- private final int workers;
-
- private final GrpcTlsDescriptor tlsConfig;
-
- private final Context context;
-
- private final int maxRapidResets;
-
- private final Duration rapidResetCheckPeriod;
-
- /**
- * Construct {@link GrpcServerBasicConfig} instance.
- *
- * @param builder the {@link GrpcServerConfiguration.Builder} to use to configure
- * this {@link GrpcServerBasicConfig}.
- */
- private GrpcServerBasicConfig(GrpcServerConfiguration.Builder builder) {
- this.name = builder.name();
- this.port = builder.port();
- this.context = builder.context();
- this.nativeTransport = builder.useNativeTransport();
- this.workers = builder.workers();
- this.tlsConfig = builder.tlsConfig();
- this.maxRapidResets = builder.maxRapidResets();
- this.rapidResetCheckPeriod = builder.rapidResetCheckPeriod();
- }
-
- /**
- * Create a {@link GrpcServerBasicConfig} instance using the specified builder.
- *
- * @param builder the {@link GrpcServerConfiguration.Builder} to use to configure
- * this {@link GrpcServerBasicConfig}
- * @return a {@link GrpcServerBasicConfig} instance
- */
- static GrpcServerBasicConfig create(GrpcServerConfiguration.Builder builder) {
- return new GrpcServerBasicConfig(builder);
- }
-
- // ---- accessors ---------------------------------------------------
-
- /**
- * Get the server name.
- *
- * @return the server name
- */
- @Override
- public String name() {
- return name;
- }
-
- /**
- * Get the server port.
- *
- * @return the server port
- */
- @Override
- public int port() {
- return port;
- }
-
- @Override
- public Context context() {
- return context;
- }
-
- /**
- * Determine whether use native transport if possible.
- *
- * If native transport support is enabled, gRPC server will use epoll on
- * Linux, or kqueue on OS X. Otherwise, the standard NIO transport will
- * be used.
- *
- * @return {@code true} if native transport should be used
- */
- @Override
- public boolean useNativeTransport() {
- return nativeTransport;
- }
-
- @Override
- public int workers() {
- return workers;
- }
-
- @Override
- public GrpcTlsDescriptor tlsConfig() {
- return tlsConfig;
- }
-
- @Override
- public Duration rapidResetCheckPeriod() {
- return rapidResetCheckPeriod;
- }
-
- @Override
- public int maxRapidResets() {
- return maxRapidResets;
- }
-}
diff --git a/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/GrpcServerCdiExtension.java b/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/GrpcServerCdiExtension.java
deleted file mode 100644
index 56b0713bda4..00000000000
--- a/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/GrpcServerCdiExtension.java
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * Copyright (c) 2019, 2024 Oracle and/or its affiliates.
- *
- * 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.helidon.microprofile.grpc.server;
-
-import java.lang.annotation.Annotation;
-import java.util.ServiceLoader;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CompletionStage;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Supplier;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import io.helidon.common.HelidonServiceLoader;
-import io.helidon.config.Config;
-import io.helidon.config.mp.MpConfig;
-import io.helidon.microprofile.grpc.core.Grpc;
-import io.helidon.microprofile.grpc.core.InProcessGrpcChannel;
-import io.helidon.microprofile.grpc.server.spi.GrpcMpContext;
-import io.helidon.microprofile.grpc.server.spi.GrpcMpExtension;
-import io.helidon.webserver.grpc.GrpcRouting;
-import io.helidon.webserver.grpc.GrpcService;
-
-import io.grpc.BindableService;
-import io.grpc.Channel;
-import io.grpc.inprocess.InProcessChannelBuilder;
-import jakarta.enterprise.context.ApplicationScoped;
-import jakarta.enterprise.context.Initialized;
-import jakarta.enterprise.event.Observes;
-import jakarta.enterprise.inject.Any;
-import jakarta.enterprise.inject.Instance;
-import jakarta.enterprise.inject.Produces;
-import jakarta.enterprise.inject.spi.AfterDeploymentValidation;
-import jakarta.enterprise.inject.spi.Bean;
-import jakarta.enterprise.inject.spi.BeanManager;
-import jakarta.enterprise.inject.spi.BeforeShutdown;
-import jakarta.enterprise.inject.spi.Extension;
-import org.eclipse.microprofile.config.ConfigProvider;
-
-/**
- * A CDI extension that will start the {@link GrpcServer gRPC server}.
- *
- * The server is started when the {@link AfterDeploymentValidation} event
- * is received and will be stopped when the {@link BeforeShutdown} event
- * is received.
- *
- * If no gRPC services are discovered the gRPC server will not be started.
- */
-public class GrpcServerCdiExtension implements Extension {
-
- private static final Logger LOGGER = Logger.getLogger(GrpcServerCdiExtension.class.getName());
- private static final Logger STARTUP_LOGGER = Logger.getLogger("io.helidon.microprofile.startup.server");
-
- private GrpcServer server;
-
-
- private void startServer(@Observes @Initialized(ApplicationScoped.class) Object event, BeanManager beanManager) {
- GrpcRouting.Builder routingBuilder = discoverGrpcRouting(beanManager);
-
- Config config = MpConfig.toHelidonConfig(ConfigProvider.getConfig());
- GrpcServerConfiguration.Builder serverConfiguration = GrpcServerConfiguration.builder(config.get("grpc"));
- CompletableFuture startedFuture = new CompletableFuture<>();
- CompletableFuture shutdownFuture = new CompletableFuture<>();
-
- loadExtensions(beanManager, config, routingBuilder, serverConfiguration, startedFuture, shutdownFuture);
- server = GrpcServer.create(serverConfiguration.build(), routingBuilder.build());
- long beforeT = System.nanoTime();
-
- server.start()
- .whenComplete((grpcServer, throwable) -> {
- if (null != throwable) {
- STARTUP_LOGGER.log(Level.SEVERE, throwable, () -> "gRPC server startup failed");
- startedFuture.completeExceptionally(throwable);
- } else {
- long t = TimeUnit.MILLISECONDS.convert(System.nanoTime() - beforeT, TimeUnit.NANOSECONDS);
-
- int port = grpcServer.port();
- STARTUP_LOGGER.finest("gRPC server started up");
- LOGGER.info(() -> "gRPC server started on localhost:" + port + " (and all other host addresses) "
- + "in " + t + " milliseconds.");
-
- grpcServer.whenShutdown()
- .whenComplete((server, error) -> {
- if (error == null) {
- shutdownFuture.complete(server);
- } else {
- shutdownFuture.completeExceptionally(error);
- }
- });
-
- startedFuture.complete(grpcServer);
- }
- });
-
- // inject the server into the producer so that it can be discovered later
- ServerProducer serverProducer = beanManager.createInstance().select(ServerProducer.class).get();
- serverProducer.server(server);
- }
-
- private void stopServer(@Observes BeforeShutdown event) {
- if (server != null) {
- LOGGER.info("Stopping gRPC server");
- long beforeT = System.nanoTime();
- server.shutdown()
- .whenComplete((webServer, throwable) -> {
- if (null != throwable) {
- LOGGER.log(Level.SEVERE, throwable, () -> "An error occurred stopping the gRPC server");
- } else {
- long t = TimeUnit.MILLISECONDS.convert(System.nanoTime() - beforeT, TimeUnit.NANOSECONDS);
- LOGGER.info(() -> "gRPC Server stopped in " + t + " milliseconds.");
- }
- });
- }
- }
-
- /**
- * Discover the services and interceptors to use to configure the
- * {@link GrpcRouting}.
- *
- * @param beanManager the CDI bean manager
- * @return the {@link GrpcRouting} to use or {@code null} if no services
- * or routing were discovered
- */
- private GrpcRouting.Builder discoverGrpcRouting(BeanManager beanManager) {
- Instance instance = beanManager.createInstance();
- GrpcRouting.Builder builder = GrpcRouting.builder();
-
- // discover @Grpc annotated beans
- // we use the bean manager to do this as we need the actual bean class
- beanManager.getBeans(Object.class, Any.Literal.INSTANCE)
- .stream()
- .filter(this::hasGrpcQualifier)
- .forEach(bean -> {
- Class> beanClass = bean.getBeanClass();
- Annotation[] qualifiers = bean.getQualifiers().toArray(new Annotation[0]);
- Object service = instance.select(beanClass, qualifiers).get();
- register(service, builder, beanClass, beanManager);
- });
-
- // discover beans of type GrpcService
- beanManager.getBeans(GrpcService.class)
- .forEach(bean -> {
- Class> beanClass = bean.getBeanClass();
- Annotation[] qualifiers = bean.getQualifiers().toArray(new Annotation[0]);
- Object service = instance.select(beanClass, qualifiers).get();
- builder.service((GrpcService) service);
- });
-
- // discover beans of type BindableService
- beanManager.getBeans(BindableService.class)
- .forEach(bean -> {
- Class> beanClass = bean.getBeanClass();
- Annotation[] qualifiers = bean.getQualifiers().toArray(new Annotation[0]);
- Object service = instance.select(beanClass, qualifiers).get();
- builder.service((BindableService) service);
- });
-
- return builder;
- }
-
- private boolean hasGrpcQualifier(Bean> bean) {
- return bean.getQualifiers()
- .stream()
- .anyMatch(q -> Grpc.class.isAssignableFrom(q.annotationType()));
- }
-
- /**
- * Load any instances of {@link GrpcMpExtension} discovered by the
- * {@link ServiceLoader} and allow them to further configure the
- * gRPC server.
- *
- * @param beanManager the {@link BeanManager}
- * @param config the Helidon configuration
- * @param routingBuilder the {@link GrpcRouting.Builder}
- * @param serverConfiguration the {@link GrpcServerConfiguration}
- */
- private void loadExtensions(BeanManager beanManager,
- Config config,
- GrpcRouting.Builder routingBuilder,
- GrpcServerConfiguration.Builder serverConfiguration,
- CompletionStage whenStarted,
- CompletionStage whenShutdown) {
-
- GrpcMpContext context = new GrpcMpContext() {
- @Override
- public Config config() {
- return config;
- }
-
- @Override
- public GrpcServerConfiguration.Builder grpcServerConfiguration() {
- return serverConfiguration;
- }
-
- @Override
- public GrpcRouting.Builder routing() {
- return routingBuilder;
- }
-
- @Override
- public BeanManager beanManager() {
- return beanManager;
- }
-
- @Override
- public CompletionStage whenStarted() {
- return whenStarted;
- }
-
- @Override
- public CompletionStage whenShutdown() {
- return whenShutdown;
- }
- };
-
- HelidonServiceLoader.create(ServiceLoader.load(GrpcMpExtension.class))
- .forEach(ext -> ext.configure(context));
-
- beanManager.createInstance()
- .select(GrpcMpExtension.class)
- .stream()
- .forEach(ext -> ext.configure(context));
- }
-
- /**
- * Register the service with the routing.
- *
- * The service is actually a CDI proxy so the real service.
- *
- * @param service the service to register
- * @param builder the gRPC routing
- * @param beanManager the {@link BeanManager} to use to locate beans required by the service
- */
- private void register(Object service, GrpcRouting.Builder builder, Class> cls, BeanManager beanManager) {
- GrpcServiceBuilder serviceBuilder = GrpcServiceBuilder.create(cls, () -> service, beanManager);
- if (serviceBuilder.isAnnotatedService()) {
- builder.service(serviceBuilder.build());
- } else {
- LOGGER.log(Level.WARNING,
- () -> "Discovered type is not a properly annotated gRPC service " + service.getClass());
- }
- }
-
- /**
- * A CDI producer that can supply the running {@link GrpcServer}
- * an in-process {@link Channel}.
- */
- @ApplicationScoped
- public static class ServerProducer {
-
- private GrpcServer server;
-
- /**
- * Produce the {@link GrpcServer}.
- *
- * @return the {@link GrpcServer}
- */
- @Produces
- public GrpcServer server() {
- return server;
- }
-
- /**
- * Produce a {@link Supplier} that can supply the {@link GrpcServer}.
- *
- * This could be useful where an injection point has the server injected
- * before the {@link #startServer} method has actually started it. In that
- * case a {@link Supplier Supplier<GrpcServer>} can be injected instead
- * that will be able to lazily supply the server.
- *
- * @return a {@link Supplier} that can supply the {@link GrpcServer}
- */
- @Produces
- public Supplier supply() {
- return this::server;
- }
-
- /**
- * Produces an in-process {@link Channel} to connect to the
- * running gRPC server.
- *
- * @return an in-process {@link Channel} to connect to the
- * running gRPC server
- */
- @Produces
- @InProcessGrpcChannel
- public Channel channel() {
- String name = server.configuration().name();
- return InProcessChannelBuilder.forName(name)
- .usePlaintext()
- .build();
- }
-
- /**
- * Produces an in-process {@link InProcessChannelBuilder} to
- * connect to the running gRPC server.
- *
- * @return an in-process {@link InProcessChannelBuilder} to
- * connect to the running gRPC server
- */
- @Produces
- @InProcessGrpcChannel
- public InProcessChannelBuilder channelBuilder() {
- String name = server.configuration().name();
- return InProcessChannelBuilder.forName(name);
- }
-
- void server(GrpcServer server) {
- this.server = server;
- }
- }
-}
diff --git a/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/GrpcServerConfiguration.java b/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/GrpcServerConfiguration.java
deleted file mode 100644
index 6672e62797c..00000000000
--- a/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/GrpcServerConfiguration.java
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- * Copyright (c) 2019, 2024 Oracle and/or its affiliates.
- *
- * 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.helidon.microprofile.grpc.server;
-
-import java.time.Duration;
-import java.util.Objects;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import io.helidon.common.context.Context;
-import io.helidon.config.Config;
-import io.helidon.config.metadata.Configured;
-import io.helidon.config.metadata.ConfiguredOption;
-
-/**
- * The configuration for a gRPC server.
- */
-public interface GrpcServerConfiguration {
- /**
- * The default server name.
- */
- String DEFAULT_NAME = "grpc.server";
-
- /**
- * The default grpc port.
- */
- int DEFAULT_PORT = 1408;
-
- /**
- * The default number of worker threads that will be used if not explicitly set.
- */
- int DEFAULT_WORKER_COUNT = Runtime.getRuntime().availableProcessors();
-
- /**
- * Get the server name.
- *
- * @return the server name
- */
- String name();
-
- /**
- * Get the server port.
- *
- * @return the server port
- */
- int port();
-
- /**
- * The top level {@link Context} to be used by the server.
- *
- * @return a context instance with registered application scoped instances
- */
- Context context();
-
- /**
- * Determine whether use native transport if possible.
- *
- * If native transport support is enabled, gRPC server will use epoll on
- * Linux, or kqueue on OS X. Otherwise, the standard NIO transport will
- * be used.
- *
- * @return {@code true} if native transport should be used
- */
- boolean useNativeTransport();
-
- /**
- * Returns a count of threads in s pool used to process gRPC requests.
- *
- * Default value is {@code CPU_COUNT * 2}.
- *
- * @return a workers count
- */
- int workers();
-
- /**
- * Returns a SslConfiguration to use with the server socket. If not {@code null} then
- * the server enforces an SSL communication.
- *
- * @return a TLS configuration to use
- */
- GrpcTlsDescriptor tlsConfig();
-
- /**
- * Returns the period for counting rapid resets (stream RST sent by client before any data have been sent by server).
- *
- * @return the period for counting rapid resets
- */
- Duration rapidResetCheckPeriod();
-
- /**
- * Returns the maximum allowed number of rapid resets (stream RST sent by client before any data have been sent by server).
- * When reached within {@link #rapidResetCheckPeriod()}, GOAWAY is sent to client and connection is closed.
- *
- * @return the maximum allowed number of rapid resets
- */
- int maxRapidResets();
-
- /**
- * Creates new instance with default values for all configuration properties.
- *
- * @return a new instance
- */
- static GrpcServerConfiguration create() {
- return builder().build();
- }
-
- /**
- * Creates new instance with values from external configuration.
- *
- * @param config the externalized configuration
- * @return a new instance
- */
- static GrpcServerConfiguration create(Config config) {
- return builder(config).build();
- }
-
- /**
- * Creates new instance of a {@link Builder server configuration builder}.
- *
- * @return a new builder instance
- */
- static Builder builder() {
- return new Builder();
- }
-
- /**
- * Creates new instance of a {@link Builder server configuration builder} with defaults from external configuration source.
- *
- * @param config the externalized configuration
- * @return a new builder instance
- */
- static Builder builder(Config config) {
- return new Builder().config(config);
- }
-
- /**
- * A {@link GrpcServerConfiguration} builder.
- */
- @Configured
- final class Builder implements io.helidon.common.Builder {
- private static final AtomicInteger GRPC_SERVER_COUNTER = new AtomicInteger(1);
-
- private String name = DEFAULT_NAME;
-
- private int port = DEFAULT_PORT;
-
- private boolean useNativeTransport;
-
- private int workers;
-
- private GrpcTlsDescriptor tlsConfig = null;
-
- private Context context;
-
- private int maxRapidResets = 200;
-
- private Duration rapidResetCheckPeriod = Duration.ofSeconds(30);
-
- private Builder() {
- }
-
- /**
- * Update the builder from configuration.
- *
- * @param config configuration instance
- * @return updated builder
- */
- @ConfiguredOption(key = "native",
- type = Boolean.class,
- value = "false",
- description = "Specify if native transport should be used.")
- public Builder config(Config config) {
- if (config == null) {
- return this;
- }
-
- name = config.get("name").asString().orElse(DEFAULT_NAME);
- port = config.get("port").asInt().orElse(DEFAULT_PORT);
- maxRapidResets = config.get("max-rapid-resets").asInt().orElse(200);
- rapidResetCheckPeriod = config.get("rapid-reset-check-period").as(Duration.class).orElse(Duration.ofSeconds(30));
- useNativeTransport = config.get("native").asBoolean().orElse(false);
- config.get("workers").asInt().ifPresent(this::workersCount);
-
- return this;
- }
-
- /**
- * Set the name of the gRPC server.
- *
- * Configuration key: {@code name}
- *
- * @param name the name of the gRPC server
- * @return an updated builder
- */
- @ConfiguredOption(key = "name", value = DEFAULT_NAME)
- public Builder name(String name) {
- this.name = name == null ? null : name.trim();
- return this;
- }
-
- /**
- * Sets server port. If port is {@code 0} or less then any available ephemeral port will be used.
- *
- * Configuration key: {@code port}
- *
- * @param port the server port
- * @return an updated builder
- */
- @ConfiguredOption(value = "" + DEFAULT_PORT)
- public Builder port(int port) {
- this.port = port < 0 ? 0 : port;
- return this;
- }
-
- /**
- * Period for counting rapid resets(stream RST sent by client before any data have been sent by server).
- * Default value is {@code PT30S}.
- *
- * @param rapidResetCheckPeriod duration
- * @return updated builder
- * @see ISO_8601 Durations
- * @see #maxRapidResets()
- */
- @ConfiguredOption("PT30S")
- public Builder rapidResetCheckPeriod(Duration rapidResetCheckPeriod) {
- Objects.requireNonNull(rapidResetCheckPeriod);
- this.rapidResetCheckPeriod = rapidResetCheckPeriod;
- return this;
- }
-
- /**
- * Maximum number of rapid resets(stream RST sent by client before any data have been sent by server).
- * When reached within {@link #rapidResetCheckPeriod()}, GOAWAY is sent to client and connection is closed.
- * Default value is {@code 200}.
- *
- * @param maxRapidResets maximum number of rapid resets
- * @return updated builder
- * @see #rapidResetCheckPeriod()
- */
- @ConfiguredOption("200")
- public Builder maxRapidResets(int maxRapidResets) {
- this.maxRapidResets = maxRapidResets;
- return this;
- }
-
- /**
- * Configure the application scoped context to be used as a parent for webserver request contexts.
- *
- * @param context top level context
- * @return an updated builder
- */
- public Builder context(Context context) {
- this.context = context;
- return this;
- }
-
- /**
- * Sets a count of threads in pool used to process HTTP requests.
- * Default value is {@code CPU_COUNT * 2}.
- *
- * Configuration key: {@code workers}
- *
- * @param workers a workers count
- * @return an updated builder
- */
- @ConfiguredOption(key = "workers", value = "Number of processors available to the JVM")
- public Builder workersCount(int workers) {
- this.workers = workers;
- return this;
- }
-
- /**
- * Configures TLS configuration to use with the server socket. If not {@code null} then
- * the server enforces an TLS communication.
- *
- * @param tlsConfig a TLS configuration to use
- * @return this builder
- */
- public Builder tlsConfig(GrpcTlsDescriptor tlsConfig) {
- this.tlsConfig = tlsConfig;
- return this;
- }
-
- String name() {
- return name;
- }
-
- int port() {
- return port;
- }
-
- /**
- * Current Helidon {@link Context}.
- *
- * @return current context
- */
- public Context context() {
- return context;
- }
-
- GrpcTlsDescriptor tlsConfig() {
- return tlsConfig;
- }
-
- boolean useNativeTransport() {
- return useNativeTransport;
- }
-
- int workers() {
- return workers;
- }
-
- int maxRapidResets() {
- return maxRapidResets;
- }
-
- Duration rapidResetCheckPeriod() {
- return rapidResetCheckPeriod;
- }
-
- @Override
- public GrpcServerConfiguration build() {
- if (name == null || name.isEmpty()) {
- name = DEFAULT_NAME;
- }
-
- if (port < 0) {
- port = 0;
- }
-
- if (context == null) {
- context = Context.builder()
- .id("grpc-" + GRPC_SERVER_COUNTER.getAndIncrement())
- .build();
- }
-
- if (workers <= 0) {
- workers = DEFAULT_WORKER_COUNT;
- }
-
- return GrpcServerBasicConfig.create(this);
- }
- }
-}
diff --git a/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/GrpcServerImpl.java b/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/GrpcServerImpl.java
deleted file mode 100644
index 3aa7a151e7b..00000000000
--- a/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/GrpcServerImpl.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (c) 2024 Oracle and/or its affiliates.
- *
- * 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.helidon.microprofile.grpc.server;
-
-import java.util.Map;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CompletionStage;
-
-import io.helidon.common.context.Context;
-import io.helidon.grpc.core.WeightedBag;
-import io.helidon.webserver.grpc.ServiceDescriptor;
-
-import io.grpc.ServerInterceptor;
-import org.eclipse.microprofile.health.HealthCheck;
-
-class GrpcServerImpl implements GrpcServer {
-
- static GrpcServerImpl create() {
- return new GrpcServerImpl();
- }
-
- static GrpcServerImpl create(GrpcServerConfiguration config) {
- return new GrpcServerImpl(); // TODO
- }
-
- @Override
- public GrpcServerConfiguration configuration() {
- return null;
- }
-
- @Override
- public Context context() {
- return null;
- }
-
- @Override
- public CompletionStage start() {
- return CompletableFuture.completedFuture(null);
- }
-
- @Override
- public CompletionStage whenShutdown() {
- return CompletableFuture.completedFuture(null);
- }
-
- @Override
- public CompletionStage shutdown() {
- return CompletableFuture.completedFuture(null);
- }
-
- @Override
- public HealthCheck[] healthChecks() {
- return new HealthCheck[0];
- }
-
- @Override
- public Map services() {
- return null;
- }
-
- @Override
- public boolean isRunning() {
- return false;
- }
-
- @Override
- public int port() {
- return 0;
- }
-
- public void deploy(ServiceDescriptor service, WeightedBag interceptors) {
- }
-}
diff --git a/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/GrpcTlsDescriptor.java b/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/GrpcTlsDescriptor.java
deleted file mode 100644
index d75c0ce05e8..00000000000
--- a/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/GrpcTlsDescriptor.java
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (c) 2019, 2024 Oracle and/or its affiliates.
- *
- * 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.helidon.microprofile.grpc.server;
-
-import io.helidon.common.configurable.Resource;
-import io.helidon.config.Config;
-import io.helidon.config.metadata.Configured;
-import io.helidon.config.metadata.ConfiguredOption;
-import io.helidon.config.objectmapping.Value;
-
-/**
- * GrpcTlsDescriptor contains details about configuring TLS of a {@link io.grpc.Channel}.
- */
-public class GrpcTlsDescriptor {
- private final boolean enabled;
- private final boolean jdkSSL;
- private final Resource tlsCert;
- private final Resource tlsKey;
- private final Resource tlsCaCert;
-
- private GrpcTlsDescriptor(boolean enabled, boolean jdkSSL, Resource tlsCert, Resource tlsKey, Resource tlsCaCert) {
- this.enabled = enabled;
- this.jdkSSL = jdkSSL;
- this.tlsCert = tlsCert;
- this.tlsKey = tlsKey;
- this.tlsCaCert = tlsCaCert;
- }
-
- /**
- * Return a new instance of {@link Builder}.
- *
- * @return a new instance of {@link Builder}
- */
- public static Builder builder() {
- return new Builder();
- }
-
- /**
- * Return an instance of builder based on the specified external config.
- *
- * @param config external config
- * @return an instance of builder
- */
- public static Builder builder(Config config) {
- return new Builder(config);
- }
-
- /**
- * Create an instance of a TLS configuration from external configuration source.
- *
- * @param config external config
- * @return an instance of a TLS configuration
- */
- public static GrpcTlsDescriptor create(Config config) {
- return builder(config).build();
- }
-
- /**
- * Check if TLS is enabled. If this is false, then none of the other configuration values are used.
- *
- * @return true if TLS is enabled; false otherwise
- */
- public boolean isEnabled() {
- return enabled;
- }
-
- /**
- * Check if JDK SSL has be used. Only used for TLS enabled server channels.A Ignored by client channel.
- *
- * @return true if JDK ssl has to be used; false otherwise
- */
- public boolean isJdkSSL() {
- return jdkSSL;
- }
-
- /**
- * Get the tlsCert path. Can be either client or server cert.
- *
- * @return the path to tls certificate
- */
- public Resource tlsCert() {
- return tlsCert;
- }
-
- /**
- * Get the client private key path. Can be either client or server private key.
- *
- * @return the path to tls private key
- */
- public Resource tlsKey() {
- return tlsKey;
- }
-
- /**
- * Get the CA (certificate authority) certificate path.
- *
- * @return the path to CA certificate
- */
- public Resource tlsCaCert() {
- return tlsCaCert;
- }
-
- /**
- * Builder to build a new instance of {@link GrpcTlsDescriptor}.
- */
- @Configured
- public static class Builder implements io.helidon.common.Builder {
-
- private boolean enabled = true;
- private boolean jdkSSL;
- private Resource tlsCert;
- private Resource tlsKey;
- private Resource tlsCaCert;
-
- private Builder() {
-
- }
-
- private Builder(Config config) {
- if (config == null) {
- return;
- }
-
- config.get("tls-cert.resource").as(Resource::create).ifPresent(this::tlsCert);
- config.get("tls-key.resource").as(Resource::create).ifPresent(this::tlsKey);
- config.get("tls-ca-cert.resource").as(Resource::create).ifPresent(this::tlsCaCert);
-
- this.jdkSSL = config.get("jdk-ssl").asBoolean().orElse(false);
- this.enabled = config.get("enabled").asBoolean().orElse(true);
- }
-
- /**
- * Enable or disable TLS. If enabled is false, then the rest of the TLS configuration properties are ignored.
- *
- * @param enabled true to enable, false otherwise
- * @return this instance for fluent API
- */
- @ConfiguredOption(value = "true")
- @Value(withDefault = "true")
- public Builder enabled(boolean enabled) {
- this.enabled = enabled;
- return this;
- }
-
- /**
- * Sets the type of SSL implementation to be used.
- *
- * @param jdkSSL true to use JDK based SSL, false otherwise
- * @return this instance for fluent API
- */
- @ConfiguredOption(key = "jdk-ssl", value = "false")
- public Builder jdkSSL(boolean jdkSSL) {
- this.jdkSSL = jdkSSL;
- return this;
- }
-
- /**
- * Set the client tlsCert path. Required only if mutual auth is desired.
- *
- * @param tlsCert the path to client's certificate
- * @return this instance for fluent API
- */
- @ConfiguredOption
- @Value(key = "tls-cert")
- public Builder tlsCert(Resource tlsCert) {
- this.tlsCert = tlsCert;
- return this;
- }
-
- /**
- * Set the client private key path. Required only if mutual auth is desired.
- *
- * @param tlsKey the 's TLS private key
- * @return this instance for fluent API
- */
- @ConfiguredOption
- @Value(key = "tls-key")
- public Builder tlsKey(Resource tlsKey) {
- this.tlsKey = tlsKey;
- return this;
- }
-
- /**
- * Set the CA (certificate authority) certificate path.
- *
- * @param caCert the path to CA certificate
- * @return this instance for fluent API
- */
- @ConfiguredOption(key = "tls-ca-cert")
- @Value(key = "tls-ca-cert")
- public Builder tlsCaCert(Resource caCert) {
- this.tlsCaCert = caCert;
- return this;
- }
-
- /**
- * Create and return a new instance of {@link GrpcTlsDescriptor}.
- *
- * @return a new instance of {@link GrpcTlsDescriptor}
- */
- public GrpcTlsDescriptor build() {
- return new GrpcTlsDescriptor(enabled, jdkSSL, tlsCert, tlsKey, tlsCaCert);
- }
- }
-}
diff --git a/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/spi/GrpcMpContext.java b/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/spi/GrpcMpContext.java
deleted file mode 100644
index 13b48d70123..00000000000
--- a/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/spi/GrpcMpContext.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2019, 2024 Oracle and/or its affiliates.
- *
- * 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.helidon.microprofile.grpc.server.spi;
-
-import java.util.concurrent.CompletionStage;
-
-import io.helidon.config.Config;
-import io.helidon.microprofile.grpc.server.GrpcServer;
-import io.helidon.microprofile.grpc.server.GrpcServerConfiguration;
-import io.helidon.webserver.grpc.GrpcRouting;
-
-import jakarta.enterprise.inject.spi.BeanManager;
-
-/**
- * A context to allow a microprofile gRPC server extensions to configure additional
- * services or components for the gRPC server or use the CDI bean manager.
- */
-public interface GrpcMpContext {
-
- /**
- * Obtain the Helidon configuration.
- *
- * @return the Helidon configuration
- */
- Config config();
-
- /**
- * Obtain the {@link GrpcServerConfiguration}.
- *
- * @return the {@link GrpcServerConfiguration}
- */
- GrpcServerConfiguration.Builder grpcServerConfiguration();
-
- /**
- * Obtain the {@link GrpcRouting.Builder} to allow modifications
- * to be made to the routing before the server is configured.
- *
- * @return the {@link GrpcRouting.Builder}
- */
- GrpcRouting.Builder routing();
-
- /**
- * Obtain the {@link jakarta.enterprise.inject.spi.BeanManager}.
- *
- * @return the {@link jakarta.enterprise.inject.spi.BeanManager}
- */
- BeanManager beanManager();
-
- /**
- * Return a completion stage is completed when the gRPC server is started.
- *
- * @return a completion stage is completed when the gRPC server is started
- */
- CompletionStage whenStarted();
-
- /**
- * Return a completion stage is completed when the gRPC server is shut down.
- *
- * @return a completion stage is completed when the gRPC server is shut down
- */
- CompletionStage whenShutdown();
-}
diff --git a/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/spi/GrpcMpExtension.java b/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/spi/GrpcMpExtension.java
deleted file mode 100644
index cf44c3252ed..00000000000
--- a/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/spi/GrpcMpExtension.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 2019, 2024 Oracle and/or its affiliates.
- *
- * 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.helidon.microprofile.grpc.server.spi;
-
-/**
- * Microprofile service to extend features of the gRPC server.
- */
-public interface GrpcMpExtension {
- /**
- * Allow the service to add configuration through the context.
- *
- * @param context context to obtain configuration objects
- */
- void configure(GrpcMpContext context);
-}
diff --git a/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/spi/package-info.java b/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/spi/package-info.java
deleted file mode 100644
index 5cf2f30af3d..00000000000
--- a/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/spi/package-info.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (c) 2019, 2024 Oracle and/or its affiliates.
- *
- * 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.
- */
-
-/**
- * Microprofile gRPC server implementation.
- */
-package io.helidon.microprofile.grpc.server.spi;
diff --git a/microprofile/grpc/server/src/main/java/module-info.java b/microprofile/grpc/server/src/main/java/module-info.java
index 298e1ad1c3b..c4b85ea5643 100644
--- a/microprofile/grpc/server/src/main/java/module-info.java
+++ b/microprofile/grpc/server/src/main/java/module-info.java
@@ -14,12 +14,13 @@
* limitations under the License.
*/
+import io.helidon.microprofile.grpc.server.GrpcMpCdiExtension;
+
/**
* gRPC microprofile server module
*/
module io.helidon.microprofile.grpc.server {
exports io.helidon.microprofile.grpc.server;
- exports io.helidon.microprofile.grpc.server.spi;
requires transitive io.helidon.webserver.grpc;
requires transitive io.helidon.microprofile.grpc.core;
@@ -43,12 +44,11 @@
requires io.helidon.config.metadata;
requires io.helidon.common.context;
- uses io.helidon.microprofile.grpc.server.spi.GrpcMpExtension;
- uses io.helidon.microprofile.grpc.server.GrpcServerCdiExtension;
+ uses GrpcMpCdiExtension;
uses io.helidon.microprofile.grpc.server.AnnotatedServiceConfigurer;
provides jakarta.enterprise.inject.spi.Extension
- with io.helidon.microprofile.grpc.server.GrpcServerCdiExtension;
+ with GrpcMpCdiExtension;
// needed when running with modules - to make private methods accessible
opens io.helidon.microprofile.grpc.server to weld.core.impl, io.helidon.microprofile.cdi;
diff --git a/microprofile/grpc/server/src/main/resources/META-INF/beans.xml b/microprofile/grpc/server/src/main/resources/META-INF/beans.xml
deleted file mode 100644
index a0938bff7d4..00000000000
--- a/microprofile/grpc/server/src/main/resources/META-INF/beans.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
diff --git a/microprofile/grpc/server/src/test/java/io/helidon/microprofile/grpc/server/EchoService.java b/microprofile/grpc/server/src/test/java/io/helidon/microprofile/grpc/server/EchoService.java
deleted file mode 100644
index 0180267b819..00000000000
--- a/microprofile/grpc/server/src/test/java/io/helidon/microprofile/grpc/server/EchoService.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2019, 2024 Oracle and/or its affiliates.
- *
- * 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.helidon.microprofile.grpc.server;
-
-import io.grpc.stub.StreamObserver;
-import io.helidon.grpc.server.test.Echo.EchoRequest;
-import io.helidon.grpc.server.test.Echo.EchoResponse;
-import io.helidon.microprofile.grpc.core.Grpc;
-import io.helidon.microprofile.grpc.core.Unary;
-import jakarta.enterprise.context.ApplicationScoped;
-
-import static io.helidon.grpc.core.ResponseHelper.complete;
-
-/**
- * A simple test gRPC echo service.
- */
-@Grpc
-@ApplicationScoped
-public class EchoService {
-
- /**
- * Echo the message back to the caller.
- *
- * @param request the echo request containing the message to echo
- * @param observer the call response
- */
- @Unary
- public void echo(EchoRequest request, StreamObserver observer) {
- String message = request.getMessage();
- EchoResponse response = EchoResponse.newBuilder().setMessage(message).build();
- complete(observer, response);
- }
-}
diff --git a/microprofile/grpc/server/src/test/java/io/helidon/microprofile/grpc/server/EchoServiceTest.java b/microprofile/grpc/server/src/test/java/io/helidon/microprofile/grpc/server/EchoServiceTest.java
index 9c88a54fe88..eeec93d2155 100644
--- a/microprofile/grpc/server/src/test/java/io/helidon/microprofile/grpc/server/EchoServiceTest.java
+++ b/microprofile/grpc/server/src/test/java/io/helidon/microprofile/grpc/server/EchoServiceTest.java
@@ -15,21 +15,86 @@
*/
package io.helidon.microprofile.grpc.server;
+import java.time.Duration;
+
+import io.grpc.stub.StreamObserver;
+import io.helidon.common.configurable.Resource;
+import io.helidon.common.tls.Tls;
+import io.helidon.microprofile.grpc.core.Grpc;
+import io.helidon.microprofile.grpc.core.Unary;
+import io.helidon.microprofile.grpc.server.test.Echo;
import io.helidon.microprofile.testing.junit5.AddExtension;
import io.helidon.microprofile.testing.junit5.HelidonTest;
-import jakarta.enterprise.inject.spi.CDI;
+import io.helidon.webclient.grpc.GrpcClient;
+import io.helidon.webclient.grpc.GrpcClientMethodDescriptor;
+import io.helidon.webclient.grpc.GrpcServiceDescriptor;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.client.WebTarget;
import org.junit.jupiter.api.Test;
+import static io.helidon.grpc.core.ResponseHelper.complete;
import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
@HelidonTest
-@AddExtension(GrpcServerCdiExtension.class)
+@AddExtension(GrpcMpCdiExtension.class)
class EchoServiceTest {
+ private final GrpcClient grpcClient;
+ private final GrpcServiceDescriptor serviceDescriptor;
+
+ @Inject
+ public EchoServiceTest(WebTarget webTarget) {
+ Tls clientTls = Tls.builder()
+ .trust(trust -> trust
+ .keystore(store -> store
+ .passphrase("password")
+ .trustStore(true)
+ .keystore(Resource.create("client.p12"))))
+ .build();
+ this.grpcClient = GrpcClient.builder()
+ .tls(clientTls)
+ .readTimeout(Duration.ofSeconds(300)) // debugging
+ .baseUri("https://localhost:" + webTarget.getUri().getPort())
+ .build();
+
+ this.serviceDescriptor = GrpcServiceDescriptor.builder()
+ .serviceName("EchoService")
+ .putMethod("echo",
+ GrpcClientMethodDescriptor.unary("EchoService", "echo")
+ .requestType(Echo.EchoRequest.class)
+ .responseType(Echo.EchoResponse.class)
+ .build())
+ .build();
+ }
+
@Test
void test() {
- assertThat(CDI.current(), is(notNullValue()));
+ Echo.EchoResponse res = grpcClient.serviceClient(serviceDescriptor)
+ .unary("echo", fromString("Howdy"));
+ assertThat(res.getMessage(), is("Howdy"));
+ }
+
+ private Echo.EchoRequest fromString(String value) {
+ return Echo.EchoRequest.newBuilder().setMessage(value).build();
+ }
+
+ @Grpc
+ @ApplicationScoped
+ public static class EchoService {
+
+ /**
+ * Echo the message back to the caller.
+ *
+ * @param request the echo request containing the message to echo
+ * @param observer the call response
+ */
+ @Unary
+ public void echo(Echo.EchoRequest request, StreamObserver observer) {
+ String message = request.getMessage();
+ Echo.EchoResponse response = Echo.EchoResponse.newBuilder().setMessage(message).build();
+ complete(observer, response);
+ }
}
}
diff --git a/microprofile/grpc/server/src/test/proto/echo.proto b/microprofile/grpc/server/src/test/proto/echo.proto
index 739b442d005..af0d4c50d0d 100644
--- a/microprofile/grpc/server/src/test/proto/echo.proto
+++ b/microprofile/grpc/server/src/test/proto/echo.proto
@@ -15,7 +15,7 @@
*/
syntax = "proto3";
-option java_package = "io.helidon.grpc.server.test";
+option java_package = "io.helidon.microprofile.grpc.server.test";
service EchoService {
rpc Echo (EchoRequest) returns (EchoResponse) {}
diff --git a/microprofile/grpc/server/src/test/resources/application.yaml b/microprofile/grpc/server/src/test/resources/application.yaml
new file mode 100644
index 00000000000..00b3aef2e03
--- /dev/null
+++ b/microprofile/grpc/server/src/test/resources/application.yaml
@@ -0,0 +1,30 @@
+#
+# Copyright (c) 2024 Oracle and/or its affiliates.
+#
+# 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.
+#
+
+server:
+ port: 0
+ tls:
+ trust:
+ keystore:
+ passphrase: "password"
+ trust-store: true
+ resource:
+ resource-path: "server.p12"
+ private-key:
+ keystore:
+ passphrase: "password"
+ resource:
+ resource-path: "server.p12"
diff --git a/microprofile/grpc/server/src/test/resources/client.p12 b/microprofile/grpc/server/src/test/resources/client.p12
new file mode 100644
index 00000000000..4eb3b8325cd
Binary files /dev/null and b/microprofile/grpc/server/src/test/resources/client.p12 differ
diff --git a/microprofile/grpc/server/src/test/resources/logging.properties b/microprofile/grpc/server/src/test/resources/logging.properties
index ab333c926fe..0931614a96f 100644
--- a/microprofile/grpc/server/src/test/resources/logging.properties
+++ b/microprofile/grpc/server/src/test/resources/logging.properties
@@ -18,7 +18,7 @@
# For more information see $JAVA_HOME/jre/lib/logging.properties
# Send messages to the console
-handlers=io.helidon.common.HelidonConsoleHandler
+handlers=io.helidon.logging.jul.HelidonConsoleHandler
# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread
java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n
@@ -26,9 +26,6 @@ java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$
# Global logging level. Can be overridden by specific loggers
.level=INFO
-# Component specific log levels
-#io.helidon.webserver.level=INFO
-#io.helidon.config.level=INFO
-#io.helidon.security.level=INFO
-#io.helidon.common.level=INFO
-#io.netty.level=INFO
+#io.helidon.webserver.http2.level=DEBUG
+#io.helidon.webclient.grpc.level=DEBUG
+
diff --git a/microprofile/grpc/server/src/test/resources/server.p12 b/microprofile/grpc/server/src/test/resources/server.p12
new file mode 100644
index 00000000000..ff8e4ddfc7f
Binary files /dev/null and b/microprofile/grpc/server/src/test/resources/server.p12 differ
diff --git a/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/BindableServiceImpl.java b/webserver/grpc/src/main/java/io/helidon/webserver/grpc/BindableServiceImpl.java
similarity index 96%
rename from microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/BindableServiceImpl.java
rename to webserver/grpc/src/main/java/io/helidon/webserver/grpc/BindableServiceImpl.java
index b7965ae9bc4..d71dcf860c4 100644
--- a/microprofile/grpc/server/src/main/java/io/helidon/microprofile/grpc/server/BindableServiceImpl.java
+++ b/webserver/grpc/src/main/java/io/helidon/webserver/grpc/BindableServiceImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package io.helidon.microprofile.grpc.server;
+package io.helidon.webserver.grpc;
import java.util.LinkedHashSet;
import java.util.List;
@@ -22,12 +22,9 @@
import java.util.concurrent.CompletionException;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
-import java.util.stream.Collectors;
import io.helidon.grpc.core.InterceptorWeights;
import io.helidon.grpc.core.WeightedBag;
-import io.helidon.webserver.grpc.MethodDescriptor;
-import io.helidon.webserver.grpc.ServiceDescriptor;
import io.grpc.BindableService;
import io.grpc.Metadata;
@@ -99,7 +96,7 @@ private ServerCallHandler wrapCallHandler(MethodDescr
priorityServerInterceptors.addAll(globalInterceptors);
priorityServerInterceptors.addAll(descriptor.interceptors());
priorityServerInterceptors.addAll(method.interceptors());
- List interceptors = priorityServerInterceptors.stream().collect(Collectors.toList());
+ List interceptors = priorityServerInterceptors.stream().toList();
if (!interceptors.isEmpty()) {
LinkedHashSet uniqueInterceptors = new LinkedHashSet<>(interceptors.size());
@@ -125,7 +122,7 @@ static Supplier createSupplier(Callable callable) {
}
static class CallableSupplier implements Supplier {
- private Callable callable;
+ private final Callable callable;
CallableSupplier(Callable callable) {
this.callable = callable;
diff --git a/webserver/grpc/src/main/java/io/helidon/webserver/grpc/Grpc.java b/webserver/grpc/src/main/java/io/helidon/webserver/grpc/Grpc.java
index 7ed1caedd9f..30be63b6ec7 100644
--- a/webserver/grpc/src/main/java/io/helidon/webserver/grpc/Grpc.java
+++ b/webserver/grpc/src/main/java/io/helidon/webserver/grpc/Grpc.java
@@ -50,7 +50,6 @@ static Grpc unary(Descriptors.FileDescriptor proto,
String serviceName,
String methodName,
ServerCalls.UnaryMethod method) {
-
return grpc(proto, serviceName, methodName, ServerCalls.asyncUnaryCall(method));
}
@@ -58,7 +57,6 @@ static Grpc bidi(Descriptors.FileDescriptor proto,
String serviceName,
String methodName,
ServerCalls.BidiStreamingMethod method) {
-
return grpc(proto, serviceName, methodName, ServerCalls.asyncBidiStreamingCall(method));
}
@@ -66,7 +64,6 @@ static Grpc serverStream(Descriptors.FileDescriptor pro
String serviceName,
String methodName,
ServerCalls.ServerStreamingMethod method) {
-
return grpc(proto, serviceName, methodName, ServerCalls.asyncServerStreamingCall(method));
}
@@ -74,7 +71,6 @@ static Grpc clientStream(Descriptors.FileDescriptor pro
String serviceName,
String methodName,
ServerCalls.ClientStreamingMethod method) {
-
return grpc(proto, serviceName, methodName, ServerCalls.asyncClientStreamingCall(method));
}
@@ -82,19 +78,27 @@ static Grpc clientStream(Descriptors.FileDescriptor pro
* Create a {@link io.helidon.webserver.grpc.Grpc gRPC route} from a {@link io.grpc.ServerMethodDefinition}.
*
* @param definition the {@link io.grpc.ServerMethodDefinition} representing the method to execute
- * @param proto an optional protocol buffer {@link com.google.protobuf.Descriptors.FileDescriptor}
- * containing the service definition
- * @param the request type
- * @param the response type
- *
+ * @param proto an optional protocol buffer {@link com.google.protobuf.Descriptors.FileDescriptor}
+ * containing the service definition
+ * @param the request type
+ * @param the response type
* @return a {@link io.helidon.webserver.grpc.Grpc gRPC route} created
- * from the {@link io.grpc.ServerMethodDefinition}
+ * from the {@link io.grpc.ServerMethodDefinition}
*/
static Grpc methodDefinition(ServerMethodDefinition definition,
Descriptors.FileDescriptor proto) {
return grpc(definition.getMethodDescriptor(), definition.getServerCallHandler(), proto);
}
+ public static Grpc, ?> unary(ServiceDescriptor service, io.helidon.webserver.grpc.MethodDescriptor, ?> method) {
+ String path = service.fullName() + "/" + method.name();
+ return new Grpc<>((MethodDescriptor) method.descriptor(),
+ PathMatchers.exact(path),
+ (Class) method.requestType(),
+ (Class) method.responseType(),
+ method.callHandler());
+ }
+
@Override
Grpc, ?> toGrpc(HttpPrologue grpcPrologue) {
return this;
@@ -153,15 +157,14 @@ private static Grpc grpc(Descriptors.FileDescriptor pro
/**
* Create a {@link io.helidon.webserver.grpc.Grpc gRPC route} from a {@link io.grpc.MethodDescriptor}.
*
- * @param grpcDesc the {@link io.grpc.MethodDescriptor} describing the method to execute
+ * @param grpcDesc the {@link io.grpc.MethodDescriptor} describing the method to execute
* @param callHandler the {@link io.grpc.ServerCallHandler} that will execute the method
- * @param proto an optional protocol buffer {@link com.google.protobuf.Descriptors.FileDescriptor} containing
- * the service definition
- * @param the request type
- * @param the response type
- *
+ * @param proto an optional protocol buffer {@link com.google.protobuf.Descriptors.FileDescriptor} containing
+ * the service definition
+ * @param the request type
+ * @param the response type
* @return a {@link io.helidon.webserver.grpc.Grpc gRPC route} created
- * from the {@link io.grpc.ServerMethodDefinition}
+ * from the {@link io.grpc.ServerMethodDefinition}
*/
private static Grpc grpc(MethodDescriptor grpcDesc,
ServerCallHandler callHandler,
diff --git a/webserver/grpc/src/main/java/io/helidon/webserver/grpc/GrpcRouting.java b/webserver/grpc/src/main/java/io/helidon/webserver/grpc/GrpcRouting.java
index e39d914015d..7b7ff4a0b19 100644
--- a/webserver/grpc/src/main/java/io/helidon/webserver/grpc/GrpcRouting.java
+++ b/webserver/grpc/src/main/java/io/helidon/webserver/grpc/GrpcRouting.java
@@ -23,17 +23,18 @@
import java.util.List;
import java.util.Map;
+import io.helidon.grpc.core.InterceptorWeights;
+import io.helidon.grpc.core.WeightedBag;
+import io.helidon.http.HttpPrologue;
+import io.helidon.http.PathMatchers;
+import io.helidon.webserver.Routing;
+
import com.google.protobuf.Descriptors;
import io.grpc.BindableService;
import io.grpc.ServerInterceptor;
import io.grpc.ServerMethodDefinition;
import io.grpc.ServerServiceDefinition;
import io.grpc.stub.ServerCalls;
-import io.helidon.grpc.core.InterceptorWeights;
-import io.helidon.grpc.core.WeightedBag;
-import io.helidon.http.HttpPrologue;
-import io.helidon.http.PathMatchers;
-import io.helidon.webserver.Routing;
/**
* GRPC specific routing.
@@ -102,7 +103,7 @@ public WeightedBag interceptors() {
* contained in this {@link GrpcRouting}.
*
* @return a {@link List} of the {@link ServiceDescriptor} instances
- * contained in this {@link GrpcRouting}
+ * contained in this {@link GrpcRouting}
*/
public List services() {
return services;
@@ -152,7 +153,7 @@ public Builder service(GrpcService service) {
* @return updated builder
*/
public Builder service(BindableService service) {
- throw new UnsupportedOperationException("Not implemented"); // TODO
+ return route(GrpcServiceRoute.create(service));
}
/**
@@ -167,7 +168,7 @@ public Builder service(ServiceDescriptor service) {
throw new IllegalArgumentException("Attempted to register service name " + name + " multiple times");
}
services.put(name, service);
- return this;
+ return route(GrpcServiceRoute.create(service));
}
/**
@@ -205,12 +206,12 @@ public Builder intercept(int weight, ServerInterceptor... interceptors) {
/**
* Unary route.
*
- * @param proto proto descriptor
+ * @param proto proto descriptor
* @param serviceName service name
- * @param methodName method name
- * @param method method to handle this route
- * @param request type
- * @param response type
+ * @param methodName method name
+ * @param method method to handle this route
+ * @param request type
+ * @param response type
* @return updated builder
*/
public Builder unary(Descriptors.FileDescriptor proto,
@@ -223,12 +224,12 @@ public Builder unary(Descriptors.FileDescriptor proto,
/**
* Bidirectional route.
*
- * @param proto proto descriptor
+ * @param proto proto descriptor
* @param serviceName service name
- * @param methodName method name
- * @param method method to handle this route
- * @param request type
- * @param response type
+ * @param methodName method name
+ * @param method method to handle this route
+ * @param request type
+ * @param response type
* @return updated builder
*/
public Builder bidi(Descriptors.FileDescriptor proto,
@@ -241,12 +242,12 @@ public Builder bidi(Descriptors.FileDescriptor proto,
/**
* Server streaming route.
*
- * @param proto proto descriptor
+ * @param proto proto descriptor
* @param serviceName service name
- * @param methodName method name
- * @param method method to handle this route
- * @param request type
- * @param response type
+ * @param methodName method name
+ * @param method method to handle this route
+ * @param request type
+ * @param response type
* @return updated builder
*/
public Builder serverStream(Descriptors.FileDescriptor proto,
@@ -259,12 +260,12 @@ public Builder serverStream(Descriptors.FileDescriptor proto,
/**
* Client streaming route.
*
- * @param proto proto descriptor
+ * @param proto proto descriptor
* @param serviceName service name
- * @param methodName method name
- * @param method method to handle this route
- * @param request type
- * @param response type
+ * @param methodName method name
+ * @param method method to handle this route
+ * @param request type
+ * @param response type
* @return updated builder
*/
public Builder clientStream(Descriptors.FileDescriptor proto,
@@ -277,9 +278,8 @@ public Builder clientStream(Descriptors.FileDescriptor proto,
/**
* Add all the routes for a {@link BindableService} service.
*
- * @param proto the proto descriptor
- * @param service the {@link BindableService} to add routes for
- *
+ * @param proto the proto descriptor
+ * @param service the {@link BindableService} to add routes for
* @return updated builder
*/
public Builder service(Descriptors.FileDescriptor proto, BindableService service) {
@@ -292,8 +292,7 @@ public Builder service(Descriptors.FileDescriptor proto, BindableService service
/**
* Add all the routes for the {@link ServerServiceDefinition} service.
*
- * @param service the {@link ServerServiceDefinition} to add routes for
- *
+ * @param service the {@link ServerServiceDefinition} to add routes for
* @return updated builder
*/
public Builder service(ServerServiceDefinition service) {
diff --git a/webserver/grpc/src/main/java/io/helidon/webserver/grpc/GrpcServiceRoute.java b/webserver/grpc/src/main/java/io/helidon/webserver/grpc/GrpcServiceRoute.java
index fdd0d91e76b..d4a8fd7aa3c 100644
--- a/webserver/grpc/src/main/java/io/helidon/webserver/grpc/GrpcServiceRoute.java
+++ b/webserver/grpc/src/main/java/io/helidon/webserver/grpc/GrpcServiceRoute.java
@@ -23,6 +23,7 @@
import io.helidon.http.PathMatchers;
import com.google.protobuf.Descriptors;
+import io.grpc.BindableService;
import io.grpc.stub.ServerCalls;
class GrpcServiceRoute extends GrpcRoute {
@@ -40,6 +41,35 @@ static GrpcRoute create(GrpcService service) {
return svcRouter.build();
}
+ static GrpcRoute create(BindableService service) {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ static GrpcRoute create(ServiceDescriptor service) {
+ String serviceName = service.name();
+ List> routes = new LinkedList<>();
+
+ service.methods().forEach(method -> {
+ io.grpc.MethodDescriptor, ?> descriptor = method.descriptor();
+ switch (descriptor.getType()) {
+ case UNARY -> routes.add(Grpc.unary(service, method));
+ /*
+ case CLIENT_STREAMING ->
+ routes.add(Grpc.clientStream(service, method));
+ case SERVER_STREAMING ->
+ routes.add(Grpc.serverStream(service, method));
+ case BIDI_STREAMING ->
+ routes.add(Grpc.bidi(service, method));
+ */
+ case UNKNOWN -> throw new IllegalArgumentException("gRPC method of type "
+ + descriptor.getType() + " not supported");
+ default -> throw new IllegalStateException("Invalid gRPC method type");
+ }
+ });
+
+ return new GrpcServiceRoute(serviceName, routes);
+ }
+
@Override
Grpc, ?> toGrpc(HttpPrologue prologue) {
for (Grpc, ?> route : routes) {
diff --git a/webserver/grpc/src/main/java/io/helidon/webserver/grpc/MethodDescriptor.java b/webserver/grpc/src/main/java/io/helidon/webserver/grpc/MethodDescriptor.java
index 8660e65d1ab..4903ecf2d32 100644
--- a/webserver/grpc/src/main/java/io/helidon/webserver/grpc/MethodDescriptor.java
+++ b/webserver/grpc/src/main/java/io/helidon/webserver/grpc/MethodDescriptor.java
@@ -42,14 +42,20 @@ public class MethodDescriptor {
private final ServerCallHandler callHandler;
private final Map, Object> context;
private final WeightedBag interceptors;
+ private final Class requestType;
+ private final Class responseType;
private MethodDescriptor(String name,
io.grpc.MethodDescriptor descriptor,
+ Class requestType,
+ Class responseType,
ServerCallHandler callHandler,
Map, Object> context,
WeightedBag interceptors) {
this.name = name;
this.descriptor = descriptor;
+ this.requestType = requestType;
+ this.responseType = responseType;
this.callHandler = callHandler;
this.context = context;
this.interceptors = interceptors.copyMe();
@@ -82,6 +88,24 @@ public ServerCallHandler callHandler() {
return callHandler;
}
+ /**
+ * Return the method's request type.
+ *
+ * @return request type
+ */
+ public Class requestType() {
+ return requestType;
+ }
+
+ /**
+ * Return the method's response type.
+ *
+ * @return response type
+ */
+ public Class responseType() {
+ return responseType;
+ }
+
/**
* Obtain the {@link Map} of {@link Context.Key}s and values to add to the
* call context when this method is invoked.
@@ -328,6 +352,8 @@ public MethodDescriptor build() {
return new MethodDescriptor<>(name,
descriptor.build(),
+ (Class) requestType,
+ (Class) requestType,
callHandler,
context,
interceptors);