/ Java

GRPC Server Side Implementation in Java

gRPC is a high performance, open source RPC framework developed by Google where a client application can directly call a server method as if it was a local object. Let’s see how we can develop server application using gRPC protocol. Here we will use Java Spring for server application.

Add Dependencies

Add those dependencies in pom.xml

<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-netty</artifactId>
    <version>1.12.0</version>
</dependency>
<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-protobuf</artifactId>
    <version>1.12.0</version>
</dependency>
<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-stub</artifactId>
    <version>1.12.0</version>
</dependency>

To generate protobuf-based code we will use protobuf-maven-plugin for this we need to put all proto files in src/main/proto directory. To add the plugin with maven build system add those line in pom.xml

<build>
    <extensions>
        <extension>
            <groupId>kr.motd.maven</groupId>
            <artifactId>os-maven-plugin</artifactId>
            <version>1.5.0.Final</version>
        </extension>
    </extensions>
    <plugins>
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.6</version>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.xolstice.maven.plugins</groupId>
            <artifactId>protobuf-maven-plugin</artifactId>
            <version>0.5.1</version>
            <configuration>
                <protocArtifact>com.google.protobuf:protoc:3.5.1-1:exe:${os.detected.classifier}</protocArtifact>
                <pluginId>grpc-java</pluginId>
                <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.12.0:exe:${os.detected.classifier}</pluginArtifact>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                        <goal>compile-custom</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

There two plugins. First one is os-maven-plugin, it will determine current operation system and will save that value into a variable called os.detected.classifier. This is important because the protoc (compiler) is native code. Depending on OS (windows, linux, mac) it will find appropriate binary to use to compile proto definition file. Second plugin is to tie os-maven-plugin (first plugin) into maven build system so that whenever youwill compile something it will generate gRPC related classes for you.

Defining the Service

Time to define our service that will be called remotely along with their parameters. We need to define our service and payload messages in .proto file using the protocol buffres Now create LoginService.proto file under src/main/proto directory and insert below code

syntax = "proto3";

option java_multiple_files = true;
option java_generic_services = true;
package com.example.learn;

message LoginRequest {
    string username = 1;
    string password = 2;
}

message LoginResponse {
    int32 responseCode = 1;
    string message = 2;
}

service LoginService {
    rpc logIn (LoginRequest) returns (LoginResponse);
}

By default protoc will generate all the messages by warping it into another class. But by adding option java_multiple_files = true we can instruct to generate individual file. message keyword is used to define request and response message and service keyword is used to define services. Here defined a Login service. Client will call the logIn method with LoginRequest message and will get LoginResponse message as response of the call.

This is definition language. This actually does not generate any Java file yet. There is multiple ways to generate Java file for the proto file. We already added the required plugins, now just open terminal and run mvn install . It will generate all the necessary Java files for you.

Service Implementation

To Implement the Login Service we need to extend LoginServiceImplBase class and overrive the login method

public class LoginServiceImp extends LoginServiceGrpc.LoginServiceImplBase {

    @Override
    public void logIn(LoginRequest request, StreamObserver<LoginResponse> responseObserver) {
        System.out.println(request);

        responseObserver
                .onNext(checkLoginCredential(request.getUsername(), request.getPassword()));

        responseObserver.onCompleted();
    }

    private LoginResponse checkLoginCredential(String username, String password) {
        UserRecord userRecord = UserRecord.getInstance();

        LoginResponse.Builder responseBuilder = LoginResponse.newBuilder();
        if (userRecord.isUserMatch(username, password)) {
            responseBuilder.setResponseCode(200)
                    .setMessage("Login Success");
        } else {
            responseBuilder.setResponseCode(400)
                    .setMessage("Login Failed");
        }

        return responseBuilder.build();
    }
}

Here UserRecord class is responsible for store and validate user details and checkLoginCredential method is responsible for building appropriate response message deepening on username and password.

To make an instance of messages we need to use builder patter of it. gRPC also use Observable pattern so to send a response we need to call onNext method, onError method to send an error. After finishing all the task we need to call onComplete to let the client to that the response is finished otherwise the connection will be hung and client will wait for more response. Our Service is ready now time to start a server to use this service.

Running the gRPC Server

We need to start the gRPC server to listen for incoming request

public static void main(String[] arg) {
        try {
            Server server = ServerBuilder.forPort(8080)
                    .addService(new LoginServiceImp())
                    .build();
            server.start();
            System.out.println("Server has started ========");

            server.awaitTermination();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

We use the builder to create gRPC server and add the login server we have implemented. start() method will start the server and awaitTermination() method will keep the server running in foreground.

You will find the sources over on GitHub.