///////////////////////////////////////////////////////////////////////////////

    Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.

    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.

///////////////////////////////////////////////////////////////////////////////

= gRPC MicroProfile Server Services
:pagename: grpc-microprofile-server
:description: Helidon gRPC MicroProfile Server-Side Services
:keywords: helidon, grpc, microprofile, micro-profile

The gRPC Microprofile APIs are an extension to <<microprofile/01_introduction.adoc, Helidon MP>> to allow building
of gRPC services and clients that integrate with the Microprofile APIs. Using Helidon gRPC MP makes building gRPC services
and clients an easier process that the traditional approach using Protobuf files and code generation. Services can be built
using POJOs that are then discovered and deployed at runtime in the same way the Helidon MP discovers and deploys web resources
in the MP http server.

Building gRPC services using Helidon gRPC MP is very simple and allows the developer to concentrate on their
application logic without needing to write a lot of boilerplate gRPC code.

== Maven Coordinates

The <<about/04_managing-dependencies.adoc, Managing Dependencies>> page describes how you
should declare dependency management for Helidon applications. Then declare the following dependency in your project:

[source,xml]
----
<dependency>
    <groupId>io.helidon.microprofile.grpc</groupId>
    <artifactId>helidon-microprofile-grpc-server</artifactId>
</dependency>
----

== Defining a Service

The traditional approach to building Java gRPC services is to write Protobuf files describing the service and then
use these to generate service stubs and finally implementing the service methods by extending the generated stub classes.
Using Helidon gRPC MP you just need to write an annotated service implementation class that is just a normal POJO.

For example:
[source,java]
.Simple gRPC Service
----
@ApplicationScoped
@io.helidon.microprofile.grpc.core.RpcService
public class StringService {

    @io.helidon.microprofile.grpc.core.Unary
    public String upper(String s) {
        return s == null ? null : s.toUpperCase();
    }
}
----

The code above is a simple service with a single unary method that just converts a String to uppercase.
The important parts in the example are the `@ApplicationScoped`, `@RpcService` and `@Unary` annotations; these,
along with other annotations discussed later, allow the gRPC MP APIs to discover, configure and deploy the service.

Of course Helidon gRPC MP does not preclude you from using the Protobuf files approach, traditional gRPC Java services
also work in a gRPC MP server.

As already shown above a Helidon gRPC MP service is just an annotated POJO. To make a class a service it requires two
annotations.

