diff --git a/pom.xml b/pom.xml
index 8337c97966da..4697c5667f1b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -215,6 +215,7 @@
service-locator
service-stub
service-to-worker
+ server-side-service-discovery
session-facade
sharding
single-table-inheritance
diff --git a/server-side-service-discovery/README.md b/server-side-service-discovery/README.md
new file mode 100644
index 000000000000..2a56e43623b6
--- /dev/null
+++ b/server-side-service-discovery/README.md
@@ -0,0 +1,172 @@
+# Server-Side Service Discovery Pattern
+
+## Intent
+
+The Server-Side Service Discovery pattern is a microservice architecture pattern that provides a centralized mechanism for services to register themselves and for consumers to discover available services dynamically. This pattern enhances system scalability and flexibility by decoupling service consumers from the physical locations of service providers.
+
+## Explanation
+
+Real-world example
+
+> Consider a large e-commerce platform with multiple microservices like Product Service, Order Service, Payment Service, and Inventory Service. Instead of hardcoding the network locations of each service, they register themselves with a central Service Registry (like Netflix Eureka). When the Order Service needs to check product availability, it queries the Service Registry to discover available instances of the Product Service. The registry returns healthy instances, and a load balancer distributes the request among them. This approach allows services to scale up/down dynamically, fail gracefully, and be discovered automatically without manual configuration.
+
+In plain words
+
+> Server-Side Service Discovery provides a centralized registry where services register themselves and consumers can discover and communicate with available services dynamically.
+
+Wikipedia says
+
+> Service discovery is the automatic detection of devices and services offered by these devices on a computer network. In the context of microservices, service discovery refers to the mechanism by which services find and communicate with each other.
+
+## Programmatic Example
+
+This implementation demonstrates the Server-Side Service Discovery pattern using Spring Cloud Netflix Eureka. The example includes:
+
+### 1. Service Registry (Eureka Server)
+
+```java
+@SpringBootApplication
+@EnableEurekaServer
+public class ServiceRegistryApp {
+ public static void main(String[] args) {
+ SpringApplication.run(ServiceRegistryApp.class, args);
+ }
+}
+```
+
+### 2. Service Providers (Product Service & Order Service)
+
+```java
+@SpringBootApplication
+@EnableEurekaClient
+public class ProductServiceApp {
+ public static void main(String[] args) {
+ SpringApplication.run(ProductServiceApp.class, args);
+ }
+}
+```
+
+### 3. Service Consumer with Load Balancing
+
+```java
+@Configuration
+public class ServiceConsumerConfig {
+ @Bean
+ @LoadBalanced
+ public RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+}
+
+@Service
+public class ServiceDiscoveryService {
+ private final RestTemplate restTemplate;
+ private final EurekaClient eurekaClient;
+
+ public String callService(String serviceName, String endpoint) {
+ try {
+ String serviceUrl = "http://" + serviceName + endpoint;
+ return restTemplate.getForObject(serviceUrl, String.class);
+ } catch (Exception e) {
+ return "Error calling service: " + e.getMessage();
+ }
+ }
+}
+```
+
+## Key Components
+
+### Service Registry
+- **Purpose**: Central repository for service instance information
+- **Implementation**: Netflix Eureka Server
+- **Features**: Service registration, health monitoring, instance management
+
+### Service Provider
+- **Purpose**: Services that register themselves with the registry
+- **Examples**: Product Service, Order Service
+- **Features**: Auto-registration, health checks, graceful shutdown
+
+### Service Consumer
+- **Purpose**: Applications that discover and consume services
+- **Features**: Service discovery, load balancing, fault tolerance
+- **Implementation**: Uses Eureka Client and Spring Cloud LoadBalancer
+
+### Load Balancer
+- **Purpose**: Distributes requests among available service instances
+- **Implementation**: Spring Cloud LoadBalancer
+- **Strategies**: Round-robin, random, weighted
+
+## Running the Example
+
+### Prerequisites
+- Java 21+
+- Maven 3.8+
+
+### Step 1: Start the Service Registry
+```bash
+cd service-registry
+mvn spring-boot:run
+```
+The Eureka dashboard will be available at: http://localhost:8761
+
+### Step 2: Start Service Providers
+```bash
+# Terminal 1 - Product Service
+cd product-service
+mvn spring-boot:run -Dspring-boot.run.arguments="--server.port=8081 --spring.application.name=product-service"
+
+# Terminal 2 - Order Service
+cd order-service
+mvn spring-boot:run -Dspring-boot.run.arguments="--server.port=8082 --spring.application.name=order-service"
+```
+
+### Step 3: Start Service Consumer
+```bash
+cd service-consumer
+mvn spring-boot:run -Dspring-boot.run.arguments="--server.port=8080 --spring.application.name=service-consumer"
+```
+
+### Step 4: Test the Pattern
+```bash
+# Discover all services
+curl http://localhost:8080/api/services
+
+# Get products through service discovery
+curl http://localhost:8080/api/products
+
+# Get orders through service discovery
+curl http://localhost:8080/api/orders
+
+# Check service health
+curl http://localhost:8080/api/services/product-service/health
+```
+
+## Pattern Benefits
+
+1. **Dynamic Service Discovery**: Services can be discovered at runtime without hardcoded configurations
+2. **Load Balancing**: Automatic distribution of requests across available instances
+3. **Fault Tolerance**: Failed instances are automatically removed from the registry
+4. **Scalability**: New service instances are automatically discovered and included
+5. **Health Monitoring**: Only healthy services participate in request handling
+6. **Decoupling**: Services are decoupled from physical network locations
+
+## Pattern Drawbacks
+
+1. **Single Point of Failure**: Service registry becomes critical infrastructure
+2. **Network Overhead**: Additional network calls for service discovery
+3. **Complexity**: Adds operational complexity to the system
+4. **Consistency**: Potential delays in service registry updates
+5. **Network Partitions**: Service registry unavailability affects all services
+
+## Related Patterns
+
+- **Client-Side Service Discovery**: Service consumers are responsible for discovering services
+- **Circuit Breaker**: Provides fault tolerance when calling discovered services
+- **API Gateway**: Often combined with service discovery for external access
+- **Health Check**: Essential for maintaining accurate service registry information
+
+## Credits
+
+- [Microservices Patterns by Chris Richardson](https://microservices.io/patterns/service-registry.html)
+- [Spring Cloud Netflix Documentation](https://spring.io/projects/spring-cloud-netflix)
+- [Building Microservices by Sam Newman](https://samnewman.io/books/building_microservices/)
\ No newline at end of file
diff --git a/server-side-service-discovery/order-service/etc/order-service.properties b/server-side-service-discovery/order-service/etc/order-service.properties
new file mode 100644
index 000000000000..ad5ce12509ec
--- /dev/null
+++ b/server-side-service-discovery/order-service/etc/order-service.properties
@@ -0,0 +1,21 @@
+# Order Service Configuration for Server-Side Service Discovery
+
+# Server Configuration
+server.port=8082
+spring.application.name=order-service
+
+# Eureka Client Configuration
+eureka.client.service-url.default-zone=http://localhost:8761/eureka/
+eureka.client.register-with-eureka=true
+eureka.client.fetch-registry=true
+eureka.instance.prefer-ip-address=true
+eureka.instance.lease-renewal-interval-in-seconds=10
+eureka.instance.lease-expiration-duration-in-seconds=30
+
+# Health Check Configuration
+management.endpoints.web.exposure.include=health,info,metrics
+management.endpoint.health.show-details=always
+
+# Logging Configuration
+logging.level.com.netflix.eureka=DEBUG
+logging.level.com.netflix.discovery=DEBUG
diff --git a/server-side-service-discovery/order-service/pom.xml b/server-side-service-discovery/order-service/pom.xml
new file mode 100644
index 000000000000..e2ba8843b6dd
--- /dev/null
+++ b/server-side-service-discovery/order-service/pom.xml
@@ -0,0 +1,95 @@
+
+
+
+
+ server-side-service-discovery
+ com.iluwatar
+ 1.26.0-SNAPSHOT
+
+ 4.0.0
+ order-service
+ jar
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-client
+ 4.1.3
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ 3.4.4
+
+
+
+ repackage
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+
+
+
+ com.iluwatar.orderservice.OrderServiceApp
+
+
+
+
+
+
+
+
+
diff --git a/server-side-service-discovery/order-service/src/main/java/com/iluwatar/orderservice/OrderServiceApp.java b/server-side-service-discovery/order-service/src/main/java/com/iluwatar/orderservice/OrderServiceApp.java
new file mode 100644
index 000000000000..3b8e64b3fafb
--- /dev/null
+++ b/server-side-service-discovery/order-service/src/main/java/com/iluwatar/orderservice/OrderServiceApp.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.orderservice;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * Order Service Application that registers itself with the Service Registry.
+ * This demonstrates another Service Provider component of the Server-Side Service Discovery pattern.
+ */
+@SpringBootApplication
+public class OrderServiceApp {
+
+ /**
+ * Main method to start the Order Service application.
+ *
+ * @param args command line arguments
+ */
+ public static void main(String[] args) {
+ SpringApplication.run(OrderServiceApp.class, args);
+ }
+}
diff --git a/server-side-service-discovery/order-service/src/main/java/com/iluwatar/orderservice/config/OrderServiceConfig.java b/server-side-service-discovery/order-service/src/main/java/com/iluwatar/orderservice/config/OrderServiceConfig.java
new file mode 100644
index 000000000000..10ad61def8cf
--- /dev/null
+++ b/server-side-service-discovery/order-service/src/main/java/com/iluwatar/orderservice/config/OrderServiceConfig.java
@@ -0,0 +1,83 @@
+/*
+ * 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.orderservice.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * Configuration for Order Service.
+ * Configures application properties and beans for the service.
+ */
+@Configuration
+public class OrderServiceConfig {
+
+ /**
+ * Creates a RestTemplate bean for making HTTP requests.
+ *
+ * @return RestTemplate instance
+ */
+ @Bean
+ public RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+
+ /**
+ * Application properties for the Order Service.
+ */
+ @ConfigurationProperties(prefix = "app")
+ public static class OrderServiceProperties {
+ private String name = "order-service";
+ private int port = 8082;
+ private String eurekaUrl = "http://localhost:8761/eureka/";
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ public String getEurekaUrl() {
+ return eurekaUrl;
+ }
+
+ public void setEurekaUrl(String eurekaUrl) {
+ this.eurekaUrl = eurekaUrl;
+ }
+ }
+}
diff --git a/server-side-service-discovery/order-service/src/main/java/com/iluwatar/orderservice/controller/OrderController.java b/server-side-service-discovery/order-service/src/main/java/com/iluwatar/orderservice/controller/OrderController.java
new file mode 100644
index 000000000000..4ea3126d2724
--- /dev/null
+++ b/server-side-service-discovery/order-service/src/main/java/com/iluwatar/orderservice/controller/OrderController.java
@@ -0,0 +1,126 @@
+/*
+ * 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.orderservice.controller;
+
+import com.iluwatar.orderservice.model.Order;
+import com.iluwatar.orderservice.service.OrderService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.Map;
+
+/**
+ * REST Controller for Order operations.
+ * Provides endpoints for managing orders.
+ */
+@RestController
+@RequestMapping("/orders")
+public class OrderController {
+
+ private final OrderService orderService;
+
+ @Autowired
+ public OrderController(OrderService orderService) {
+ this.orderService = orderService;
+ }
+
+ /**
+ * Get all orders.
+ *
+ * @return list of all orders
+ */
+ @GetMapping
+ public ResponseEntity> getAllOrders() {
+ List orders = orderService.getAllOrders();
+ return ResponseEntity.ok(orders);
+ }
+
+ /**
+ * Get order by ID.
+ *
+ * @param id the order ID
+ * @return the order if found, 404 otherwise
+ */
+ @GetMapping("/{id}")
+ public ResponseEntity getOrderById(@PathVariable("id") Long id) {
+ Optional order = orderService.getOrderById(id);
+ return order.map(ResponseEntity::ok)
+ .orElse(ResponseEntity.notFound().build());
+ }
+
+ /**
+ * Create a new order.
+ *
+ * @param order the order to create
+ * @return the created order
+ */
+ @PostMapping
+ public ResponseEntity createOrder(@RequestBody Order order) {
+ Order createdOrder = orderService.createOrder(order);
+ return ResponseEntity.status(HttpStatus.CREATED).body(createdOrder);
+ }
+
+ /**
+ * Update order status.
+ *
+ * @param id the order ID
+ * @param request the request containing the new status
+ * @return the updated order if found, 404 otherwise
+ */
+ @PutMapping("/{id}/status")
+ public ResponseEntity updateOrderStatus(@PathVariable("id") Long id, @RequestBody Map request) {
+ String status = request.get("status");
+ Optional updatedOrder = orderService.updateOrderStatus(id, status);
+ return updatedOrder.map(ResponseEntity::ok)
+ .orElse(ResponseEntity.notFound().build());
+ }
+
+ /**
+ * Cancel an order.
+ *
+ * @param id the order ID
+ * @return 204 if cancelled, 404 if not found
+ */
+ @DeleteMapping("/{id}")
+ public ResponseEntity cancelOrder(@PathVariable("id") Long id) {
+ boolean cancelled = orderService.cancelOrder(id);
+ return cancelled ? ResponseEntity.noContent().build() : ResponseEntity.notFound().build();
+ }
+
+ /**
+ * Health check endpoint.
+ *
+ * @return service status
+ */
+ @GetMapping("/health")
+ public ResponseEntity healthCheck() {
+ return ResponseEntity.ok("Order Service is running!");
+ }
+}
diff --git a/server-side-service-discovery/order-service/src/main/java/com/iluwatar/orderservice/model/Order.java b/server-side-service-discovery/order-service/src/main/java/com/iluwatar/orderservice/model/Order.java
new file mode 100644
index 000000000000..2c395af76b9a
--- /dev/null
+++ b/server-side-service-discovery/order-service/src/main/java/com/iluwatar/orderservice/model/Order.java
@@ -0,0 +1,146 @@
+/*
+ * 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.orderservice.model;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * Order entity representing an order in the system.
+ */
+public class Order {
+ private Long id;
+ private String customerName;
+ private String customerEmail;
+ private List items;
+ private Double totalAmount;
+ private String status;
+ private LocalDateTime createdAt;
+
+ /**
+ * Default constructor.
+ */
+ public Order() {
+ this.createdAt = LocalDateTime.now();
+ this.status = "PENDING";
+ }
+
+ /**
+ * Constructor with essential fields.
+ *
+ * @param customerName the customer name
+ * @param customerEmail the customer email
+ * @param items the order items
+ */
+ public Order(String customerName, String customerEmail, List items) {
+ this();
+ this.customerName = customerName;
+ this.customerEmail = customerEmail;
+ this.items = items;
+ calculateTotalAmount();
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getCustomerName() {
+ return customerName;
+ }
+
+ public void setCustomerName(String customerName) {
+ this.customerName = customerName;
+ }
+
+ public String getCustomerEmail() {
+ return customerEmail;
+ }
+
+ public void setCustomerEmail(String customerEmail) {
+ this.customerEmail = customerEmail;
+ }
+
+ public List getItems() {
+ return items;
+ }
+
+ public void setItems(List items) {
+ this.items = items;
+ calculateTotalAmount();
+ }
+
+ public Double getTotalAmount() {
+ return totalAmount;
+ }
+
+ public void setTotalAmount(Double totalAmount) {
+ this.totalAmount = totalAmount;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public LocalDateTime getCreatedAt() {
+ return createdAt;
+ }
+
+ public void setCreatedAt(LocalDateTime createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ /**
+ * Calculate the total amount based on order items.
+ */
+ private void calculateTotalAmount() {
+ if (items != null) {
+ this.totalAmount = items.stream()
+ .mapToDouble(item -> item.getPrice() * item.getQuantity())
+ .sum();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "Order{" +
+ "id=" + id +
+ ", customerName='" + customerName + '\'' +
+ ", customerEmail='" + customerEmail + '\'' +
+ ", items=" + items +
+ ", totalAmount=" + totalAmount +
+ ", status='" + status + '\'' +
+ ", createdAt=" + createdAt +
+ '}';
+ }
+}
diff --git a/server-side-service-discovery/order-service/src/main/java/com/iluwatar/orderservice/model/OrderItem.java b/server-side-service-discovery/order-service/src/main/java/com/iluwatar/orderservice/model/OrderItem.java
new file mode 100644
index 000000000000..65e9c35872ea
--- /dev/null
+++ b/server-side-service-discovery/order-service/src/main/java/com/iluwatar/orderservice/model/OrderItem.java
@@ -0,0 +1,99 @@
+/*
+ * 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.orderservice.model;
+
+/**
+ * OrderItem entity representing an item in an order.
+ */
+public class OrderItem {
+ private Long productId;
+ private String productName;
+ private Integer quantity;
+ private Double price;
+
+ /**
+ * Default constructor.
+ */
+ public OrderItem() {
+ }
+
+ /**
+ * Constructor with all fields.
+ *
+ * @param productId the product ID
+ * @param productName the product name
+ * @param quantity the quantity
+ * @param price the unit price
+ */
+ public OrderItem(Long productId, String productName, Integer quantity, Double price) {
+ this.productId = productId;
+ this.productName = productName;
+ this.quantity = quantity;
+ this.price = price;
+ }
+
+ public Long getProductId() {
+ return productId;
+ }
+
+ public void setProductId(Long productId) {
+ this.productId = productId;
+ }
+
+ public String getProductName() {
+ return productName;
+ }
+
+ public void setProductName(String productName) {
+ this.productName = productName;
+ }
+
+ public Integer getQuantity() {
+ return quantity;
+ }
+
+ public void setQuantity(Integer quantity) {
+ this.quantity = quantity;
+ }
+
+ public Double getPrice() {
+ return price;
+ }
+
+ public void setPrice(Double price) {
+ this.price = price;
+ }
+
+ @Override
+ public String toString() {
+ return "OrderItem{" +
+ "productId=" + productId +
+ ", productName='" + productName + '\'' +
+ ", quantity=" + quantity +
+ ", price=" + price +
+ '}';
+ }
+}
diff --git a/server-side-service-discovery/order-service/src/main/java/com/iluwatar/orderservice/service/OrderBusinessService.java b/server-side-service-discovery/order-service/src/main/java/com/iluwatar/orderservice/service/OrderBusinessService.java
new file mode 100644
index 000000000000..3583546f1439
--- /dev/null
+++ b/server-side-service-discovery/order-service/src/main/java/com/iluwatar/orderservice/service/OrderBusinessService.java
@@ -0,0 +1,127 @@
+/*
+ * 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.orderservice.service;
+
+import com.iluwatar.orderservice.model.Order;
+import com.iluwatar.orderservice.model.OrderItem;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Service class for managing orders.
+ * Provides business logic for order operations.
+ */
+@Service
+public class OrderBusinessService {
+
+ private final List orders = new ArrayList<>();
+ private final AtomicLong nextId = new AtomicLong(1);
+
+ /**
+ * Constructor that initializes some sample orders.
+ */
+ public OrderBusinessService() {
+ // Create sample orders
+ List items1 = List.of(
+ new OrderItem(1L, "Laptop", 1, 999.99),
+ new OrderItem(2L, "Book", 2, 49.99)
+ );
+ Order order1 = new Order("John Doe", "john@example.com", items1);
+ order1.setId(nextId.getAndIncrement());
+ orders.add(order1);
+
+ List items2 = List.of(
+ new OrderItem(3L, "Coffee Mug", 1, 19.99)
+ );
+ Order order2 = new Order("Jane Smith", "jane@example.com", items2);
+ order2.setId(nextId.getAndIncrement());
+ orders.add(order2);
+ }
+
+ /**
+ * Get all orders.
+ *
+ * @return list of all orders
+ */
+ public List getAllOrders() {
+ return new ArrayList<>(orders);
+ }
+
+ /**
+ * Get order by ID.
+ *
+ * @param id the order ID
+ * @return the order if found, empty otherwise
+ */
+ public Optional getOrderById(Long id) {
+ return orders.stream()
+ .filter(order -> order.getId().equals(id))
+ .findFirst();
+ }
+
+ /**
+ * Create a new order.
+ *
+ * @param order the order to create
+ * @return the created order
+ */
+ public Order createOrder(Order order) {
+ order.setId(nextId.getAndIncrement());
+ orders.add(order);
+ return order;
+ }
+
+ /**
+ * Update order status.
+ *
+ * @param id the order ID
+ * @param status the new status
+ * @return the updated order if found, empty otherwise
+ */
+ public Optional updateOrderStatus(Long id, String status) {
+ Optional orderOpt = getOrderById(id);
+ if (orderOpt.isPresent()) {
+ Order order = orderOpt.get();
+ order.setStatus(status);
+ return Optional.of(order);
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * Delete an order by ID.
+ *
+ * @param id the order ID
+ * @return true if order was deleted, false otherwise
+ */
+ public boolean deleteOrder(Long id) {
+ return orders.removeIf(order -> order.getId().equals(id));
+ }
+}
diff --git a/server-side-service-discovery/order-service/src/main/java/com/iluwatar/orderservice/service/OrderService.java b/server-side-service-discovery/order-service/src/main/java/com/iluwatar/orderservice/service/OrderService.java
new file mode 100644
index 000000000000..b61276427a6f
--- /dev/null
+++ b/server-side-service-discovery/order-service/src/main/java/com/iluwatar/orderservice/service/OrderService.java
@@ -0,0 +1,131 @@
+/*
+ * 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.orderservice.service;
+
+import com.iluwatar.orderservice.model.Order;
+import com.iluwatar.orderservice.model.OrderItem;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Service class for managing orders.
+ * Provides business logic for order operations.
+ */
+@Service
+public class OrderService {
+
+ private final List orders = new ArrayList<>();
+ private Long nextId = 1L;
+
+ /**
+ * Constructor that initializes some sample orders.
+ */
+ public OrderService() {
+ List items1 = List.of(
+ new OrderItem(1L, "Laptop", 1, 999.99),
+ new OrderItem(2L, "Book", 2, 49.99)
+ );
+ Order order1 = new Order("John Doe", "john@example.com", items1);
+ order1.setId(nextId++);
+ orders.add(order1);
+
+ List items2 = List.of(
+ new OrderItem(3L, "Coffee Mug", 3, 19.99)
+ );
+ Order order2 = new Order("Jane Smith", "jane@example.com", items2);
+ order2.setId(nextId++);
+ orders.add(order2);
+ }
+
+ /**
+ * Get all orders.
+ *
+ * @return list of all orders
+ */
+ public List getAllOrders() {
+ return new ArrayList<>(orders);
+ }
+
+ /**
+ * Get order by ID.
+ *
+ * @param id the order ID
+ * @return the order if found, empty otherwise
+ */
+ public Optional getOrderById(Long id) {
+ return orders.stream()
+ .filter(order -> order.getId().equals(id))
+ .findFirst();
+ }
+
+ /**
+ * Create a new order.
+ *
+ * @param order the order to create
+ * @return the created order
+ */
+ public Order createOrder(Order order) {
+ order.setId(nextId++);
+ order.setStatus("CONFIRMED");
+ orders.add(order);
+ return order;
+ }
+
+ /**
+ * Update order status.
+ *
+ * @param id the order ID
+ * @param status the new status
+ * @return the updated order if found, empty otherwise
+ */
+ public Optional updateOrderStatus(Long id, String status) {
+ Optional orderOpt = getOrderById(id);
+ if (orderOpt.isPresent()) {
+ Order order = orderOpt.get();
+ order.setStatus(status);
+ return Optional.of(order);
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * Cancel an order.
+ *
+ * @param id the order ID
+ * @return true if order was cancelled, false otherwise
+ */
+ public boolean cancelOrder(Long id) {
+ Optional orderOpt = getOrderById(id);
+ if (orderOpt.isPresent()) {
+ orderOpt.get().setStatus("CANCELLED");
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/server-side-service-discovery/order-service/src/main/resources/application.properties b/server-side-service-discovery/order-service/src/main/resources/application.properties
new file mode 100644
index 000000000000..40587f8a24a1
--- /dev/null
+++ b/server-side-service-discovery/order-service/src/main/resources/application.properties
@@ -0,0 +1,6 @@
+server.port=8082
+spring.application.name=order-service
+eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
+eureka.instance.prefer-ip-address=true
+management.endpoints.web.exposure.include=health,info
+management.endpoint.health.show-details=always
diff --git a/server-side-service-discovery/order-service/src/test/java/com/iluwatar/orderservice/service/OrderServiceTest.java b/server-side-service-discovery/order-service/src/test/java/com/iluwatar/orderservice/service/OrderServiceTest.java
new file mode 100644
index 000000000000..e4a3e2ca6772
--- /dev/null
+++ b/server-side-service-discovery/order-service/src/test/java/com/iluwatar/orderservice/service/OrderServiceTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.orderservice.service;
+
+import com.iluwatar.orderservice.model.Order;
+import com.iluwatar.orderservice.model.OrderItem;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Unit tests for OrderService.
+ */
+class OrderServiceTest {
+
+ private OrderService orderService;
+
+ @BeforeEach
+ void setUp() {
+ orderService = new OrderService();
+ }
+
+ @Test
+ void testGetAllOrders() {
+ List orders = orderService.getAllOrders();
+ assertNotNull(orders);
+ assertEquals(2, orders.size());
+ }
+
+ @Test
+ void testGetOrderById() {
+ Optional order = orderService.getOrderById(1L);
+ assertTrue(order.isPresent());
+ assertEquals("John Doe", order.get().getCustomerName());
+ }
+
+ @Test
+ void testGetOrderByIdNotFound() {
+ Optional order = orderService.getOrderById(999L);
+ assertFalse(order.isPresent());
+ }
+
+ @Test
+ void testCreateOrder() {
+ List items = List.of(
+ new OrderItem(1L, "Test Product", 2, 50.0)
+ );
+ Order newOrder = new Order("Test Customer", "test@example.com", items);
+ Order createdOrder = orderService.createOrder(newOrder);
+
+ assertNotNull(createdOrder.getId());
+ assertEquals("CONFIRMED", createdOrder.getStatus());
+ assertEquals(3, orderService.getAllOrders().size());
+ }
+
+ @Test
+ void testUpdateOrderStatus() {
+ Optional updatedOrder = orderService.updateOrderStatus(1L, "SHIPPED");
+ assertTrue(updatedOrder.isPresent());
+ assertEquals("SHIPPED", updatedOrder.get().getStatus());
+ }
+
+ @Test
+ void testUpdateOrderStatusNotFound() {
+ Optional updatedOrder = orderService.updateOrderStatus(999L, "SHIPPED");
+ assertFalse(updatedOrder.isPresent());
+ }
+
+ @Test
+ void testCancelOrder() {
+ boolean cancelled = orderService.cancelOrder(1L);
+ assertTrue(cancelled);
+
+ Optional order = orderService.getOrderById(1L);
+ assertTrue(order.isPresent());
+ assertEquals("CANCELLED", order.get().getStatus());
+ }
+
+ @Test
+ void testCancelOrderNotFound() {
+ boolean cancelled = orderService.cancelOrder(999L);
+ assertFalse(cancelled);
+ }
+}
diff --git a/server-side-service-discovery/pom.xml b/server-side-service-discovery/pom.xml
new file mode 100644
index 000000000000..3078c71f8f6e
--- /dev/null
+++ b/server-side-service-discovery/pom.xml
@@ -0,0 +1,68 @@
+
+
+
+
+ java-design-patterns
+ com.iluwatar
+ 1.26.0-SNAPSHOT
+
+ 4.0.0
+ server-side-service-discovery
+ pom
+
+
+ 3.4.4
+ 2024.0.0
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring.boot.version}
+ pom
+ import
+
+
+ org.springframework.cloud
+ spring-cloud-dependencies
+ ${spring.cloud.version}
+ pom
+ import
+
+
+
+
+
+ service-registry
+ product-service
+ order-service
+ service-consumer
+
+
diff --git a/server-side-service-discovery/product-service/etc/product-service.properties b/server-side-service-discovery/product-service/etc/product-service.properties
new file mode 100644
index 000000000000..73e3a644be55
--- /dev/null
+++ b/server-side-service-discovery/product-service/etc/product-service.properties
@@ -0,0 +1,21 @@
+# Product Service Configuration for Server-Side Service Discovery
+
+# Server Configuration
+server.port=8081
+spring.application.name=product-service
+
+# Eureka Client Configuration
+eureka.client.service-url.default-zone=http://localhost:8761/eureka/
+eureka.client.register-with-eureka=true
+eureka.client.fetch-registry=true
+eureka.instance.prefer-ip-address=true
+eureka.instance.lease-renewal-interval-in-seconds=10
+eureka.instance.lease-expiration-duration-in-seconds=30
+
+# Health Check Configuration
+management.endpoints.web.exposure.include=health,info,metrics
+management.endpoint.health.show-details=always
+
+# Logging Configuration
+logging.level.com.netflix.eureka=DEBUG
+logging.level.com.netflix.discovery=DEBUG
diff --git a/server-side-service-discovery/product-service/pom.xml b/server-side-service-discovery/product-service/pom.xml
new file mode 100644
index 000000000000..eed90a7267e2
--- /dev/null
+++ b/server-side-service-discovery/product-service/pom.xml
@@ -0,0 +1,95 @@
+
+
+
+
+ server-side-service-discovery
+ com.iluwatar
+ 1.26.0-SNAPSHOT
+
+ 4.0.0
+ product-service
+ jar
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-client
+ 4.1.3
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ 3.4.4
+
+
+
+ repackage
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+
+
+
+ com.iluwatar.productservice.ProductServiceApp
+
+
+
+
+
+
+
+
+
diff --git a/server-side-service-discovery/product-service/src/main/java/com/iluwatar/productservice/ProductServiceApp.java b/server-side-service-discovery/product-service/src/main/java/com/iluwatar/productservice/ProductServiceApp.java
new file mode 100644
index 000000000000..b983bd9feda1
--- /dev/null
+++ b/server-side-service-discovery/product-service/src/main/java/com/iluwatar/productservice/ProductServiceApp.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.productservice;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * Product Service Application that registers itself with the Service Registry.
+ * This demonstrates the Service Provider component of the Server-Side Service Discovery pattern.
+ */
+@SpringBootApplication
+public class ProductServiceApp {
+
+ /**
+ * Main method to start the Product Service application.
+ *
+ * @param args command line arguments
+ */
+ public static void main(String[] args) {
+ SpringApplication.run(ProductServiceApp.class, args);
+ }
+}
diff --git a/server-side-service-discovery/product-service/src/main/java/com/iluwatar/productservice/config/ProductServiceConfig.java b/server-side-service-discovery/product-service/src/main/java/com/iluwatar/productservice/config/ProductServiceConfig.java
new file mode 100644
index 000000000000..ad2ff7c7c784
--- /dev/null
+++ b/server-side-service-discovery/product-service/src/main/java/com/iluwatar/productservice/config/ProductServiceConfig.java
@@ -0,0 +1,83 @@
+/*
+ * 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.productservice.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * Configuration for Product Service.
+ * Configures application properties and beans for the service.
+ */
+@Configuration
+public class ProductServiceConfig {
+
+ /**
+ * Creates a RestTemplate bean for making HTTP requests.
+ *
+ * @return RestTemplate instance
+ */
+ @Bean
+ public RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+
+ /**
+ * Application properties for the Product Service.
+ */
+ @ConfigurationProperties(prefix = "app")
+ public static class ProductServiceProperties {
+ private String name = "product-service";
+ private int port = 8081;
+ private String eurekaUrl = "http://localhost:8761/eureka/";
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ public String getEurekaUrl() {
+ return eurekaUrl;
+ }
+
+ public void setEurekaUrl(String eurekaUrl) {
+ this.eurekaUrl = eurekaUrl;
+ }
+ }
+}
diff --git a/server-side-service-discovery/product-service/src/main/java/com/iluwatar/productservice/controller/ProductController.java b/server-side-service-discovery/product-service/src/main/java/com/iluwatar/productservice/controller/ProductController.java
new file mode 100644
index 000000000000..5cfa8c8a6a3c
--- /dev/null
+++ b/server-side-service-discovery/product-service/src/main/java/com/iluwatar/productservice/controller/ProductController.java
@@ -0,0 +1,110 @@
+/*
+ * 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.productservice.controller;
+
+import com.iluwatar.productservice.model.Product;
+import com.iluwatar.productservice.service.ProductService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * REST Controller for Product operations.
+ * Provides endpoints for managing products.
+ */
+@RestController
+@RequestMapping("/products")
+public class ProductController {
+
+ private final ProductService productService;
+
+ @Autowired
+ public ProductController(ProductService productService) {
+ this.productService = productService;
+ }
+
+ /**
+ * Get all products.
+ *
+ * @return list of all products
+ */
+ @GetMapping
+ public ResponseEntity> getAllProducts() {
+ List products = productService.getAllProducts();
+ return ResponseEntity.ok(products);
+ }
+
+ /**
+ * Get product by ID.
+ *
+ * @param id the product ID
+ * @return the product if found, 404 otherwise
+ */
+ @GetMapping("/{id}")
+ public ResponseEntity getProductById(@PathVariable("id") Long id) {
+ Optional product = productService.getProductById(id);
+ return product.map(ResponseEntity::ok)
+ .orElse(ResponseEntity.notFound().build());
+ }
+
+ /**
+ * Add a new product.
+ *
+ * @param product the product to add
+ * @return the created product
+ */
+ @PostMapping
+ public ResponseEntity addProduct(@RequestBody Product product) {
+ Product createdProduct = productService.addProduct(product);
+ return ResponseEntity.status(HttpStatus.CREATED).body(createdProduct);
+ }
+
+ /**
+ * Delete a product by ID.
+ *
+ * @param id the product ID
+ * @return 204 if deleted, 404 if not found
+ */
+ @DeleteMapping("/{id}")
+ public ResponseEntity deleteProduct(@PathVariable("id") Long id) {
+ boolean deleted = productService.deleteProduct(id);
+ return deleted ? ResponseEntity.noContent().build() : ResponseEntity.notFound().build();
+ }
+
+ /**
+ * Health check endpoint.
+ *
+ * @return service status
+ */
+ @GetMapping("/health")
+ public ResponseEntity healthCheck() {
+ return ResponseEntity.ok("Product Service is running!");
+ }
+}
diff --git a/server-side-service-discovery/product-service/src/main/java/com/iluwatar/productservice/model/Product.java b/server-side-service-discovery/product-service/src/main/java/com/iluwatar/productservice/model/Product.java
new file mode 100644
index 000000000000..3b3f201d113c
--- /dev/null
+++ b/server-side-service-discovery/product-service/src/main/java/com/iluwatar/productservice/model/Product.java
@@ -0,0 +1,111 @@
+/*
+ * 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.productservice.model;
+
+/**
+ * Product entity representing a product in the system.
+ */
+public class Product {
+ private Long id;
+ private String name;
+ private String description;
+ private Double price;
+ private String category;
+
+ /**
+ * Default constructor.
+ */
+ public Product() {
+ }
+
+ /**
+ * Constructor with all fields.
+ *
+ * @param id the product id
+ * @param name the product name
+ * @param description the product description
+ * @param price the product price
+ * @param category the product category
+ */
+ public Product(Long id, String name, String description, Double price, String category) {
+ this.id = id;
+ this.name = name;
+ this.description = description;
+ this.price = price;
+ this.category = category;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public Double getPrice() {
+ return price;
+ }
+
+ public void setPrice(Double price) {
+ this.price = price;
+ }
+
+ public String getCategory() {
+ return category;
+ }
+
+ public void setCategory(String category) {
+ this.category = category;
+ }
+
+ @Override
+ public String toString() {
+ return "Product{" +
+ "id=" + id +
+ ", name='" + name + '\'' +
+ ", description='" + description + '\'' +
+ ", price=" + price +
+ ", category='" + category + '\'' +
+ '}';
+ }
+}
diff --git a/server-side-service-discovery/product-service/src/main/java/com/iluwatar/productservice/service/ProductService.java b/server-side-service-discovery/product-service/src/main/java/com/iluwatar/productservice/service/ProductService.java
new file mode 100644
index 000000000000..02fa4568f343
--- /dev/null
+++ b/server-side-service-discovery/product-service/src/main/java/com/iluwatar/productservice/service/ProductService.java
@@ -0,0 +1,101 @@
+/*
+ * 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.productservice.service;
+
+import com.iluwatar.productservice.model.Product;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Optional;
+
+/**
+ * Service class for managing products.
+ * Provides business logic for product operations.
+ */
+@Service
+public class ProductService {
+
+ private final List products = new ArrayList<>();
+
+ /**
+ * Constructor that initializes some sample products.
+ */
+ public ProductService() {
+ products.add(new Product(1L, "Laptop", "High-performance laptop", 999.99, "Electronics"));
+ products.add(new Product(2L, "Book", "Java Design Patterns", 49.99, "Books"));
+ products.add(new Product(3L, "Coffee Mug", "Programmer's coffee mug", 19.99, "Office Supplies"));
+ }
+
+ /**
+ * Get all products.
+ *
+ * @return list of all products
+ */
+ public List getAllProducts() {
+ return new ArrayList<>(products);
+ }
+
+ /**
+ * Get product by ID.
+ *
+ * @param id the product ID
+ * @return the product if found, empty otherwise
+ */
+ public Optional getProductById(Long id) {
+ return products.stream()
+ .filter(product -> product.getId().equals(id))
+ .findFirst();
+ }
+
+ /**
+ * Add a new product.
+ *
+ * @param product the product to add
+ * @return the added product
+ */
+ public Product addProduct(Product product) {
+ if (product.getId() == null) {
+ Long nextId = products.stream()
+ .mapToLong(Product::getId)
+ .max()
+ .orElse(0) + 1;
+ product.setId(nextId);
+ }
+ products.add(product);
+ return product;
+ }
+
+ /**
+ * Delete a product by ID.
+ *
+ * @param id the product ID
+ * @return true if product was deleted, false otherwise
+ */
+ public boolean deleteProduct(Long id) {
+ return products.removeIf(product -> product.getId().equals(id));
+ }
+}
diff --git a/server-side-service-discovery/product-service/src/main/resources/application.properties b/server-side-service-discovery/product-service/src/main/resources/application.properties
new file mode 100644
index 000000000000..cab7ae08a850
--- /dev/null
+++ b/server-side-service-discovery/product-service/src/main/resources/application.properties
@@ -0,0 +1,6 @@
+server.port=8081
+spring.application.name=product-service
+eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
+eureka.instance.prefer-ip-address=true
+management.endpoints.web.exposure.include=health,info
+management.endpoint.health.show-details=always
diff --git a/server-side-service-discovery/product-service/src/test/java/com/iluwatar/productservice/service/ProductServiceTest.java b/server-side-service-discovery/product-service/src/test/java/com/iluwatar/productservice/service/ProductServiceTest.java
new file mode 100644
index 000000000000..f2f2cf116f15
--- /dev/null
+++ b/server-side-service-discovery/product-service/src/test/java/com/iluwatar/productservice/service/ProductServiceTest.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.productservice.service;
+
+import com.iluwatar.productservice.model.Product;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Unit tests for ProductService.
+ */
+class ProductServiceTest {
+
+ private ProductService productService;
+
+ @BeforeEach
+ void setUp() {
+ productService = new ProductService();
+ }
+
+ @Test
+ void testGetAllProducts() {
+ List products = productService.getAllProducts();
+ assertNotNull(products);
+ assertEquals(3, products.size());
+ }
+
+ @Test
+ void testGetProductById() {
+ Optional product = productService.getProductById(1L);
+ assertTrue(product.isPresent());
+ assertEquals("Laptop", product.get().getName());
+ }
+
+ @Test
+ void testGetProductByIdNotFound() {
+ Optional product = productService.getProductById(999L);
+ assertFalse(product.isPresent());
+ }
+
+ @Test
+ void testAddProduct() {
+ Product newProduct = new Product(null, "Tablet", "Android tablet", 299.99, "Electronics");
+ Product addedProduct = productService.addProduct(newProduct);
+
+ assertNotNull(addedProduct.getId());
+ assertEquals("Tablet", addedProduct.getName());
+ assertEquals(4, productService.getAllProducts().size());
+ }
+
+ @Test
+ void testDeleteProduct() {
+ boolean deleted = productService.deleteProduct(1L);
+ assertTrue(deleted);
+ assertEquals(2, productService.getAllProducts().size());
+ }
+
+ @Test
+ void testDeleteProductNotFound() {
+ boolean deleted = productService.deleteProduct(999L);
+ assertFalse(deleted);
+ assertEquals(3, productService.getAllProducts().size());
+ }
+}
diff --git a/server-side-service-discovery/service-consumer/etc/service-consumer.properties b/server-side-service-discovery/service-consumer/etc/service-consumer.properties
new file mode 100644
index 000000000000..e889a3a19515
--- /dev/null
+++ b/server-side-service-discovery/service-consumer/etc/service-consumer.properties
@@ -0,0 +1,24 @@
+# Service Consumer Configuration for Server-Side Service Discovery
+
+# Server Configuration
+server.port=8080
+spring.application.name=service-consumer
+
+# Eureka Client Configuration
+eureka.client.service-url.default-zone=http://localhost:8761/eureka/
+eureka.client.register-with-eureka=true
+eureka.client.fetch-registry=true
+eureka.instance.prefer-ip-address=true
+eureka.instance.lease-renewal-interval-in-seconds=10
+eureka.instance.lease-expiration-duration-in-seconds=30
+
+# Health Check Configuration
+management.endpoints.web.exposure.include=health,info,metrics
+management.endpoint.health.show-details=always
+
+# Logging Configuration
+logging.level.com.netflix.eureka=DEBUG
+logging.level.com.netflix.discovery=DEBUG
+
+# Load Balancer Configuration
+spring.cloud.loadbalancer.ribbon.enabled=false
diff --git a/server-side-service-discovery/service-consumer/pom.xml b/server-side-service-discovery/service-consumer/pom.xml
new file mode 100644
index 000000000000..63823868fbb9
--- /dev/null
+++ b/server-side-service-discovery/service-consumer/pom.xml
@@ -0,0 +1,100 @@
+
+
+
+
+ server-side-service-discovery
+ com.iluwatar
+ 1.26.0-SNAPSHOT
+
+ 4.0.0
+ service-consumer
+ jar
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-client
+ 4.1.3
+
+
+ org.springframework.cloud
+ spring-cloud-starter-loadbalancer
+ 4.1.4
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ 3.4.4
+
+
+
+ repackage
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+
+
+
+ com.iluwatar.serviceconsumer.ServiceConsumerApp
+
+
+
+
+
+
+
+
+
diff --git a/server-side-service-discovery/service-consumer/src/main/java/com/iluwatar/serviceconsumer/ServiceConsumerApp.java b/server-side-service-discovery/service-consumer/src/main/java/com/iluwatar/serviceconsumer/ServiceConsumerApp.java
new file mode 100644
index 000000000000..95db21273884
--- /dev/null
+++ b/server-side-service-discovery/service-consumer/src/main/java/com/iluwatar/serviceconsumer/ServiceConsumerApp.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.serviceconsumer;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * Service Consumer Application that discovers and consumes services from the Service Registry.
+ * This demonstrates the Service Consumer component of the Server-Side Service Discovery pattern.
+ */
+@SpringBootApplication
+public class ServiceConsumerApp {
+
+ /**
+ * Main method to start the Service Consumer application.
+ *
+ * @param args command line arguments
+ */
+ public static void main(String[] args) {
+ SpringApplication.run(ServiceConsumerApp.class, args);
+ }
+}
diff --git a/server-side-service-discovery/service-consumer/src/main/java/com/iluwatar/serviceconsumer/config/ServiceConsumerConfig.java b/server-side-service-discovery/service-consumer/src/main/java/com/iluwatar/serviceconsumer/config/ServiceConsumerConfig.java
new file mode 100644
index 000000000000..993bcd2365d7
--- /dev/null
+++ b/server-side-service-discovery/service-consumer/src/main/java/com/iluwatar/serviceconsumer/config/ServiceConsumerConfig.java
@@ -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.
+ */
+
+package com.iluwatar.serviceconsumer.config;
+
+import org.springframework.cloud.client.loadbalancer.LoadBalanced;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * Configuration class for Service Consumer.
+ * Configures the RestTemplate with load balancing for service discovery.
+ */
+@Configuration
+public class ServiceConsumerConfig {
+
+ /**
+ * Create a load-balanced RestTemplate bean.
+ * The @LoadBalanced annotation enables client-side load balancing
+ * using the service names registered in the service registry.
+ *
+ * @return load-balanced RestTemplate
+ */
+ @Bean
+ @LoadBalanced
+ public RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+}
diff --git a/server-side-service-discovery/service-consumer/src/main/java/com/iluwatar/serviceconsumer/controller/ServiceConsumerController.java b/server-side-service-discovery/service-consumer/src/main/java/com/iluwatar/serviceconsumer/controller/ServiceConsumerController.java
new file mode 100644
index 000000000000..1cd36c383696
--- /dev/null
+++ b/server-side-service-discovery/service-consumer/src/main/java/com/iluwatar/serviceconsumer/controller/ServiceConsumerController.java
@@ -0,0 +1,149 @@
+/*
+ * 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.serviceconsumer.controller;
+
+import com.iluwatar.serviceconsumer.service.ServiceDiscoveryService;
+import com.netflix.appinfo.InstanceInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * REST Controller that demonstrates service discovery and consumption.
+ * This controller shows how to discover services and make calls to them
+ * using the Server-Side Service Discovery pattern.
+ */
+@RestController
+@RequestMapping("/api")
+public class ServiceConsumerController {
+
+ private final ServiceDiscoveryService serviceDiscoveryService;
+
+ @Autowired
+ public ServiceConsumerController(ServiceDiscoveryService serviceDiscoveryService) {
+ this.serviceDiscoveryService = serviceDiscoveryService;
+ }
+
+ /**
+ * Discover all available services.
+ *
+ * @return list of all registered services
+ */
+ @GetMapping("/services")
+ public ResponseEntity> discoverAllServices() {
+ List services = serviceDiscoveryService.getAllServices();
+ return ResponseEntity.ok(services);
+ }
+
+ /**
+ * Discover instances of a specific service.
+ *
+ * @param serviceName the name of the service
+ * @return list of service instances
+ */
+ @GetMapping("/services/{serviceName}/instances")
+ public ResponseEntity> discoverServiceInstances(@PathVariable("serviceName") String serviceName) {
+ List instances = serviceDiscoveryService.discoverService(serviceName);
+ return ResponseEntity.ok(instances);
+ }
+
+ /**
+ * Check if a service is available.
+ *
+ * @param serviceName the name of the service
+ * @return service availability status
+ */
+ @GetMapping("/services/{serviceName}/availability")
+ public ResponseEntity