From 4c66f20575636903d2d0ea1c0571817383fc3a80 Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 18 Jun 2026 17:39:51 +0300 Subject: [PATCH 1/5] Implement asynchronous request processor with caching --- .../java/mate/academy/AsyncRequestProcessor.java | 14 +++++++++++++- src/main/java/mate/academy/Main.java | 4 +++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/main/java/mate/academy/AsyncRequestProcessor.java b/src/main/java/mate/academy/AsyncRequestProcessor.java index ee5eea1..40f9917 100644 --- a/src/main/java/mate/academy/AsyncRequestProcessor.java +++ b/src/main/java/mate/academy/AsyncRequestProcessor.java @@ -1,16 +1,28 @@ package mate.academy; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; public class AsyncRequestProcessor { private final Executor executor; + ConcurrentHashMap> cache = new ConcurrentHashMap(); + public AsyncRequestProcessor(Executor executor) { this.executor = executor; } public CompletableFuture processRequest(String userId) { - return null; + return this.cache.computeIfAbsent( + userId, key -> CompletableFuture.supplyAsync(() -> { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + return new UserData(userId, "Details for " + userId); + }, this.executor) + ); } } diff --git a/src/main/java/mate/academy/Main.java b/src/main/java/mate/academy/Main.java index a3c9b9e..42e237d 100644 --- a/src/main/java/mate/academy/Main.java +++ b/src/main/java/mate/academy/Main.java @@ -2,11 +2,13 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; public class Main { public static void main(String[] args) { // Feel free to play with AsyncRequestProcessor in this main method if you want - ExecutorService executor = null; // Provide implementation that fits your needs + ExecutorService executor = Executors.newFixedThreadPool(10); // Provide implementation + // that fits your needs AsyncRequestProcessor asyncRequestProcessor = new AsyncRequestProcessor(executor); // Simulating multiple concurrent requests From 09ab2bc273af290c7a85b3e94532e3bf0acaef04 Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 18 Jun 2026 17:46:52 +0300 Subject: [PATCH 2/5] solution --- pom.xml | 4 ++-- .../mate/academy/AsyncRequestProcessor.java | 21 ++++++++----------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/pom.xml b/pom.xml index 981f403..cae55a3 100644 --- a/pom.xml +++ b/pom.xml @@ -9,8 +9,8 @@ 1.0-SNAPSHOT - 17 - 17 + 21 + 21 UTF-8 https://raw.githubusercontent.com/mate-academy/style-guides/master/java/checkstyle.xml diff --git a/src/main/java/mate/academy/AsyncRequestProcessor.java b/src/main/java/mate/academy/AsyncRequestProcessor.java index 40f9917..8e7c758 100644 --- a/src/main/java/mate/academy/AsyncRequestProcessor.java +++ b/src/main/java/mate/academy/AsyncRequestProcessor.java @@ -6,23 +6,20 @@ public class AsyncRequestProcessor { private final Executor executor; - ConcurrentHashMap> cache = new ConcurrentHashMap(); - + private ConcurrentHashMap> cache = new ConcurrentHashMap(); public AsyncRequestProcessor(Executor executor) { this.executor = executor; } public CompletableFuture processRequest(String userId) { - return this.cache.computeIfAbsent( - userId, key -> CompletableFuture.supplyAsync(() -> { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - return new UserData(userId, "Details for " + userId); - }, this.executor) - ); + return this.cache.computeIfAbsent(userId, key -> CompletableFuture.supplyAsync(() -> { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + return new UserData(userId, "Details for " + userId); + }, this.executor)); } } From f7df013ce10dc08bb49541b91f68b839882629d9 Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 18 Jun 2026 17:52:21 +0300 Subject: [PATCH 3/5] fix to jdk 21 --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bcedab6..f17654b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,10 +7,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@v4 with: - java-version: '17' + java-version: '21' distribution: 'temurin' cache: maven - name: Build with Maven From 68ce8e0fb362722bb37dae0230fdb30b819df6c0 Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 18 Jun 2026 18:07:07 +0300 Subject: [PATCH 4/5] Refactor cache to store UserData as per requirements --- .../java/mate/academy/AsyncRequestProcessor.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main/java/mate/academy/AsyncRequestProcessor.java b/src/main/java/mate/academy/AsyncRequestProcessor.java index 8e7c758..85edcbd 100644 --- a/src/main/java/mate/academy/AsyncRequestProcessor.java +++ b/src/main/java/mate/academy/AsyncRequestProcessor.java @@ -1,25 +1,34 @@ package mate.academy; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; public class AsyncRequestProcessor { private final Executor executor; - private ConcurrentHashMap> cache = new ConcurrentHashMap(); + private final Map cache = new ConcurrentHashMap<>(); public AsyncRequestProcessor(Executor executor) { this.executor = executor; } public CompletableFuture processRequest(String userId) { - return this.cache.computeIfAbsent(userId, key -> CompletableFuture.supplyAsync(() -> { + UserData cached = cache.get(userId); + if (cached != null) { + return CompletableFuture.completedFuture(cached); + } + + return CompletableFuture.supplyAsync(() -> { try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } return new UserData(userId, "Details for " + userId); - }, this.executor)); + }, this.executor).thenApply(userData -> { + cache.put(userId, userData); + return userData; + }); } } From 81f3aa641deb047a3710029a9df590fa5b76705d Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 18 Jun 2026 18:38:55 +0300 Subject: [PATCH 5/5] Refactor AsyncRequestProcessor for better readability --- .../mate/academy/AsyncRequestProcessor.java | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/main/java/mate/academy/AsyncRequestProcessor.java b/src/main/java/mate/academy/AsyncRequestProcessor.java index 85edcbd..222b86c 100644 --- a/src/main/java/mate/academy/AsyncRequestProcessor.java +++ b/src/main/java/mate/academy/AsyncRequestProcessor.java @@ -19,16 +19,28 @@ public CompletableFuture processRequest(String userId) { return CompletableFuture.completedFuture(cached); } + return fetchUserDataAsync(userId) + .thenApply(userData -> saveToCache(userId, userData)); + } + + private CompletableFuture fetchUserDataAsync(String userId) { return CompletableFuture.supplyAsync(() -> { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } + simulateDatabaseCall(); return new UserData(userId, "Details for " + userId); - }, this.executor).thenApply(userData -> { - cache.put(userId, userData); - return userData; - }); + }, this.executor); + } + + private UserData saveToCache(String userId, UserData userData) { + cache.put(userId, userData); + return userData; + } + + private void simulateDatabaseCall() { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Data fetching interrupted", e); + } } }