Define protobuff file
Protocol buffer file is the base template for the communication between the server and the client.
//protobuff version
syntax = "proto3";
//package for protobuff
package calculator;
//package for java
option java_package = "com.thebytecloud.calculator";
//This option will create classes as separate files.
//If this is false, all classes will be created in the same java file.
option java_multiple_files = true;
//Error Handling
message SquareRootRequest {
int32 number = 1;
}
message SquareRootResponse {
double number_root = 1;
}
//Service is like a class which has methods for the communication.
service CalculatorService {
//Error handling
//Error will be sent if request number is negative. Error type will be INVALID_ARGUMENT
rpc FindSquareRoot(SquareRootRequest) returns (SquareRootResponse) {};
}
Generating the java classes
Running below command in the terminal will generate java files in package com.thebytecloud.calculator (option java_package)
mvn clean generate-sources
Implementing protobuff service methods
package com.thebytecloud.server;
import com.thebytecloud.calculator.*;
import io.grpc.Status;
import io.grpc.stub.StreamObserver;
public class CalculatorServiceImpl extends CalculatorServiceGrpc.CalculatorServiceImplBase {
@Override
public void findSquareRoot(SquareRootRequest request, StreamObserver<SquareRootResponse> responseObserver) {
Integer number = request.getNumber();
if(number >= 0){
double numberRoot = Math.sqrt(number);
responseObserver.onNext(SquareRootResponse.newBuilder().setNumberRoot(numberRoot).build());
responseObserver.onCompleted();
}else{
responseObserver.onError(Status.INVALID_ARGUMENT
.withDescription("The number is not positive")
.augmentDescription("Number sent: "+ number)
.asRuntimeException()
);
responseObserver.onCompleted();
}
}
}
Client Implementation
package com.thebytecloud.client;
import com.thebytecloud.calculator.*;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.StatusRuntimeException;
import io.grpc.stub.StreamObserver;
import java.util.Arrays;
import java.util.Iterator;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class CalculatorClient {
private final ManagedChannel managedChannel;
public CalculatorClient(ManagedChannel managedChannel) {
this.managedChannel = managedChannel;
}
public static void main(String[] args) throws InterruptedException {
String server = "localhost";
int serverPort = 7070;
if(System.getenv("SERVER_PORT") != null)
serverPort = Integer.parseInt(System.getenv("SERVER_PORT"));
if(System.getenv("SERVER") != null)
server = System.getenv("SERVER");
System.out.println("server = " + server+":"+serverPort);
Thread.sleep(2000);
ManagedChannel managedChannel = ManagedChannelBuilder.forAddress(server, serverPort)
.usePlaintext()
.build();
CalculatorClient calculatorClient = new CalculatorClient(managedChannel);
calculatorClient.errorHandling();
}
private void errorHandling() {
CalculatorServiceGrpc.CalculatorServiceBlockingStub stub = CalculatorServiceGrpc.newBlockingStub(managedChannel);
int number = -1;
try{
stub.findSquareRoot(SquareRootRequest.newBuilder().setNumber(number).build());
} catch (StatusRuntimeException e){
System.out.println("Exception on Square Root..."+ e.getLocalizedMessage());
e.printStackTrace();
}
}
}
Executing server and client
Executing server and client can be done via IDE or command line. Following are the commands to execute in terminal.
gRPC Server
grpc-java-examples$ mvn clean install
grpc-java-examples$ java -cp target/grpc-java-examples-1.0-SNAPSHOT-jar-with-dependencies.jar com.thebytecloud.server.CalculatorServer
serverBindPort = 7070
Starting gRPC Server...!
gRPC Client
grpc-java-examples$ java -cp target/grpc-java-examples-1.0-SNAPSHOT-jar-with-dependencies.jar com.thebytecloud.client.CalculatorClient
server = localhost:7070
Exception on Square Root...INVALID_ARGUMENT: The number is not positive
Number sent: -1
io.grpc.StatusRuntimeException: INVALID_ARGUMENT: The number is not positive
Number sent: -1
at io.grpc.stub.ClientCalls.toStatusRuntimeException(ClientCalls.java:233)
at io.grpc.stub.ClientCalls.getUnchecked(ClientCalls.java:214)
at io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:139)
at com.thebytecloud.calculator.CalculatorServiceGrpc$CalculatorServiceBlockingStub.findSquareRoot(CalculatorServiceGrpc.java:430)
at com.thebytecloud.client.CalculatorClient.errorHandling(CalculatorClient.java:185)
at com.thebytecloud.client.CalculatorClient.main(CalculatorClient.java:51)
grpc-java-examples$
Here client sending negative number for finding square root. Server found that parameter is invalid and throws error response with custom message with the number sent.