Skip to content

Commit 390358d

Browse files
committed
remote-procedure-call
1 parent fb92682 commit 390358d

30 files changed

+2006
-0
lines changed

Diff for: pom.xml

+1
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@
225225
<module>money</module>
226226
<module>table-inheritance</module>
227227
<module>bloc</module>
228+
<module>remote-procedure-call</module>
228229
</modules>
229230
<repositories>
230231
<repository>

Diff for: remote-procedure-call/README.md

+147
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
---
2+
title: Remote Procedure Call in Java using gRPC
3+
shortTitle: gRPC in Java
4+
description: Remote Procedure Call in Java using gRPC communicating between 2 microservices product and cart application
5+
category: Data Transfer
6+
language: en
7+
tag:
8+
- Behavioral
9+
- Integration
10+
- Messaging
11+
- Client-Server
12+
- Data Transfer
13+
- Microservices
14+
- Remote Procedure Call
15+
- Remote Method Invocation
16+
---
17+
# Remote Method Invocation / Remote Procedure Call
18+
Remote Method Invocation has various different aliases, Remote Procedure Call / Remote Method Invocation or RPC for short. Is a protocol
19+
that one program can use to request a service from a different program located in same or another computer in a network without having to understand network details.
20+
21+
RMI can be implemented in various different languages and frameworks. Technologies like REST, gRPC and Thrift can be used for RMI. In this example we
22+
will be using gRPC to implement Remote Procedure Call in Java.
23+
24+
## Terminologies
25+
- Client: The client is the application that sends a request to the server.
26+
- Server: The server is the application that receives the request from the client and sends a response back to the client.
27+
- Stub: The client-side proxy for the server.
28+
- Skeleton: The server-side proxy for the client.
29+
- Protocol: The set of rules that the client and server follow to communicate with each other.
30+
- Stream: The sequence of messages that are sent between the client and server, understand it as list of objects.
31+
32+
## What is gRPC?
33+
[gRPC](https://grpc.io/docs/what-is-grpc/introduction/) is a high-performance, open-source and universal RPC framework. gRPC was developed by Google but is now open-source
34+
and is based on the HTTP/2 protocol.
35+
36+
A gRPC client can call a method on a gRPC server similar to if it was calling a method on a local object.
37+
This allows client and server to communicate with each other by just using method calls. gRPC internally uses [protobuf](https://protobuf.dev/) to serialize the data for communication.
38+
39+
## When to use gRPC?
40+
gRPC should be used when you need high performance communication between client and server. It is mostly used in micro-service architecture when one
41+
service needs to communicate with another service.
42+
43+
For communication you need to define contract / interfaces denoting the method signature, data types and parameters along with return type.
44+
These methods can be called by client service just like a method call, when using gRPC, a gRPC service is created which will in-turn call the
45+
implementation of the RPC method in the server and return the response (if any).
46+
47+
Start by creating a .proto file which should have all the methods and data types you need for communication between the services.
48+
When you compile your code `maven/gradle gRPC` plugin will in return create objects and interfaces which you need to implement / extend in your
49+
server side. The client will then call the method defined in .proto file using the generated stubs by gPRC. In return inside the server the
50+
implementation of the method will be called and the response will be sent back to the client.
51+
52+
### In this example
53+
We will be using 2 different micro-services
54+
- product-service
55+
- cart-service
56+
57+
Along with a shopping.proto file to define the contract between the services.
58+
- ShoppingService
59+
60+
This is a basic e-commerce simulation.
61+
62+
In this simple example the `product-service` has data related to products and is used a source of truth. The `cart-service`
63+
needs the product data that is available in `product-service`. Certain number of products in turn may be bought by a customer,
64+
inside the cart service at which point the product quantity needs to be decreased in `product-service`, hence the need for bidirectional
65+
communication from `product-service` -> `cart-service` and vice versa they both communicate via gRPC.
66+
67+
- getAllProducts() - gets all the product from state in `product-service` and stores it in `cart-service`
68+
- reduceProductQuantity() - reduces the quantity of a product by `id` fetched by `getAllProducts` and stored in `cart-service`
69+
when the method is hit, it reduces the quantity of product with same `id` in `product-service`
70+
71+
## How to implement gRPC in Java?
72+
### .proto file
73+
- Create a [.proto](https://protobuf.dev/programming-guides/proto2/) file [example](./proto/shopping.proto) defining the service and message contracts
74+
- Define service interfaces, method signatures and data types in your .proto file
75+
### At the server end
76+
- Add gRPC and protobuf dependencies in your `pom.xml`
77+
- Include gRPC and protobuf plugins in `mvn build plugins`, for it to generate interfaces from your `.proto` during compilation
78+
- Include the .proto file directory in mvn build plugins to generate the interfaces
79+
- Build the project via `mvn clean install`
80+
- gRPC will generate the stubs and skeletons for you
81+
- Implement the service logic for the generated methods of skeleton in your service classes
82+
- Start the gRPC server at server's side on a specific port and attach the gRPC Implementation service to it
83+
### At the client end
84+
- Add gRPC and protobuf dependencies in your `pom.xml`
85+
- Include gRPC and protobuf plugins in `mvn build plugins`, for it to generate interfaces from your `.proto` during compilation
86+
- Include the .proto file directory in mvn build plugins to generate the interfaces
87+
- Build the project via `mvn clean install`
88+
- gRPC will generate the stubs and skeletons for you
89+
- A stub will expose the available methods to be called by the client, call the methods you need on server via the stub
90+
- Create Channel with server's host and port at client's end to communicate between server and client
91+
- Start client, and you are good to go
92+
93+
## gRPC in action
94+
### Product Service
95+
#### Service
96+
- ProductService - API Interface for Internal logic in `product-service`
97+
- ProductServiceImpl - Implementation of ProductService, saves product data in memory for simplicity, exposes getter(s) for the same.
98+
Houses Composition of ProductService to store state.
99+
- ProductServiceGrpcImpl - gRPC contract implementation, methods to retrieve all products and reduce quantity of a product.
100+
This file implements the logic that should be executed when gRPC methods are called
101+
102+
#### Model
103+
- Product - Product POJO Model
104+
#### Mocks
105+
- ProductMocks - Mock data of Product for testing and state initialization.
106+
107+
### Cart Service
108+
#### Service
109+
- CartService - API Interface for Internal logic in `cart-service`,
110+
- CartServiceImpl - Implementation of CartService, methods to call the stub to populate data in cart and reduce quantities.
111+
This file calls the gRPC method to communicate with `product-service`.
112+
#### Model
113+
- ProductInCart - Cut from Product POJO in `product-service`
114+
115+
### proto
116+
Proto folder contains all the proto files which define contract for the services.
117+
proto files end with .proto and contain the types, methods and services that are to be used in gRPC communication.
118+
119+
### Good practise
120+
- Keep types / method names in PascalCase in .proto file
121+
122+
### How to run this project
123+
- Clone the project
124+
- navigate to 'remote-procedure-call' directory via
125+
```shell
126+
cd java-design-patterns/remote-procedure-call
127+
```
128+
- build the project with, this will download dependencies, compile .proto to java interface and classes and create final jar
129+
```shell
130+
mvn clean install
131+
```
132+
- Start the `product-service` before `cart-service` as `cart-service` depends on product-service
133+
```shell
134+
mvn exec:java -Dexec.mainClass="com.iluwatar.rpc.product.Main" -pl product-service
135+
```
136+
- Start a new terminal session
137+
- navigate to 'remote-procedure-call' directory
138+
- Start the `cart-service`
139+
```shell
140+
mvn exec:java -Dexec.mainClass="com.iluwatar.rpc.cart.Main" -pl cart-service
141+
```
142+
- `cart-service` on startup will hit a gRPC call to `product-service` to get all products and populate the cart.
143+
- `cart-service` will then reduce the quantity of a product in `product-service` when a product is bought.
144+
- `cart-service` will then shut-down gracefully.
145+
- all the operations will be logged in the console.
146+
- `product-service` will continue to run and can be used for further operations by running `cart-service` again.
147+
- To stop the services, press `ctrl+c` in the terminal.
119 KB
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
@startuml
2+
skinparam dpi 300
3+
scale 0.3
4+
5+
package com.iluwatar.rpc.cart.model {
6+
class ProductInCart {
7+
- id : Long
8+
- name : String
9+
- price : double
10+
- quantityToReduce : int
11+
- type : String
12+
}
13+
}
14+
15+
package com.iluwatar.rpc.cart.service {
16+
interface CartService {
17+
+ getAllProducts() {abstract}
18+
+ getRandomProductFromCart() : ProductInCart {abstract}
19+
+ reduceCartQuantityFromProduct(ProductInCart) {abstract}
20+
}
21+
22+
class CartServiceImpl {
23+
- log : Logger {static}
24+
- productsInCart : List<ProductInCart>
25+
- shoppingServiceBlockingStub : ShoppingServiceBlockingStub
26+
+ CartServiceImpl(shoppingStub : ShoppingServiceBlockingStub)
27+
+ getAllProducts()
28+
+ getRandomProductFromCart() : ProductInCart
29+
+ reduceCartQuantityFromProduct(product : ProductInCart)
30+
}
31+
}
32+
33+
package com.iluwatar.rpc.proto {
34+
class Empty {}
35+
36+
class ProductResponse {
37+
- id : long
38+
- name : String
39+
- price : double
40+
- type : String
41+
}
42+
43+
class ReduceProductRequest {
44+
- productId : long
45+
- quantity : int
46+
}
47+
48+
class ReduceProductResponse {
49+
- message : String
50+
- status : boolean
51+
}
52+
53+
class ShoppingServiceImplBase {
54+
- getAllProducts(request: Empty, responseStreamObserver: StreamObserver<ProductResponse>)
55+
- reduceProductQuantity(request: ReduceProductRequest, responseStreamObserver : StreamObserver<ReduceProductResponse>)
56+
}
57+
58+
}
59+
package com.iluwatar.rpc.cart {
60+
class Main {
61+
- HOST : String {static}
62+
- SERVER_PORT : int {static}
63+
- log : Logger {static}
64+
+ main(args : String[]) {static}
65+
}
66+
}
67+
68+
CartServiceImpl --> "-productsInCart" ProductInCart
69+
CartServiceImpl ..|> CartService
70+
@enduml

Diff for: remote-procedure-call/cart-service/pom.xml

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
4+
This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
5+
6+
The MIT License
7+
Copyright © 2014-2022 Ilkka Seppälä
8+
9+
Permission is hereby granted, free of charge, to any person obtaining a copy
10+
of this software and associated documentation files (the "Software"), to deal
11+
in the Software without restriction, including without limitation the rights
12+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
copies of the Software, and to permit persons to whom the Software is
14+
furnished to do so, subject to the following conditions:
15+
16+
The above copyright notice and this permission notice shall be included in
17+
all copies or substantial portions of the Software.
18+
19+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
THE SOFTWARE.
26+
27+
-->
28+
<project xmlns="http://maven.apache.org/POM/4.0.0"
29+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
30+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
31+
32+
<parent>
33+
<artifactId>remote-procedure-call</artifactId>
34+
<groupId>com.iluwatar</groupId>
35+
<version>1.26.0-SNAPSHOT</version>
36+
</parent>
37+
38+
<modelVersion>4.0.0</modelVersion>
39+
<artifactId>cart-service</artifactId>
40+
<packaging>jar</packaging>
41+
42+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
3+
*
4+
* The MIT License
5+
* Copyright © 2014-2022 Ilkka Seppälä
6+
*
7+
* Permission is hereby granted, free of charge, to any person obtaining a copy
8+
* of this software and associated documentation files (the "Software"), to deal
9+
* in the Software without restriction, including without limitation the rights
10+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
* copies of the Software, and to permit persons to whom the Software is
12+
* furnished to do so, subject to the following conditions:
13+
*
14+
* The above copyright notice and this permission notice shall be included in
15+
* all copies or substantial portions of the Software.
16+
*
17+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
* THE SOFTWARE.
24+
*/
25+
package com.iluwatar.rpc.cart;
26+
27+
import com.iluwatar.rpc.cart.service.CartServiceImpl;
28+
import com.iluwatar.rpc.proto.ShoppingServiceGrpc;
29+
import com.iluwatar.rpc.proto.ShoppingServiceGrpc.ShoppingServiceBlockingStub;
30+
import io.grpc.ManagedChannel;
31+
import io.grpc.ManagedChannelBuilder;
32+
import java.util.concurrent.TimeUnit;
33+
import org.slf4j.Logger;
34+
import org.slf4j.LoggerFactory;
35+
36+
/**
37+
* Main class for the cart service.
38+
* Initializes the shopping channel and the cart service.
39+
*
40+
* @author CoderSleek
41+
* @version 1.0
42+
*/
43+
public class Main {
44+
private static final int SERVER_PORT = 8080;
45+
private static final String HOST = "localhost";
46+
private static final Logger log = LoggerFactory.getLogger(Main.class);
47+
/**
48+
* Main method to initialize the cart service and channel for RPC connection
49+
* initializes blocking stub and passes it to CartServiceImpl for constructor initialization.
50+
* Initializes data fetching from product-service.
51+
* shuts down after 1 request
52+
*/
53+
public static void main(String[] args) {
54+
ManagedChannel productChannel = ManagedChannelBuilder
55+
.forAddress(HOST, SERVER_PORT)
56+
.usePlaintext()
57+
.enableRetry()
58+
.keepAliveTime(10, TimeUnit.SECONDS)
59+
.build();
60+
61+
ShoppingServiceBlockingStub blockingStub = ShoppingServiceGrpc.newBlockingStub(productChannel);
62+
log.info("cart-service started");
63+
64+
var cartService = new CartServiceImpl(blockingStub);
65+
cartService.getAllProducts();
66+
67+
var productInCart = cartService.getRandomProductFromCart();
68+
productInCart.setQuantityToReduce(10);
69+
70+
cartService.reduceCartQuantityFromProduct(productInCart);
71+
productChannel.shutdown();
72+
log.info("cart-service execution successful, shutting down");
73+
}
74+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
3+
*
4+
* The MIT License
5+
* Copyright © 2014-2022 Ilkka Seppälä
6+
*
7+
* Permission is hereby granted, free of charge, to any person obtaining a copy
8+
* of this software and associated documentation files (the "Software"), to deal
9+
* in the Software without restriction, including without limitation the rights
10+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
* copies of the Software, and to permit persons to whom the Software is
12+
* furnished to do so, subject to the following conditions:
13+
*
14+
* The above copyright notice and this permission notice shall be included in
15+
* all copies or substantial portions of the Software.
16+
*
17+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
* THE SOFTWARE.
24+
*/
25+
package com.iluwatar.rpc.cart.model;
26+
27+
import lombok.Builder;
28+
import lombok.Data;
29+
30+
/**
31+
* ProductInCart is a POJO model class for product in cart.
32+
* ProductInCart is a cut from Product class in product-service
33+
*
34+
* @link com.iluwatar.rpc.product.model.Product
35+
* @author CoderSleek
36+
* @version 1.0
37+
*/
38+
@Data
39+
@Builder(toBuilder = true)
40+
public class ProductInCart {
41+
private Long id;
42+
private String name;
43+
private String type;
44+
private double price;
45+
private int quantityToReduce;
46+
}

0 commit comments

Comments
 (0)