feat: Added Microservices UI Client side composition #2698 (#3062)

* Added Microservices client side ui composition to the repo.
Added ClientSideCompositionTest, ApiGateway, ClientSideIntegrator, FrontendComponent, CartFrontend, ProductFrontend, updated pom.xml, ReadME.md.

* Improved some checkstyle changes.

* Added Random variable to re-use the random instead of creating it everytime in FrontendComponent.

* changed the Pom.xml and upadted the ReadME.md

* Changes in the README.md File as per requirement, name of the file changed from ReadME.md to README.md

---------

Co-authored-by: Ilkka Seppälä <iluwatar@users.noreply.github.com>
This commit is contained in:
Tarun Vishwakarma
2025-01-07 00:25:08 +05:30
committed by GitHub
parent c06bd2c5a1
commit ab59dfe770
10 changed files with 442 additions and 0 deletions
@@ -0,0 +1,50 @@
package com.iluwatar.clientsideuicomposition;
import java.util.HashMap;
import java.util.Map;
/**
* ApiGateway class acts as a dynamic routing mechanism that forwards client
* requests to the appropriate frontend components based on dynamically
* registered routes.
*
* <p>This allows for flexible, runtime-defined routing without hardcoding specific paths.
*/
public class ApiGateway {
// A map to store routes dynamically, where the key is the path and the value
// is the associated FrontendComponent
private final Map<String, FrontendComponent> routes = new HashMap<>();
/**
* Registers a route dynamically at runtime.
*
* @param path the path to access the component (e.g., "/products")
* @param component the frontend component to be accessed at the given path
*/
public void registerRoute(String path, FrontendComponent component) {
routes.put(path, component);
}
/**
* Handles a client request by routing it to the appropriate frontend component.
*
* <p>This method dynamically handles parameters passed with the request, which
* allows the frontend components to respond based on those parameters.
*
* @param path the path for which the request is made (e.g., "/products", "/cart")
* @param params a map of parameters that might influence the data fetching logic
* (e.g., filters, userId, categories, etc.)
* @return the data fetched from the appropriate component or "404 Not Found"
* if the path is not registered
*/
public String handleRequest(String path, Map<String, String> params) {
if (routes.containsKey(path)) {
// Fetch data dynamically based on the provided parameters
return routes.get(path).fetchData(params);
} else {
// Return a 404 error if the path is not registered
return "404 Not Found";
}
}
}
@@ -0,0 +1,24 @@
package com.iluwatar.clientsideuicomposition;
import java.util.Map;
/**
* CartFrontend is a concrete implementation of FrontendComponent
* that simulates fetching shopping cart data based on the user.
*/
public class CartFrontend extends FrontendComponent {
/**
* Fetches the current state of the shopping cart based on dynamic parameters
* like user ID.
*
* @param params parameters that influence the cart data, e.g., "userId"
* @return a string representing the items in the shopping cart for a given
* user
*/
@Override
protected String getData(Map<String, String> params) {
String userId = params.getOrDefault("userId", "anonymous");
return "Shopping Cart for user '" + userId + "': [Item 1, Item 2]";
}
}
@@ -0,0 +1,40 @@
package com.iluwatar.clientsideuicomposition;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
/**
* ClientSideIntegrator class simulates the client-side integration layer that
* dynamically assembles various frontend components into a cohesive user
* interface.
*/
@Slf4j
public class ClientSideIntegrator {
private final ApiGateway apiGateway;
/**
* Constructor that accepts an instance of ApiGateway to handle dynamic
* routing.
*
* @param apiGateway the gateway that routes requests to different frontend
* components
*/
public ClientSideIntegrator(ApiGateway apiGateway) {
this.apiGateway = apiGateway;
}
/**
* Composes the user interface dynamically by fetching data from different
* frontend components based on provided parameters.
*
* @param path the route of the frontend component
* @param params a map of dynamic parameters to influence the data fetching
*/
public void composeUi(String path, Map<String, String> params) {
// Fetch data dynamically based on the route and parameters
String data = apiGateway.handleRequest(path, params);
LOGGER.info("Composed UI Component for path '" + path + "':");
LOGGER.info(data);
}
}
@@ -0,0 +1,40 @@
package com.iluwatar.clientsideuicomposition;
import java.util.Map;
import java.util.Random;
/**
* FrontendComponent is an abstract class representing an independent frontend
* component that fetches data dynamically based on the provided parameters.
*/
public abstract class FrontendComponent {
public static final Random random = new Random();
/**
* Simulates asynchronous data fetching by introducing a random delay and
* then fetching the data based on dynamic input.
*
* @param params a map of parameters that may affect the data fetching logic
* @return the data fetched by the frontend component
*/
public String fetchData(Map<String, String> params) {
try {
// Simulate delay in fetching data (e.g., network latency)
Thread.sleep(random.nextInt(1000));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// Fetch and return the data based on the given parameters
return getData(params);
}
/**
* Abstract method to be implemented by subclasses to return data based on
* parameters.
*
* @param params a map of parameters that may affect the data fetching logic
* @return the data for this specific component
*/
protected abstract String getData(Map<String, String> params);
}
@@ -0,0 +1,24 @@
package com.iluwatar.clientsideuicomposition;
import java.util.Map;
/**
* ProductFrontend is a concrete implementation of FrontendComponent
* that simulates fetching dynamic product data.
*/
public class ProductFrontend extends FrontendComponent {
/**
* Fetches a list of products based on dynamic parameters such as category.
*
* @param params parameters that influence the data fetched, e.g., "category"
* @return a string representing a filtered list of products
*/
@Override
protected String getData(Map<String, String> params) {
String category = params.getOrDefault("category", "all");
return "Product List for category '"
+ category
+ "': [Product 1, Product 2, Product 3]";
}
}