[source,java]
----
@ApplicationScoped                                <1>
@io.helidon.microprofile.grpc.core.RpcService     <2>
public class StringService {
----

<1> The `ApplicationScoped` annotation is what makes the service implementation a CDI bean and hence discoverable.
<2> The `RpcService` annotation is what defines the class as a gRPC service so that when the bean is iscovered it is
then deployed by the gRPC MP server.

=== Service Name
By default when a class is annotated with `RpcService` the class name will be used as the gRPC service name. So in the example
above the service name will be `StringService`. This can be change by supplying a name to the annotation.

[source,java]
----
@ApplicationScoped
@io.helidon.microprofile.grpc.core.RpcService(name="Strings") <1>
public class StringService {
----
<1> in the example above the name of the deployed service will be `Strings`.


== Defining Service Methods
Once a class is properly annotated to make it a gRPC MP service it needs to have service methods that implement the
application business logic. In gRPC there are four different types of method:

* Unary - a simple method with at most a single request value and returning at most a single response value.
* Server Streaming - a method that takes at most a single request value but may return zero or more response values.
* Client Streaming - a request that takes one or more request values and returns at most one response value.
* Bi-directional Streaming - a method that can take one or more request values and return zero or more response values.

The Helidon gRPC MP API determines a method type by its annotation, which should be one of the following:
[source,java]
----
@io.helidon.microprofile.grpc.core.Unary
@io.helidon.microprofile.grpc.core.ServerStreaming
@io.helidon.microprofile.grpc.core.ClientStreaming
@io.helidon.microprofile.grpc.core.Bidirectional
----

=== Request an Response Types
A gRPC service method typically takes a request parameter and returns a response value (streaming methods may take or return
multiple requests or responses). In traditional gRPC Java the types used for the request and response values must be
Protobuf serializable classes but this is not the case with Helidon gRPC. Helidon supports <<grpc/09_marshalling.adoc, pluggable Marshallers>>
and by default will support any Java primitive or Java `Serializable` as well as Protobuf types. Any type that can be marshalled
by the built-in marshallers or custom supplied marshaller may be used as a request or response type.

=== Unary Methods
A unary gRPC method is the simplest type of service method. Typically a unary method takes a request value and returns a
response value but this does not have to be the case, a unary method could just as easily take no request parameter and/or
return no response.

All of the signatures below are valid unary methods in Helidon gRPC MP.
[source,java]
----
// A unary method with a simple request and response
@io.helidon.microprofile.grpc.core.Unary
public ResponseType invoke(RequestType req)

// A unary method that just returns a response
@io.helidon.microprofile.grpc.core.Unary
public ResponseType invoke()

// A unary method that takes a request but returns no response
@io.helidon.microprofile.grpc.core.Unary
public void invoke(RequestType req)

// A unary method that takes no request and returns no response
@io.helidon.microprofile.grpc.core.Unary
public void invoke()

// An async unary request that takes a request and returns a future
// that will complete when the response is ready
@io.helidon.microprofile.grpc.core.Unary
public CompletableFuture<ResponseType> invoke(RequestType req)

// An async unary request that takes no request and returns a future
// that will complete when the response is ready
@io.helidon.microprofile.grpc.core.Unary
public CompletableFuture<ResponseType> invoke()

// The standard gRPC Java unary method signature
@io.helidon.microprofile.grpc.core.Unary
public void invoke(RequestType req, StreamObserver<ResponseType> observer)

// The standard gRPC Java unary method signature but without a request type
@io.helidon.microprofile.grpc.core.Unary
public void invoke(StreamObserver<ResponseType> observer)

// A unary method that takes a request type and a future to complete
// with the response type
@io.helidon.microprofile.grpc.core.Unary
public void invoke(RequestType req, CompletableFuture<ResponseType> observer)

// A unary method that takes no request type but just takes a future
// to complete with the response type
@io.helidon.microprofile.grpc.core.Unary
public void invoke(CompletableFuture<ResponseType> observer)
----

The various signatures supported above allow the service developer to choose the method signature that best fits their
application business logic without needing to worry about handling standard gRPC Java requests and StreamObservers. The
standard gRPC Java method signature is in the list above so it can still be used if required.

=== ServerStreaming Methods
A server streaming method receives a requests from the client and when the request stream is complete it sends back a stream
of response values. A traditional gRPC Java server streaming method takes two parameters, the request and a `StreamObserver`
that is used to send back the single response in the same way that a unary method sends a response. As with unary methods
Helidon gRPC MP supports different method signatures for server streaming methods.

All of the signatures below are valid server streaming methods in Helidon gRPC MP.
[source,java]
----
// The standard gRPC Java server streaming method signature
@io.helidon.microprofile.grpc.core.ServerStreaming
public void invoke(RequestType req, StreamObserver<ResponseType> observer)

// A server streaming method that uses a Stream to send the responses to the client
@io.helidon.microprofile.grpc.core.ServerStreaming
public Stream<ResponseType> invoke(RequestType req)

// The server streaming method without a request parameter
@io.helidon.microprofile.grpc.core.ServerStreaming
public void invoke(StreamObserver<ResponseType> observer)

// A server streaming method without a request parameter
// that uses a Stream to send the responses to the client
@io.helidon.microprofile.grpc.core.ServerStreaming
public Stream<ResponseType> invoke(RequestType req)
----

As with unary methods, the Helidon gRPC MP API supports multiple different method signatures for implementing server streaming
methods.

=== ClientStreaming Methods
A client streaming method receives a stream of requests from the client and when the request stream is complete it sends back a
response. A traditional gRPC Java client streaming method takes two `StreamObserver` parameters, one is the stream of client
requests and the other is used to send back the single response in the same way that a unary method sends a response. As with
unary methods Helidon gRPC MP supports different method signatures for client streaming methods.

All of the signatures below are valid client streaming methods in Helidon gRPC MP.
[source,java]
----
// The standard gRPC Java client streaming method signature
@io.helidon.microprofile.grpc.core.ClientStreaming
public StreamObserver<RequestType> invoke(StreamObserver<ResponseType> observer)

// The gRPC Java client streaming method with an asynchronous response
@io.helidon.microprofile.grpc.core.ClientStreaming
public StreamObserver<RequestType> invoke(CompletableFuture<ResponseType> observer)

----


=== Bi-Directional Streaming Methods
A bidirectional streaming method is a method that is a constant stream of client requests and server responses. Other than
the standard gRPC Java `StreamObserver` there are not any other built in types that make sense to use to implement
different method signatures for a bidirectional method so the only supported signature is the standard gRPC Java method.

[source,java]
----
@io.helidon.microprofile.grpc.core.Bidirectional
public StreamObserver<RequestType> invoke(StreamObserver<ResponseType> observer)
----

== Deploying Protobuf Services
Whilst the examples above show how simple it is to write gRPC services with basic POJOs there may be cases where there is a
requirement to deploy services built the traditional way using gRPC Java generated classes or built as
<<grpc/04_service_implementation.adoc,non-microprofile Helidon gRCP services>>.

=== Annotate the Service Implementation
When the gRPC MP server is starting it will discover all CDI beans of type `io.grpc.BindableService`. Service sub-classes
implemented the traditional way with code generation are instances of `BindableService` so by annotating the implementation class
with the `@ApplicationScoped` annotation they become discoverable and will be deployed into the gRPC server.

[source,java]
----
@ApplicationScoped
public class StringService 
    extends StringServiceGrpc.StringServiceImplBase {
----

In exactly the same way, if a class is an implementation of `io.helidon.grpc.server.GrpcService` then by annotating the class with
the `@ApplicationScoped` annotation it will be discovered and deployed when the MP gRPC server starts.

[source,java]
----
@ApplicationScoped
public class StringService implements GrpcService {
----

=== Implement a GrpcMpExtension
If it is not possible to annotate the service class (for example the code is built by a third party) another way to deploy none
CDI bean services is to implement a gRPC MP server extension.
The extension will then be called when the MP server is starting and be given the chance to add additional services for deployment.
An extension should implement the `io.helidon.microprofile.grpc.server.spi.GrpcMpExtension` interface.

For example, assuming that there was a gRPC service class called `StringService` that needed to be deployed an extension class
might look like this:
[source,java]
----
public class MyExtension
        implements GrpcMpExtension {
    @Override
    public void configure(GrpcMpContext context) {  <1>
        context.routing()
               .register(new ServiceService());     <2>
    }
}
----

<1> The `configure` method of the extension will be called to allow the extension to add extra configuration to the server.
<2> In this example an instance of the `StringService` is registered with the routing (as described in
the <<grpc/03_routing.adoc,basic gRPC server documentation>>).

The `GrpcMpExtension` instances are discovered and loaded using the service loader so for the example above to work a file
`META-INF/services/io.helidon.microprofile.grpc.server.spi.GrpcMpExtension` would need to be created that contained the names
of the service implementations.

