diff --git a/pom.xml b/pom.xml
index 5ac889f7f24f..989d5d436f90 100644
--- a/pom.xml
+++ b/pom.xml
@@ -225,6 +225,7 @@
     <module>money</module>
     <module>table-inheritance</module>
     <module>bloc</module>
+	<module>remote-procedure-call</module>
   </modules>
   <repositories>
     <repository>
diff --git a/remote-procedure-call/README.md b/remote-procedure-call/README.md
new file mode 100644
index 000000000000..58c2b7eb3a9d
--- /dev/null
+++ b/remote-procedure-call/README.md
@@ -0,0 +1,147 @@
+---
+title: Remote Procedure Call in Java using gRPC
+shortTitle: gRPC in Java
+description: Remote Procedure Call in Java using gRPC communicating between 2 microservices product and cart application
+category: Data Transfer
+language: en
+tag:
+- Behavioral
+- Integration
+- Messaging
+- Client-Server
+- Data Transfer
+- Microservices
+- Remote Procedure Call
+- Remote Method Invocation
+---
+# Remote Method Invocation / Remote Procedure Call
+Remote Method Invocation has various different aliases, Remote Procedure Call / Remote Method Invocation or RPC for short. Is a protocol
+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.
+
+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
+will be using gRPC to implement Remote Procedure Call in Java.
+
+## Terminologies
+- Client: The client is the application that sends a request to the server.
+- Server: The server is the application that receives the request from the client and sends a response back to the client.
+- Stub: The client-side proxy for the server.
+- Skeleton: The server-side proxy for the client.
+- Protocol: The set of rules that the client and server follow to communicate with each other.
+- Stream: The sequence of messages that are sent between the client and server, understand it as list of objects.
+
+## What is gRPC?
+[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
+and is based on the HTTP/2 protocol.
+
+A gRPC client can call a method on a gRPC server similar to if it was calling a method on a local object.
+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.
+
+## When to use gRPC?
+gRPC should be used when you need high performance communication between client and server. It is mostly used in micro-service architecture when one
+service needs to communicate with another service.
+
+For communication you need to define contract / interfaces denoting the method signature, data types and parameters along with return type.
+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
+implementation of the RPC method in the server and return the response (if any).
+
+Start by creating a .proto file which should have all the methods and data types you need for communication between the services.
+When you compile your code `maven/gradle gRPC` plugin will in return create objects and interfaces which you need to implement / extend in your
+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
+implementation of the method will be called and the response will be sent back to the client.
+
+### In this example
+We will be using 2 different micro-services
+- product-service
+- cart-service
+
+Along with a shopping.proto file to define the contract between the services.
+- ShoppingService
+
+This is a basic e-commerce simulation.
+
+In this simple example the `product-service` has data related to products and is used a source of truth. The `cart-service`
+needs the product data that is available in `product-service`. Certain number of products in turn may be bought by a customer,
+inside the cart service at which point the product quantity needs to be decreased in `product-service`, hence the need for bidirectional
+communication from `product-service` -> `cart-service` and vice versa they both communicate via gRPC.
+
+- getAllProducts() - gets all the product from state in `product-service` and stores it in `cart-service`
+- reduceProductQuantity() - reduces the quantity of a product by `id` fetched by `getAllProducts` and stored in `cart-service`
+ when the method is hit, it reduces the quantity of product with same `id` in `product-service`
+
+## How to implement gRPC in Java?
+### .proto file
+- Create a [.proto](https://protobuf.dev/programming-guides/proto2/) file [example](./proto/shopping.proto) defining the service and message contracts
+- Define service interfaces, method signatures and data types in your .proto file
+### At the server end
+- Add gRPC and protobuf dependencies in your `pom.xml`
+- Include gRPC and protobuf plugins in `mvn build plugins`, for it to generate interfaces from your `.proto` during compilation
+- Include the .proto file directory in mvn build plugins to generate the interfaces
+- Build the project via `mvn clean install`
+- gRPC will generate the stubs and skeletons for you
+- Implement the service logic for the generated methods of skeleton in your service classes
+- Start the gRPC server at server's side on a specific port and attach the gRPC Implementation service to it
+### At the client end
+- Add gRPC and protobuf dependencies in your `pom.xml`
+- Include gRPC and protobuf plugins in `mvn build plugins`, for it to generate interfaces from your `.proto` during compilation
+- Include the .proto file directory in mvn build plugins to generate the interfaces
+- Build the project via `mvn clean install`
+- gRPC will generate the stubs and skeletons for you
+- A stub will expose the available methods to be called by the client, call the methods you need on server via the stub
+- Create Channel with server's host and port at client's end to communicate between server and client
+- Start client, and you are good to go
+
+## gRPC in action
+### Product Service
+#### Service
+- ProductService - API Interface for Internal logic in `product-service`
+- ProductServiceImpl - Implementation of ProductService, saves product data in memory for simplicity, exposes getter(s) for the same.
+ Houses Composition of ProductService to store state.
+- ProductServiceGrpcImpl - gRPC contract implementation, methods to retrieve all products and reduce quantity of a product.
+This file implements the logic that should be executed when gRPC methods are called
+     
+#### Model
+- Product - Product POJO Model
+#### Mocks
+- ProductMocks - Mock data of Product for testing and state initialization.
+
+### Cart Service
+#### Service
+- CartService - API Interface for Internal logic in `cart-service`, 
+- CartServiceImpl - Implementation of CartService, methods to call the stub to populate data in cart and reduce quantities.
+ This file calls the gRPC method to communicate with `product-service`.
+#### Model
+- ProductInCart - Cut from Product POJO in `product-service`
+
+### proto
+Proto folder contains all the proto files which define contract for the services.
+proto files end with .proto and contain the types, methods and services that are to be used in gRPC communication.
+
+### Good practise
+- Keep types / method names in PascalCase in .proto file
+
+### How to run this project
+- Clone the project
+- navigate to 'remote-procedure-call' directory via
+```shell
+cd java-design-patterns/remote-procedure-call
+```
+- build the project with, this will download dependencies, compile .proto to java interface and classes and create final jar
+```shell
+mvn clean install
+```
+- Start the `product-service` before `cart-service` as `cart-service` depends on product-service
+```shell
+mvn exec:java -Dexec.mainClass="com.iluwatar.rpc.product.Main" -pl product-service
+```
+- Start a new terminal session
+- navigate to 'remote-procedure-call' directory
+- Start the `cart-service`
+```shell
+mvn exec:java -Dexec.mainClass="com.iluwatar.rpc.cart.Main" -pl cart-service
+```
+- `cart-service` on startup will hit a gRPC call to `product-service` to get all products and populate the cart.
+- `cart-service` will then reduce the quantity of a product in `product-service` when a product is bought.
+- `cart-service` will then shut-down gracefully.
+- all the operations will be logged in the console.
+- `product-service` will continue to run and can be used for further operations by running `cart-service` again.
+- To stop the services, press `ctrl+c` in the terminal.
diff --git a/remote-procedure-call/cart-service/etc/cart-service.urm.png b/remote-procedure-call/cart-service/etc/cart-service.urm.png
new file mode 100644
index 000000000000..ab374fa9732b
Binary files /dev/null and b/remote-procedure-call/cart-service/etc/cart-service.urm.png differ
diff --git a/remote-procedure-call/cart-service/etc/cart-service.urm.puml b/remote-procedure-call/cart-service/etc/cart-service.urm.puml
new file mode 100644
index 000000000000..b49796603e31
--- /dev/null
+++ b/remote-procedure-call/cart-service/etc/cart-service.urm.puml
@@ -0,0 +1,70 @@
+@startuml
+skinparam dpi 300
+scale 0.3
+
+package com.iluwatar.rpc.cart.model {
+  class ProductInCart {
+    - id : Long
+    - name : String
+    - price : double
+    - quantityToReduce : int
+    - type : String
+  }
+}
+
+package com.iluwatar.rpc.cart.service {
+  interface CartService {
+    + getAllProducts() {abstract}
+    + getRandomProductFromCart() : ProductInCart {abstract}
+    + reduceCartQuantityFromProduct(ProductInCart) {abstract}
+  }
+
+  class CartServiceImpl {
+    - log : Logger {static}
+    - productsInCart : List<ProductInCart>
+    - shoppingServiceBlockingStub : ShoppingServiceBlockingStub
+    + CartServiceImpl(shoppingStub : ShoppingServiceBlockingStub)
+    + getAllProducts()
+    + getRandomProductFromCart() : ProductInCart
+    + reduceCartQuantityFromProduct(product : ProductInCart)
+  }
+}
+
+package com.iluwatar.rpc.proto {
+  class Empty {}
+
+  class ProductResponse {
+    - id : long
+    - name : String
+    - price : double
+    - type : String
+  }
+
+  class ReduceProductRequest {
+    - productId : long
+    - quantity : int
+  }
+
+  class ReduceProductResponse {
+    - message : String
+    - status : boolean
+  }
+
+  class ShoppingServiceImplBase {
+    - getAllProducts(request: Empty, responseStreamObserver: StreamObserver<ProductResponse>)
+    - reduceProductQuantity(request: ReduceProductRequest, responseStreamObserver : StreamObserver<ReduceProductResponse>)
+  }
+
+}
+package com.iluwatar.rpc.cart {
+  class Main {
+    - HOST : String {static}
+    - SERVER_PORT : int {static}
+    - log : Logger {static}
+    + main(args : String[]) {static}
+  }
+}
+
+CartServiceImpl -->  "-productsInCart" ProductInCart
+CartServiceImpl ..|> CartService
+@enduml
\ No newline at end of file
diff --git a/remote-procedure-call/cart-service/pom.xml b/remote-procedure-call/cart-service/pom.xml
new file mode 100644
index 000000000000..7fad34a3edb6
--- /dev/null
+++ b/remote-procedure-call/cart-service/pom.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+
+    The MIT License
+    Copyright © 2014-2022 Ilkka Seppälä
+
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+	<parent>
+        <artifactId>remote-procedure-call</artifactId>
+        <groupId>com.iluwatar</groupId>
+        <version>1.26.0-SNAPSHOT</version>
+	</parent>
+
+    <modelVersion>4.0.0</modelVersion>
+	<artifactId>cart-service</artifactId>
+    <packaging>jar</packaging>
+
+</project>
\ No newline at end of file
diff --git a/remote-procedure-call/cart-service/src/main/java/com/iluwatar/rpc/cart/Main.java b/remote-procedure-call/cart-service/src/main/java/com/iluwatar/rpc/cart/Main.java
new file mode 100644
index 000000000000..db8bd1738ee5
--- /dev/null
+++ b/remote-procedure-call/cart-service/src/main/java/com/iluwatar/rpc/cart/Main.java
@@ -0,0 +1,74 @@
+/*
+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.rpc.cart;
+
+import com.iluwatar.rpc.cart.service.CartServiceImpl;
+import com.iluwatar.rpc.proto.ShoppingServiceGrpc;
+import com.iluwatar.rpc.proto.ShoppingServiceGrpc.ShoppingServiceBlockingStub;
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
+import java.util.concurrent.TimeUnit;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Main class for the cart service.
+ * Initializes the shopping channel and the cart service.
+ *
+ * @author CoderSleek
+ * @version 1.0
+ */
+public class Main {
+  private static final int SERVER_PORT = 8080;
+  private static final String HOST = "localhost";
+  private static final Logger log = LoggerFactory.getLogger(Main.class);
+  /**
+   * Main method to initialize the cart service and channel for RPC connection
+   * initializes blocking stub and passes it to CartServiceImpl for constructor initialization.
+   * Initializes data fetching from product-service.
+   * shuts down after 1 request
+   */
+  public static void main(String[] args) {
+    ManagedChannel productChannel = ManagedChannelBuilder
+        .forAddress(HOST, SERVER_PORT)
+        .usePlaintext()
+        .enableRetry()
+        .keepAliveTime(10, TimeUnit.SECONDS)
+        .build();
+
+    ShoppingServiceBlockingStub blockingStub = ShoppingServiceGrpc.newBlockingStub(productChannel);
+    log.info("cart-service started");
+
+    var cartService = new CartServiceImpl(blockingStub);
+    cartService.getAllProducts();
+
+    var productInCart = cartService.getRandomProductFromCart();
+    productInCart.setQuantityToReduce(10);
+
+    cartService.reduceCartQuantityFromProduct(productInCart);
+    productChannel.shutdown();
+    log.info("cart-service execution successful, shutting down");
+  }
+}
\ No newline at end of file
diff --git a/remote-procedure-call/cart-service/src/main/java/com/iluwatar/rpc/cart/model/ProductInCart.java b/remote-procedure-call/cart-service/src/main/java/com/iluwatar/rpc/cart/model/ProductInCart.java
new file mode 100644
index 000000000000..522dce357f5d
--- /dev/null
+++ b/remote-procedure-call/cart-service/src/main/java/com/iluwatar/rpc/cart/model/ProductInCart.java
@@ -0,0 +1,46 @@
+/*
+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.rpc.cart.model;
+
+import lombok.Builder;
+import lombok.Data;
+
+/**
+ * ProductInCart is a POJO model class for product in cart.
+ * ProductInCart is a cut from Product class in product-service
+ *
+ * @link com.iluwatar.rpc.product.model.Product
+ * @author CoderSleek
+ * @version 1.0
+ */
+@Data
+@Builder(toBuilder = true)
+public class ProductInCart {
+  private Long id;
+  private String name;
+  private String type;
+  private double price;
+  private int quantityToReduce;
+}
diff --git a/remote-procedure-call/cart-service/src/main/java/com/iluwatar/rpc/cart/service/CartService.java b/remote-procedure-call/cart-service/src/main/java/com/iluwatar/rpc/cart/service/CartService.java
new file mode 100644
index 000000000000..e6720f439cd4
--- /dev/null
+++ b/remote-procedure-call/cart-service/src/main/java/com/iluwatar/rpc/cart/service/CartService.java
@@ -0,0 +1,61 @@
+/*
+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.rpc.cart.service;
+
+import com.iluwatar.rpc.cart.model.ProductInCart;
+
+/**
+ * API Contract for Cart service, which can be exposed.
+ * Includes contract method for grpc stub as well.
+ * Thread safety is not guaranteed.
+ * @link com.iluwatar.rpc.cart.model.ProductInCart
+ * @author CoderSleek
+ * @version 1.0
+ */
+public interface CartService {
+  /**
+   * returns a random product from cart, if cart is empty throws IllegalStateException.
+   * randomized just for demonstration purposes.
+   *
+   * @return randomly chosen ProductInCart from List of ProductInCart
+   * @throws IllegalStateException if cart is empty
+   */
+  ProductInCart getRandomProductFromCart() throws IllegalStateException;
+
+  /**
+   * reduces the quantity of a product from cart by doing a RPC call to product service.
+   *
+   * @param product product whose quantity needs to be reduced in product-service
+   * @throws IllegalArgumentException if product is null or id invalid
+   * @throws IllegalStateException if product is not found in cart or cart is null
+   */
+  void reduceCartQuantityFromProduct(ProductInCart product)
+      throws IllegalStateException, IllegalArgumentException;
+
+  /**
+   * RPC call to get all the products from product-service and add them to cart.
+   */
+  void getAllProducts();
+}
diff --git a/remote-procedure-call/cart-service/src/main/java/com/iluwatar/rpc/cart/service/CartServiceImpl.java b/remote-procedure-call/cart-service/src/main/java/com/iluwatar/rpc/cart/service/CartServiceImpl.java
new file mode 100644
index 000000000000..c647bde3110d
--- /dev/null
+++ b/remote-procedure-call/cart-service/src/main/java/com/iluwatar/rpc/cart/service/CartServiceImpl.java
@@ -0,0 +1,132 @@
+/*
+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.rpc.cart.service;
+
+import com.iluwatar.rpc.cart.model.ProductInCart;
+import com.iluwatar.rpc.proto.Shopping.ReduceProductRequest;
+import com.iluwatar.rpc.proto.Shopping.ReduceProductResponse;
+import com.iluwatar.rpc.proto.ShoppingServiceGrpc.ShoppingServiceBlockingStub;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implementation of cart-service Contract exposed by gRPC proto.
+ * Thread safety is not guaranteed.
+ * @link com.iluwatar.rpc.cart.model.ProductInCart
+ * @link com.iluwatar.rpc.cart.service.CartService
+ * @author CoderSleek
+ * @version 1.0
+ */
+public class CartServiceImpl implements CartService {
+  private final ShoppingServiceBlockingStub shoppingServiceBlockingStub;
+  private final List<ProductInCart> productsInCart = new ArrayList<>();
+  private static final Logger log = LoggerFactory.getLogger(CartServiceImpl.class);
+
+  /**
+   * Constructor to initialize CartServiceImpl with ProductServiceBlockingStub.
+   * blocking-stub is initialized in Main
+   * @param shoppingStub ProductServiceBlockingStub
+   * @throws IllegalArgumentException if ProductServiceBlockingStub is null
+   */
+  public CartServiceImpl(ShoppingServiceBlockingStub shoppingStub) {
+    if (shoppingStub == null) {
+      throw new IllegalArgumentException("ShoppingServiceBlockingStub is null");
+    }
+    this.shoppingServiceBlockingStub = shoppingStub;
+  }
+
+  @Override
+  public void reduceCartQuantityFromProduct(ProductInCart product)
+      throws IllegalArgumentException, IllegalStateException {
+    log.info("Started Request for reducing product quantity from cart in product-service");
+    if (product == null) {
+      throw new IllegalArgumentException("Product state is null");
+    }
+    if (product.getId() <= 0) {
+      throw new IllegalArgumentException("Invalid Product id");
+    }
+    if (productsInCart.isEmpty()) {
+      throw new IllegalStateException("Products In cart array empty, populate cart first");
+    }
+
+    // type exposed and maintained in gRPC proto
+    ReduceProductRequest request = ReduceProductRequest
+        .newBuilder()
+        .setProductId(product.getId())
+        .setQuantity(product.getQuantityToReduce())
+        .build();
+
+    log.info("Initiating RPC call to reduce quantity of product with id: {}", product.getId());
+    ReduceProductResponse response = shoppingServiceBlockingStub.reduceProductQuantity(request);
+    log.info("Completed RPC call reduce quantity with status: {}", response.getStatus());
+    log.info("RPC call response message: {}", response.getMessage());
+    log.info("Completed Request for reducing product quantity from cart in product-service");
+  }
+
+  @Override
+  public void getAllProducts() {
+    log.info("Started request to fetch all products from product-service");
+    // stream of products / multiple products
+    try {
+      shoppingServiceBlockingStub.getAllProducts(null)
+          .forEachRemaining(product ->
+              productsInCart.add(ProductInCart.builder()
+                  .name(product.getName())
+                  .id(product.getId())
+                  .price(product.getPrice())
+                  .type(product.getType())
+                  .quantityToReduce(0)
+                  .build())
+          );
+    } catch (Exception e) {
+      log.error("Error occurred while fetching products: ", e);
+      throw new IllegalStateException("Failed to fetch products from ProductService", e);
+    }
+    log.info("Fetching of products completed");
+  }
+
+  /**
+   * returns a random product from cart, if cart is empty throws IllegalStateException.
+   * randomized just for demonstration purposes.
+   * returns a new instance of ProductInCart to avoid mutation of quantityToReduce in original object.
+   *
+   * @return randomly chosen ProductInCart from List of ProductInCart
+   * @throws IllegalStateException if cart is empty
+   */
+  @Override
+  public ProductInCart getRandomProductFromCart() throws IllegalStateException {
+    if (productsInCart.isEmpty()) {
+      throw new IllegalStateException("Products In cart array empty");
+    }
+
+    // randomly choose a product for dynamic results
+    int randInt = new Random().nextInt(productsInCart.size());
+    // to builder is used to return a copy of the object to avoid mutation of original object
+    return productsInCart.get(randInt).toBuilder().build();
+  }
+}
diff --git a/remote-procedure-call/cart-service/src/main/resources/logback.xml b/remote-procedure-call/cart-service/src/main/resources/logback.xml
new file mode 100644
index 000000000000..ed930c512e7e
--- /dev/null
+++ b/remote-procedure-call/cart-service/src/main/resources/logback.xml
@@ -0,0 +1,12 @@
+<!-- to ensure only info and error logging -->
+<configuration>
+    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
+        </encoder>
+    </appender>
+
+    <root level="INFO">
+        <appender-ref ref="CONSOLE" />
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/remote-procedure-call/cart-service/src/test/java/com/iluwatar/rpc/cart/service/CartServiceImplIntegrationTest.java b/remote-procedure-call/cart-service/src/test/java/com/iluwatar/rpc/cart/service/CartServiceImplIntegrationTest.java
new file mode 100644
index 000000000000..64bdbe46eb20
--- /dev/null
+++ b/remote-procedure-call/cart-service/src/test/java/com/iluwatar/rpc/cart/service/CartServiceImplIntegrationTest.java
@@ -0,0 +1,96 @@
+/*
+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.rpc.cart.service;
+
+import com.iluwatar.rpc.cart.model.ProductInCart;
+import com.iluwatar.rpc.proto.ShoppingServiceGrpc.ShoppingServiceBlockingStub;
+import com.iluwatar.rpc.proto.Shopping.ProductResponse;
+import com.iluwatar.rpc.proto.Shopping.ReduceProductRequest;
+import com.iluwatar.rpc.proto.Shopping.ReduceProductResponse;
+import java.util.ArrayList;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+class CartServiceImplIntegrationTest {
+
+  @Mock
+  private ShoppingServiceBlockingStub productServiceBlockingStub;
+
+  @InjectMocks
+  private CartServiceImpl cartService;
+
+  private ProductResponse product;
+
+  @BeforeEach
+  public void setUp() {
+    product = ProductResponse.newBuilder()
+        .setId(1)
+        .setName("Test")
+        .setPrice(100)
+        .setType("Test")
+        .build();
+
+    ArrayList<ProductResponse> productList = new ArrayList<>();
+
+    productList.add(product);
+    when(productServiceBlockingStub.getAllProducts(null)).thenReturn(productList.iterator());
+    cartService.getAllProducts();
+  }
+
+  @Test
+  void testGetRandomProductFromCartAndReduceQuantity_Success() {
+    ProductInCart randomProduct = cartService.getRandomProductFromCart();
+
+    assertNotNull(randomProduct);
+    assertEquals(product.getId(), randomProduct.getId());
+    assertEquals(product.getName(), randomProduct.getName());
+    randomProduct.setQuantityToReduce(100);
+
+    ReduceProductResponse response = ReduceProductResponse.newBuilder()
+        .setStatus(true)
+        .setMessage("Success")
+        .build();
+
+    when(productServiceBlockingStub.reduceProductQuantity(
+        any(ReduceProductRequest.class)
+    )).thenReturn(response);
+    cartService.reduceCartQuantityFromProduct(randomProduct);
+
+    verify(productServiceBlockingStub, times(1)).reduceProductQuantity(
+        any(ReduceProductRequest.class));
+  }
+}
\ No newline at end of file
diff --git a/remote-procedure-call/cart-service/src/test/java/com/iluwatar/rpc/cart/service/CartServiceImplTest.java b/remote-procedure-call/cart-service/src/test/java/com/iluwatar/rpc/cart/service/CartServiceImplTest.java
new file mode 100644
index 000000000000..6cd2ccdd627c
--- /dev/null
+++ b/remote-procedure-call/cart-service/src/test/java/com/iluwatar/rpc/cart/service/CartServiceImplTest.java
@@ -0,0 +1,168 @@
+/*
+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.rpc.cart.service;
+
+import com.iluwatar.rpc.cart.model.ProductInCart;
+import com.iluwatar.rpc.proto.ShoppingServiceGrpc.ShoppingServiceBlockingStub;
+import com.iluwatar.rpc.proto.Shopping;
+import com.iluwatar.rpc.proto.Shopping.ReduceProductRequest;
+import com.iluwatar.rpc.proto.Shopping.ReduceProductResponse;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+@ExtendWith(MockitoExtension.class)
+class CartServiceImplTest {
+  @Mock
+  private ShoppingServiceBlockingStub productServiceBlockingStub;
+  @InjectMocks
+  private CartServiceImpl cartService;
+
+  private static List<Shopping.ProductResponse> products;
+
+  @BeforeEach
+  public void setUp() {
+    products = new ArrayList<>();
+    var product = productInCartProvider();
+    products.add(Shopping.ProductResponse.newBuilder()
+        .setId(product.getId())
+        .setPrice(product.getPrice())
+        .setType(product.getType())
+        .setName(product.getName())
+        .build());
+  }
+
+  @Test
+  void testReduceCartQuantityFromProduct_NullProduct() {
+    IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
+      cartService.reduceCartQuantityFromProduct(null);
+    });
+    assertEquals("Product state is null", exception.getMessage());
+  }
+
+  @Test
+  void testReduceCartQuantityFromProduct_InvalidProductProperties() {
+    ProductInCart invalidProduct = productInCartProvider();
+    invalidProduct.setId(-1L);
+    IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
+      cartService.reduceCartQuantityFromProduct(invalidProduct);
+    });
+    assertEquals("Invalid Product id", exception.getMessage());
+  }
+
+  @Test
+  void testReduceCartQuantityFromProduct_EmptyCart() {
+    ProductInCart product = productInCartProvider();
+
+    IllegalStateException exception = assertThrows(IllegalStateException.class, () -> {
+      cartService.reduceCartQuantityFromProduct(product);
+    });
+    assertEquals("Products In cart array empty, populate cart first", exception.getMessage());
+  }
+
+  @Test
+  void testReduceCartQuantityFromProduct_Success() {
+    when(productServiceBlockingStub.getAllProducts(null)).thenReturn(products.iterator());
+
+    ProductInCart product = productInCartProvider();
+    product.setId(3L);
+
+    ReduceProductResponse response =
+        ReduceProductResponse.newBuilder().setStatus(true).setMessage("Success").build();
+    when(productServiceBlockingStub.reduceProductQuantity(
+        any(ReduceProductRequest.class))).thenReturn(response);
+
+    cartService.getAllProducts();
+    cartService.reduceCartQuantityFromProduct(product);
+    verify(productServiceBlockingStub, times(1)).reduceProductQuantity(
+        any(ReduceProductRequest.class));
+  }
+
+  @Test
+  void testGetAllProducts_Success() {
+    when(productServiceBlockingStub.getAllProducts(null)).thenReturn(products.iterator());
+
+    List<Shopping.ProductResponse> products = new ArrayList<>();
+    var productInCart = productInCartProvider();
+    products.add(Shopping.ProductResponse.newBuilder()
+        .setId(productInCart.getId())
+        .setName(productInCart.getName())
+        .setType(productInCart.getType())
+        .setPrice(productInCart.getPrice() + 10)
+        .build());
+
+    when(productServiceBlockingStub.getAllProducts(null)).thenReturn(products.iterator());
+
+    cartService.getAllProducts();
+    assertDoesNotThrow(() -> cartService.getRandomProductFromCart());
+  }
+
+  @Test
+  void testGetAllProducts_Exception() {
+    when(productServiceBlockingStub.getAllProducts(null)).thenThrow(
+        new RuntimeException("Service error"));
+
+    IllegalStateException exception = assertThrows(IllegalStateException.class, () -> {
+      cartService.getAllProducts();
+    });
+    assertEquals("Failed to fetch products from ProductService", exception.getMessage());
+  }
+
+  @Test
+  void testGetRandomProductFromCart_EmptyCart() {
+    IllegalStateException exception = assertThrows(IllegalStateException.class, () -> {
+      cartService.getRandomProductFromCart();
+    });
+    assertEquals("Products In cart array empty", exception.getMessage());
+  }
+
+  @Test
+  void testGetRandomProductFromCart_Success() {
+    when(productServiceBlockingStub.getAllProducts(null)).thenReturn(products.iterator());
+
+    cartService.getAllProducts();
+    ProductInCart randomProduct = cartService.getRandomProductFromCart();
+    assertNotNull(randomProduct);
+  }
+
+  private ProductInCart productInCartProvider() {
+    return ProductInCart.builder()
+        .id(1L)
+        .name("Test")
+        .type("Test type")
+        .price(0.0)
+        .quantityToReduce(10)
+        .build();
+  }
+}
\ No newline at end of file
diff --git a/remote-procedure-call/cart-service/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/remote-procedure-call/cart-service/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 000000000000..ca6ee9cea8ec
--- /dev/null
+++ b/remote-procedure-call/cart-service/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1 @@
+mock-maker-inline
\ No newline at end of file
diff --git a/remote-procedure-call/etc/remote-procedure-call.urm.puml b/remote-procedure-call/etc/remote-procedure-call.urm.puml
new file mode 100644
index 000000000000..02af47ddf261
--- /dev/null
+++ b/remote-procedure-call/etc/remote-procedure-call.urm.puml
@@ -0,0 +1,2 @@
+@startuml
+@enduml
\ No newline at end of file
diff --git a/remote-procedure-call/pom.xml b/remote-procedure-call/pom.xml
new file mode 100644
index 000000000000..a9c8761191a9
--- /dev/null
+++ b/remote-procedure-call/pom.xml
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+
+    The MIT License
+    Copyright © 2014-2022 Ilkka Seppälä
+
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>java-design-patterns</artifactId>
+        <groupId>com.iluwatar</groupId>
+        <version>1.26.0-SNAPSHOT</version>
+    </parent>
+
+    <properties>
+        <grpc-version>1.68.0</grpc-version>
+        <protobuf-version>4.28.2</protobuf-version>
+        <jakarta-annotation-version>3.0.0</jakarta-annotation-version>
+        <mockito-version>5.14.2</mockito-version>
+        <maven-compiler-plugin-version>3.11.0</maven-compiler-plugin-version>
+        <protobuf-maven-plugin-version>0.6.1</protobuf-maven-plugin-version>
+    </properties>
+
+	<modelVersion>4.0.0</modelVersion>
+    <artifactId>remote-procedure-call</artifactId>
+    <version>1.26.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <modules>
+        <module>cart-service</module>
+        <module>product-service</module>
+    </modules>
+
+	<dependencies>
+		<dependency>
+			<groupId>io.grpc</groupId>
+			<artifactId>grpc-netty-shaded</artifactId>
+			<version>${grpc-version}</version>
+			<scope>runtime</scope>
+		</dependency>
+		<dependency>
+			<groupId>io.grpc</groupId>
+			<artifactId>grpc-protobuf</artifactId>
+			<version>${grpc-version}</version>
+		</dependency>
+		<dependency>
+			<groupId>io.grpc</groupId>
+			<artifactId>grpc-stub</artifactId>
+			<version>${grpc-version}</version>
+		</dependency>
+        <dependency>
+            <groupId>com.google.protobuf</groupId>
+            <artifactId>protobuf-java</artifactId>
+            <version>${protobuf-version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-engine</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-junit-jupiter</artifactId>
+            <version>${mockito-version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+	<build>
+        <extensions>
+            <extension>
+                <groupId>kr.motd.maven</groupId>
+                <artifactId>os-maven-plugin</artifactId>
+                <version>1.7.1</version>
+            </extension>
+        </extensions>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>${maven-compiler-plugin-version}</version>
+            </plugin>
+            <plugin>
+                <groupId>org.xolstice.maven.plugins</groupId>
+                <artifactId>protobuf-maven-plugin</artifactId>
+                <version>${protobuf-maven-plugin-version}</version>
+                <configuration>
+                    <protoSourceRoot>${project.basedir}/../proto</protoSourceRoot>
+                    <protocArtifact>com.google.protobuf:protoc:4.28.2:exe:${os.detected.classifier}</protocArtifact>
+                    <pluginId>grpc-java</pluginId>
+                    <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.68.0:exe:${os.detected.classifier}</pluginArtifact>
+                </configuration>
+                <executions>
+                    <execution>
+                        <configuration>
+                            <pluginParameter>@generated=omit</pluginParameter>
+                        </configuration>
+                        <goals>
+                            <goal>compile</goal>
+                            <goal>compile-custom</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file
diff --git a/remote-procedure-call/product-service/etc/product-service.urm.png b/remote-procedure-call/product-service/etc/product-service.urm.png
new file mode 100644
index 000000000000..948b3d5273be
Binary files /dev/null and b/remote-procedure-call/product-service/etc/product-service.urm.png differ
diff --git a/remote-procedure-call/product-service/etc/product-service.urm.puml b/remote-procedure-call/product-service/etc/product-service.urm.puml
new file mode 100644
index 000000000000..799192b93d2e
--- /dev/null
+++ b/remote-procedure-call/product-service/etc/product-service.urm.puml
@@ -0,0 +1,80 @@
+@startuml
+skinparam dpi 300
+scale 0.3
+
+package com.iluwatar.rpc.product {
+  class Main {
+    - SERVER_PORT : int {static}
+    - log : Logger {static}
+    + main(args : String[]) {static}
+  }
+}
+
+package com.iluwatar.rpc.product.model {
+  class Product {
+    - id : Long
+    - name : String
+    - price : double
+    - quantity : int
+    - type : String
+  }
+}
+
+package com.iluwatar.rpc.product.mocks {
+  class ProductMocks {
+    + ProductMocks()
+    + getMockProducts() : List<Product> {static}
+  }
+}
+
+package com.iluwatar.rpc.product.service {
+  interface ProductService {
+    + getAllProducts() : List<Product> {abstract}
+    + getProduct(Long) : Optional<Product> {abstract}
+  }
+  class ProductServiceGrpcImpl {
+    - log : Logger {static}
+    - productService : ProductService
+    + ProductServiceGrpcImpl(productService : ProductService)
+    + getAllProducts(request : Empty, responseStreamObserver : StreamObserver<ProductResponse>)
+    + reduceProductQuantity(request : ReduceProductRequest, responseStreamObserver : StreamObserver<ReduceProductResponse>)
+  }
+  class ProductServiceImpl {
+    - products : List<Product>
+    + ProductServiceImpl(products : List<Product>)
+    + getAllProducts() : List<Product>
+    + getProduct(id : Long) : Optional<Product>
+  }
+}
+
+package com.iluwatar.rpc.proto {
+  class Empty {}
+
+  class ProductResponse {
+    - id : long
+    - name : String
+    - price : double
+    - type : String
+  }
+
+  class ReduceProductRequest {
+    - productId : long
+    - quantity : int
+  }
+
+  class ReduceProductResponse {
+    - message : String
+    - status : boolean
+  }
+
+  class ShoppingServiceImplBase {
+    - getAllProducts(request: Empty, responseStreamObserver: StreamObserver<ProductResponse>)
+    - reduceProductQuantity(request: ReduceProductRequest, responseStreamObserver : StreamObserver<ReduceProductResponse>)
+  }
+}
+
+ProductServiceImpl -->  "-products" Product
+ProductServiceGrpcImpl -->  "-productService" ProductService
+ProductServiceGrpcImpl --|> ShoppingServiceImplBase
+ProductServiceImpl ..|> ProductService
+@enduml
\ No newline at end of file
diff --git a/remote-procedure-call/product-service/pom.xml b/remote-procedure-call/product-service/pom.xml
new file mode 100644
index 000000000000..bf54b0e75413
--- /dev/null
+++ b/remote-procedure-call/product-service/pom.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+
+    The MIT License
+    Copyright © 2014-2022 Ilkka Seppälä
+
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <parent>
+        <artifactId>remote-procedure-call</artifactId>
+        <groupId>com.iluwatar</groupId>
+        <version>1.26.0-SNAPSHOT</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+	<artifactId>product-service</artifactId>
+    <packaging>jar</packaging>
+
+</project>
\ No newline at end of file
diff --git a/remote-procedure-call/product-service/src/main/java/com/iluwatar/rpc/product/Main.java b/remote-procedure-call/product-service/src/main/java/com/iluwatar/rpc/product/Main.java
new file mode 100644
index 000000000000..bd1c958cbb20
--- /dev/null
+++ b/remote-procedure-call/product-service/src/main/java/com/iluwatar/rpc/product/Main.java
@@ -0,0 +1,72 @@
+/*
+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.rpc.product;
+
+import com.iluwatar.rpc.product.mocks.ProductMocks;
+import com.iluwatar.rpc.product.model.Product;
+import com.iluwatar.rpc.product.service.ProductServiceGrpcImpl;
+import com.iluwatar.rpc.product.service.ProductServiceImpl;
+import io.grpc.Server;
+import io.grpc.ServerBuilder;
+import java.io.IOException;
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Main class to start the product service.
+ *
+ * @author CoderSleek
+ * @version 1.0
+ */
+public class Main {
+  private static final int SERVER_PORT = 8080;
+  private static final Logger log = LoggerFactory.getLogger(Main.class);
+  /**
+   * Main method to start the product service.
+   * instantiates product mock data and starts the gRPC server.
+   * constructor injects ProductService into ProductServiceGrpcImpl
+   * listens on default server port 8080
+   *
+   * @param args the input arguments
+   * @throws IOException          the io exception
+   * @throws InterruptedException the interrupted exception
+   */
+  public static void main(String[] args) throws IOException, InterruptedException {
+    List<Product> products = ProductMocks.getMockProducts();
+    var productServiceImpl = new ProductServiceImpl(products);
+    var productServiceGrpcImpl = new ProductServiceGrpcImpl(productServiceImpl);
+
+    Server server = ServerBuilder
+        .forPort(SERVER_PORT)
+        .addService(productServiceGrpcImpl)
+        .build();
+
+    log.info("Starting server on port: " + SERVER_PORT);
+    log.info("Waiting for request---------");
+    server.start();
+    server.awaitTermination();
+  }
+}
\ No newline at end of file
diff --git a/remote-procedure-call/product-service/src/main/java/com/iluwatar/rpc/product/mocks/ProductMocks.java b/remote-procedure-call/product-service/src/main/java/com/iluwatar/rpc/product/mocks/ProductMocks.java
new file mode 100644
index 000000000000..68b5cd036fa2
--- /dev/null
+++ b/remote-procedure-call/product-service/src/main/java/com/iluwatar/rpc/product/mocks/ProductMocks.java
@@ -0,0 +1,54 @@
+/*
+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.rpc.product.mocks;
+
+import com.iluwatar.rpc.product.model.Product;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Mocks data for product POJO, used for testing and in memory store.
+ * Thread safety is not guaranteed.
+ * @link com.iluwatar.rpc.product.model.Product
+ * @author CoderSleek
+ * @version 1.0
+ */
+public class ProductMocks {
+  /**
+   * Returns new Mock product ArrayList on each call, to reset state.
+   *
+   * @return the mock products
+   */
+  public static List<Product> getMockProducts() {
+    return new ArrayList<>() {{
+        add(new Product(1L, "Product 1", "Type 1", 50.0, 10));
+        add(new Product(2L, "Product 2", "Type 2", 40.0, 20));
+        add(new Product(3L, "Product 3",  "Type 3", 30.0, 30));
+        add(new Product(4L, "Product 4", "Type 4", 20.0, 40));
+        add(new Product(5L, "Product 5", "Type 5", 10.0, 50));
+      }
+    };
+  }
+}
\ No newline at end of file
diff --git a/remote-procedure-call/product-service/src/main/java/com/iluwatar/rpc/product/model/Product.java b/remote-procedure-call/product-service/src/main/java/com/iluwatar/rpc/product/model/Product.java
new file mode 100644
index 000000000000..f0975877b35b
--- /dev/null
+++ b/remote-procedure-call/product-service/src/main/java/com/iluwatar/rpc/product/model/Product.java
@@ -0,0 +1,44 @@
+/*
+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.rpc.product.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+/**
+ * Product POJO class.
+ *
+ * @author CoderSleek
+ * @version 1.0
+ */
+@Data
+@AllArgsConstructor
+public class Product {
+  private Long id;
+  private String name;
+  private String type;
+  private double price;
+  private int quantity;
+}
\ No newline at end of file
diff --git a/remote-procedure-call/product-service/src/main/java/com/iluwatar/rpc/product/service/ProductService.java b/remote-procedure-call/product-service/src/main/java/com/iluwatar/rpc/product/service/ProductService.java
new file mode 100644
index 000000000000..01ef6f2dbb5b
--- /dev/null
+++ b/remote-procedure-call/product-service/src/main/java/com/iluwatar/rpc/product/service/ProductService.java
@@ -0,0 +1,55 @@
+/*
+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.rpc.product.service;
+
+import com.iluwatar.rpc.product.model.Product;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * API Contract for Product service, which can be exposed.
+ * Includes getter methods for product by id and all products.
+ * Thread safety is not guaranteed.
+ *
+ * @link com.iluwatar.rpc.product.model.Product
+ * @author CoderSleek
+ * @version 1.0
+ */
+public interface ProductService {
+  /**
+   * Get optional of product by id.
+   *
+   * @param id id of product
+   * @return product
+   */
+  Optional<Product> getProduct(Long id);
+
+  /**
+   * Get all products.
+   * @return ArrayList of all products
+   * @throws IllegalStateException thrown when products array is null or empty, denotes improper initialization
+   */
+  List<Product> getAllProducts() throws IllegalStateException;
+}
diff --git a/remote-procedure-call/product-service/src/main/java/com/iluwatar/rpc/product/service/ProductServiceGrpcImpl.java b/remote-procedure-call/product-service/src/main/java/com/iluwatar/rpc/product/service/ProductServiceGrpcImpl.java
new file mode 100644
index 000000000000..2dd5d58e3f2f
--- /dev/null
+++ b/remote-procedure-call/product-service/src/main/java/com/iluwatar/rpc/product/service/ProductServiceGrpcImpl.java
@@ -0,0 +1,147 @@
+/*
+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.rpc.product.service;
+
+import com.iluwatar.rpc.product.model.Product;
+import com.iluwatar.rpc.proto.Shopping.Empty;
+import com.iluwatar.rpc.proto.Shopping.ProductResponse;
+import com.iluwatar.rpc.proto.Shopping.ReduceProductRequest;
+import com.iluwatar.rpc.proto.Shopping.ReduceProductResponse;
+import com.iluwatar.rpc.proto.ShoppingServiceGrpc.ShoppingServiceImplBase;
+import io.grpc.Status;
+import io.grpc.stub.StreamObserver;
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implementation of product-service Contract exposed by gRPC proto.
+ * Thread safety is not guaranteed.
+ *
+ * @link com.iluwatar.rpc.product.service.ProductService
+ * @link com.iluwatar.rpc.product.model.Product
+ * @author CoderSleek
+ * @version 1.0
+ */
+public class ProductServiceGrpcImpl extends ShoppingServiceImplBase {
+  private final ProductService productService;
+  private static final Logger log = LoggerFactory.getLogger(ProductServiceGrpcImpl.class);
+
+  /**
+   * Constructor for initializing Implementation of ProductService Contract internally.
+   * ProductService Implementation stores Product data in internal state for simplicity.
+   *
+   * @param productService ProductService
+   */
+  public ProductServiceGrpcImpl(ProductService productService) {
+    this.productService = productService;
+  }
+
+  /**
+   * Reduces the quantity of a specified product via product id by the requested quantity.
+   * To simulate a customer buying an item, once bought the quantity of the product is reduced from stock.
+   * @param request contains product id and quantity to reduce
+   * @param responseStreamObserver for iterating over response
+   */
+  @Override
+  public void reduceProductQuantity(ReduceProductRequest request,
+                                    StreamObserver<ReduceProductResponse> responseStreamObserver) {
+    log.info("Received request to reduce product quantity");
+    boolean status;
+    String message;
+    var product = this.productService.getProduct(request.getProductId());
+
+    if (product.isEmpty()) {
+      status = false;
+      message = "Product with ID does not exist";
+    } else {
+      int productQuantity = product.get().getQuantity();
+      int requestedQuantity = request.getQuantity();
+
+      if (requestedQuantity <= 0) {
+        status = false;
+        message = "Invalid Quantity";
+      } else if (requestedQuantity > productQuantity) {
+        status = false;
+        message = "Product has less quantity in stock than requested";
+      } else {
+        log.info("Before reducing quantity: {}", productQuantity);
+        product.get().setQuantity(productQuantity - requestedQuantity);
+        log.info("After reducing quantity: {}", product.get().getQuantity());
+        status = true;
+        message = "Success";
+      }
+    }
+
+    var response = ReduceProductResponse
+        .newBuilder()
+        .setMessage(message)
+        .setStatus(status)
+        .build();
+
+    responseStreamObserver.onNext(response);
+    responseStreamObserver.onCompleted();
+    log.info("Request to Reduce Product Quantity Execution Completed");
+  }
+
+  /**
+   * Fetches all products from ProductService and streams them to the client.
+   * Throws NOT_FOUND status exception if products are not found.
+   * @param request empty placeholder request
+   * @param responseStreamObserver for iterating over responses
+   */
+  @Override
+  public void getAllProducts(Empty request,
+                             StreamObserver<ProductResponse> responseStreamObserver) {
+    log.info("Received request to fetch all products");
+    List<Product> products;
+
+    try {
+      products = this.productService.getAllProducts();
+    } catch (IllegalStateException e) {
+      log.error("Failed to fetch products from ProductService", e);
+      responseStreamObserver.onError(
+          Status.NOT_FOUND
+              .withDescription(e.getMessage())
+              .asException());
+      responseStreamObserver.onCompleted();
+      return;
+    }
+
+    for (var product : products) {
+      responseStreamObserver.onNext(
+          ProductResponse.newBuilder()
+              .setId(product.getId())
+              .setName(product.getName())
+              .setPrice(product.getPrice())
+              .setType(product.getType())
+              .build()
+      );
+    }
+
+    responseStreamObserver.onCompleted();
+    log.info("Request to fetch all products Execution Completed");
+  }
+}
diff --git a/remote-procedure-call/product-service/src/main/java/com/iluwatar/rpc/product/service/ProductServiceImpl.java b/remote-procedure-call/product-service/src/main/java/com/iluwatar/rpc/product/service/ProductServiceImpl.java
new file mode 100644
index 000000000000..2ce1749b1927
--- /dev/null
+++ b/remote-procedure-call/product-service/src/main/java/com/iluwatar/rpc/product/service/ProductServiceImpl.java
@@ -0,0 +1,78 @@
+/*
+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.rpc.product.service;
+
+import com.iluwatar.rpc.product.model.Product;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Implementation of ProductService Contract, maintains Product state for simplicity.
+ * Provides getter methods for product by id and all products.
+ * Thread safety is not guaranteed.
+ *
+ * @link com.iluwatar.rpc.product.service.ProductService
+ * @link com.iluwatar.rpc.product.model.Product
+ * @author CoderSleek
+ * @version 1.0
+ */
+public class ProductServiceImpl implements ProductService {
+  private final List<Product> products;
+
+  /**
+   * Constructor to set internal state of Product array.
+   *
+   * @param products ArrayList of products
+   */
+  public ProductServiceImpl(List<Product> products) {
+    this.products = products;
+  }
+
+  /**
+   * Get optional of product by id.
+   * @param id id of product
+   * @return Product first item in the list with matching id, if not found returns empty optional
+   */
+  @Override
+  public Optional<Product> getProduct(Long id) {
+    return products
+        .stream()
+        .filter(product -> product.getId().equals(id))
+        .findFirst();
+  }
+
+  @Override
+  public List<Product> getAllProducts() throws IllegalStateException {
+    if (products == null) {
+      throw new IllegalStateException("Products array is not initialized properly");
+    }
+
+    if (products.isEmpty()) {
+      throw new IllegalStateException("Products array does not have any data");
+    }
+
+    return products;
+  }
+}
diff --git a/remote-procedure-call/product-service/src/main/resources/logback.xml b/remote-procedure-call/product-service/src/main/resources/logback.xml
new file mode 100644
index 000000000000..ed930c512e7e
--- /dev/null
+++ b/remote-procedure-call/product-service/src/main/resources/logback.xml
@@ -0,0 +1,12 @@
+<!-- to ensure only info and error logging -->
+<configuration>
+    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
+        </encoder>
+    </appender>
+
+    <root level="INFO">
+        <appender-ref ref="CONSOLE" />
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/remote-procedure-call/product-service/src/test/java/com/iluwatar/rpc/product/service/ProductServiceGrpcImplTest.java b/remote-procedure-call/product-service/src/test/java/com/iluwatar/rpc/product/service/ProductServiceGrpcImplTest.java
new file mode 100644
index 000000000000..4a390b9123d1
--- /dev/null
+++ b/remote-procedure-call/product-service/src/test/java/com/iluwatar/rpc/product/service/ProductServiceGrpcImplTest.java
@@ -0,0 +1,192 @@
+/*
+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.rpc.product.service;
+
+import com.iluwatar.rpc.product.mocks.ProductMocks;
+import com.iluwatar.rpc.product.model.Product;
+import com.iluwatar.rpc.proto.Shopping.Empty;
+import com.iluwatar.rpc.proto.Shopping.ProductResponse;
+import com.iluwatar.rpc.proto.Shopping.ReduceProductRequest;
+import com.iluwatar.rpc.proto.Shopping.ReduceProductResponse;
+import io.grpc.StatusException;
+import io.grpc.stub.StreamObserver;
+import java.util.List;
+import java.util.Optional;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.*;
+import static org.mockito.ArgumentMatchers.any;
+
+@ExtendWith(MockitoExtension.class)
+class ProductServiceGrpcImplTest {
+  @Mock
+  private ProductService productService;
+
+  @InjectMocks
+  private ProductServiceGrpcImpl productServiceGrpcImpl;
+
+  private List<Product> productsMockData;
+
+  @BeforeEach
+  public void setUp() {
+    productsMockData = ProductMocks.getMockProducts();
+  }
+
+  @Test
+  void testReduceProductQuantity_ProductNotFound() {
+    var request = ReduceProductRequest.newBuilder()
+        .setProductId(6L)
+        .setQuantity(5)
+        .build();
+    StreamObserver<ReduceProductResponse> responseObserver = mock(StreamObserver.class);
+
+    when(productService.getProduct(request.getProductId())).thenReturn(Optional.empty());
+
+    productServiceGrpcImpl.reduceProductQuantity(request, responseObserver);
+
+    ArgumentCaptor<ReduceProductResponse> responseCaptor =
+        ArgumentCaptor.forClass(ReduceProductResponse.class);
+    verify(responseObserver).onNext(responseCaptor.capture());
+    verify(responseObserver).onCompleted();
+
+    ReduceProductResponse response = responseCaptor.getValue();
+    assertFalse(response.getStatus());
+    assertEquals("Product with ID does not exist", response.getMessage());
+  }
+
+  @Test
+  void testReduceProductQuantity_InvalidQuantity() {
+    Product product = productsMockData.get(0);
+    ReduceProductRequest request = ReduceProductRequest.newBuilder()
+        .setProductId(product.getId())
+        .setQuantity(-5)
+        .build();
+    StreamObserver<ReduceProductResponse> responseObserver = mock(StreamObserver.class);
+
+    when(productService.getProduct(product.getId())).thenReturn(Optional.of(product));
+
+    productServiceGrpcImpl.reduceProductQuantity(request, responseObserver);
+
+    ArgumentCaptor<ReduceProductResponse> responseCaptor =
+        ArgumentCaptor.forClass(ReduceProductResponse.class);
+    verify(responseObserver).onNext(responseCaptor.capture());
+    verify(responseObserver).onCompleted();
+
+    ReduceProductResponse response = responseCaptor.getValue();
+    assertFalse(response.getStatus());
+    assertEquals("Invalid Quantity", response.getMessage());
+  }
+
+  @Test
+  void testReduceProductQuantity_InsufficientQuantity() {
+    Product product = productsMockData.get(0);
+
+    ReduceProductRequest request = ReduceProductRequest.newBuilder()
+        .setProductId(product.getId())
+        .setQuantity(1000)
+        .build();
+    StreamObserver<ReduceProductResponse> responseObserver = mock(StreamObserver.class);
+
+    when(productService.getProduct(product.getId())).thenReturn(Optional.of(product));
+
+    productServiceGrpcImpl.reduceProductQuantity(request, responseObserver);
+
+    ArgumentCaptor<ReduceProductResponse> responseCaptor =
+        ArgumentCaptor.forClass(ReduceProductResponse.class);
+    verify(responseObserver).onNext(responseCaptor.capture());
+    verify(responseObserver).onCompleted();
+
+    ReduceProductResponse response = responseCaptor.getValue();
+    assertFalse(response.getStatus());
+    assertEquals("Product has less quantity in stock than requested", response.getMessage());
+  }
+
+  @Test
+  void testReduceProductQuantity_Success() {
+    Product product = productsMockData.get(0);
+    ReduceProductRequest request = ReduceProductRequest.newBuilder()
+        .setProductId(product.getId())
+        .setQuantity(5)
+        .build();
+    StreamObserver<ReduceProductResponse> responseObserver = mock(StreamObserver.class);
+
+    when(productService.getProduct(product.getId())).thenReturn(Optional.of(product));
+
+    productServiceGrpcImpl.reduceProductQuantity(request, responseObserver);
+
+    ArgumentCaptor<ReduceProductResponse> responseCaptor =
+        ArgumentCaptor.forClass(ReduceProductResponse.class);
+    verify(responseObserver).onNext(responseCaptor.capture());
+    verify(responseObserver).onCompleted();
+
+    ReduceProductResponse response = responseCaptor.getValue();
+    assertTrue(response.getStatus());
+    assertEquals("Success", response.getMessage());
+    assertEquals(5, product.getQuantity());
+  }
+
+  @Test
+  void testGetAllProducts_Success() {
+    List<Product> productsLocal = ProductMocks.getMockProducts();
+    var product = productsLocal.get(0);
+
+    StreamObserver<ProductResponse> responseObserver = mock(StreamObserver.class);
+
+    when(productService.getAllProducts()).thenReturn(productsMockData);
+    productServiceGrpcImpl.getAllProducts(null, responseObserver);
+
+    ArgumentCaptor<ProductResponse> responseCaptor = ArgumentCaptor.forClass(ProductResponse.class);
+    verify(responseObserver, times(5)).onNext(responseCaptor.capture());
+    verify(responseObserver).onCompleted();
+
+    assertEquals(productsLocal.size(), responseCaptor.getAllValues().size());
+    assertEquals(Long.compare(product.getId(), responseCaptor.getAllValues().get(0).getId()), 0);
+    assertEquals(product.getName(), responseCaptor.getAllValues().get(0).getName());
+    assertEquals(product.getType(), responseCaptor.getAllValues().get(0).getType());
+    assertEquals(
+        Double.compare(product.getPrice(), responseCaptor.getAllValues().get(0).getPrice()), 0);
+  }
+
+  @Test
+  void testGetAllProducts_Failure() {
+    StreamObserver<ProductResponse> responseObserver = mock(StreamObserver.class);
+
+    when(productService.getAllProducts()).thenThrow(new IllegalStateException("Database error"));
+
+    productServiceGrpcImpl.getAllProducts(Empty.newBuilder().build(), responseObserver);
+
+    verify(responseObserver).onError(any(StatusException.class));
+    verify(responseObserver).onCompleted();
+  }
+}
diff --git a/remote-procedure-call/product-service/src/test/java/com/iluwatar/rpc/product/service/ProductServiceImplTest.java b/remote-procedure-call/product-service/src/test/java/com/iluwatar/rpc/product/service/ProductServiceImplTest.java
new file mode 100644
index 000000000000..9c82c86605d3
--- /dev/null
+++ b/remote-procedure-call/product-service/src/test/java/com/iluwatar/rpc/product/service/ProductServiceImplTest.java
@@ -0,0 +1,92 @@
+/*
+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.rpc.product.service;
+
+import com.iluwatar.rpc.product.mocks.ProductMocks;
+import com.iluwatar.rpc.product.model.Product;
+import java.util.List;
+import java.util.Optional;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@ExtendWith(MockitoExtension.class)
+class ProductServiceImplTest {
+  private static List<Product> products;
+  private ProductServiceImpl productService;
+
+  @BeforeEach
+  void setUp() {
+    products = ProductMocks.getMockProducts();
+    productService = new ProductServiceImpl(products);
+  }
+
+  @Test
+  void testGetProduct() {
+    Optional<Product> product = productService.getProduct(1L);
+    assertTrue(product.isPresent());
+    assertEquals(1L, product.get().getId());
+    assertEquals("Product 1", product.get().getName());
+    assertEquals(50.0, product.get().getPrice());
+  }
+
+  @Test
+  void testGetProductNotFound() {
+    Optional<Product> product = productService.getProduct(6L);
+    assertFalse(product.isPresent());
+  }
+
+  @Test
+  void testGetAllProducts() {
+    List<Product> allProducts = productService.getAllProducts();
+    assertNotNull(allProducts);
+    assertEquals(5, allProducts.size());
+  }
+
+  @Test
+  void testGetAllProductsEmpty() {
+    products.clear();
+    IllegalStateException exception = assertThrows(IllegalStateException.class, () -> {
+      productService.getAllProducts();
+    });
+    assertEquals("Products array does not have any data", exception.getMessage());
+  }
+
+  @Test
+  void testGetAllProductNull() {
+    productService = new ProductServiceImpl(null);
+    IllegalStateException exception = assertThrows(IllegalStateException.class, () -> {
+      productService.getAllProducts();
+    });
+    assertEquals("Products array is not initialized properly", exception.getMessage());
+  }
+}
\ No newline at end of file
diff --git a/remote-procedure-call/product-service/src/test/java/com/iluwatar/rpc/product/service/ProductServiceIntegrationTest.java b/remote-procedure-call/product-service/src/test/java/com/iluwatar/rpc/product/service/ProductServiceIntegrationTest.java
new file mode 100644
index 000000000000..a9a87463b43b
--- /dev/null
+++ b/remote-procedure-call/product-service/src/test/java/com/iluwatar/rpc/product/service/ProductServiceIntegrationTest.java
@@ -0,0 +1,102 @@
+/*
+ * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+ *
+ * The MIT License
+ * Copyright © 2014-2022 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.rpc.product.service;
+
+import com.iluwatar.rpc.product.mocks.ProductMocks;
+import com.iluwatar.rpc.product.model.Product;
+import com.iluwatar.rpc.proto.ShoppingServiceGrpc;
+import com.iluwatar.rpc.proto.ShoppingServiceGrpc.ShoppingServiceBlockingStub;
+import com.iluwatar.rpc.proto.Shopping.ProductResponse;
+import com.iluwatar.rpc.proto.Shopping.ReduceProductRequest;
+import com.iluwatar.rpc.proto.Shopping.ReduceProductResponse;
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
+import io.grpc.Server;
+import io.grpc.ServerBuilder;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@ExtendWith(MockitoExtension.class)
+class ProductServiceIntegrationTest {
+  private static Server server;
+  private static ManagedChannel channel;
+  private static ShoppingServiceBlockingStub blockingStub;
+
+  @BeforeAll
+  public static void setup() throws IOException {
+    List<Product> products = ProductMocks.getMockProducts();
+    var productServiceMain = new ProductServiceImpl(products);
+
+    server = ServerBuilder
+        .forPort(8080)
+        .addService(new ProductServiceGrpcImpl(productServiceMain))
+        .build()
+        .start();
+
+    channel = ManagedChannelBuilder.forAddress("localhost", 8080)
+        .usePlaintext()
+        .build();
+
+    blockingStub = ShoppingServiceGrpc.newBlockingStub(channel);
+  }
+
+  @AfterAll
+  public static void teardown() {
+    channel.shutdownNow();
+    server.shutdownNow();
+  }
+
+  @Test
+  void testReduceProductQuantity() {
+    ReduceProductRequest request = ReduceProductRequest.newBuilder()
+        .setProductId(1L)
+        .setQuantity(5)
+        .build();
+
+    ReduceProductResponse response = blockingStub.reduceProductQuantity(request);
+
+    assertTrue(response.getStatus());
+    assertEquals("Success", response.getMessage());
+  }
+
+  @Test
+  void testGetAllProducts() {
+    var responseIterator = blockingStub.getAllProducts(null);
+
+    ArrayList<ProductResponse> responses = new ArrayList<>();
+    responseIterator.forEachRemaining(responses::add);
+
+    assertEquals(ProductMocks.getMockProducts().size(), responses.size());
+  }
+}
diff --git a/remote-procedure-call/product-service/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/remote-procedure-call/product-service/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 000000000000..ca6ee9cea8ec
--- /dev/null
+++ b/remote-procedure-call/product-service/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1 @@
+mock-maker-inline
\ No newline at end of file
diff --git a/remote-procedure-call/proto/shopping.proto b/remote-procedure-call/proto/shopping.proto
new file mode 100644
index 000000000000..47515f054fda
--- /dev/null
+++ b/remote-procedure-call/proto/shopping.proto
@@ -0,0 +1,52 @@
+//
+// This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
+//
+// The MIT License
+// Copyright © 2014-2022 Ilkka Seppälä
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+syntax = "proto3";
+
+package com.iluwatar.rpc.proto;
+
+service ShoppingService {
+    rpc ReduceProductQuantity (ReduceProductRequest) returns (ReduceProductResponse);
+    rpc GetAllProducts (Empty) returns (stream ProductResponse);
+}
+
+message ReduceProductRequest {
+    uint64 product_id = 1;
+    uint32 quantity = 2;
+}
+
+message ReduceProductResponse {
+    bool status = 1;
+    string message = 2;
+}
+
+message ProductResponse {
+    uint64 id = 1;
+    string name = 2;
+    string type = 3;
+    double price = 4;
+}
+
+message Empty {}