From 61ad8a1ea9698954ede474a6742a3c38d7671165 Mon Sep 17 00:00:00 2001 From: Natalia Cholewa Date: Sun, 18 Jan 2026 16:28:47 +0100 Subject: [PATCH] fix: resolve merge conflicts --- client/src/main/java/client/MyModule.java | 2 +- client/src/main/java/client/UI.java | 2 +- .../client/scenes/FoodpalApplicationCtrl.java | 2 +- .../java/client/scenes/SearchBarCtrl.java | 2 +- .../scenes/recipe/IngredientsPopupCtrl.java | 2 +- .../scenes/recipe/RecipeDetailCtrl.java | 2 +- .../java/client/utils/server/Endpoints.java | 87 +++++++++++++++++ .../utils/{ => server}/ServerUtils.java | 96 ++++++------------- .../test/java/client/ServerUtilsMockTest.java | 16 +++- .../src/test/java/client/ServerUtilsTest.java | 17 +++- 10 files changed, 151 insertions(+), 77 deletions(-) create mode 100644 client/src/main/java/client/utils/server/Endpoints.java rename client/src/main/java/client/utils/{ => server}/ServerUtils.java (78%) diff --git a/client/src/main/java/client/MyModule.java b/client/src/main/java/client/MyModule.java index 1561131..4d027ca 100644 --- a/client/src/main/java/client/MyModule.java +++ b/client/src/main/java/client/MyModule.java @@ -23,7 +23,7 @@ import client.scenes.recipe.IngredientListCtrl; import client.scenes.recipe.RecipeStepListCtrl; import client.utils.ConfigService; import client.utils.LocaleManager; -import client.utils.ServerUtils; +import client.utils.server.ServerUtils; import client.utils.WebSocketDataService; import client.utils.WebSocketUtils; import com.google.inject.Binder; diff --git a/client/src/main/java/client/UI.java b/client/src/main/java/client/UI.java index af43795..752dbaf 100644 --- a/client/src/main/java/client/UI.java +++ b/client/src/main/java/client/UI.java @@ -2,7 +2,7 @@ package client; import client.scenes.FoodpalApplicationCtrl; import client.scenes.MainCtrl; -import client.utils.ServerUtils; +import client.utils.server.ServerUtils; import com.google.inject.Injector; import javafx.application.Application; import javafx.scene.image.Image; diff --git a/client/src/main/java/client/scenes/FoodpalApplicationCtrl.java b/client/src/main/java/client/scenes/FoodpalApplicationCtrl.java index dbd89da..e7cb0df 100644 --- a/client/src/main/java/client/scenes/FoodpalApplicationCtrl.java +++ b/client/src/main/java/client/scenes/FoodpalApplicationCtrl.java @@ -18,7 +18,7 @@ import client.utils.ConfigService; import client.utils.DefaultValueFactory; import client.utils.LocaleAware; import client.utils.LocaleManager; -import client.utils.ServerUtils; +import client.utils.server.ServerUtils; import client.utils.WebSocketDataService; import client.utils.WebSocketUtils; import commons.Ingredient; diff --git a/client/src/main/java/client/scenes/SearchBarCtrl.java b/client/src/main/java/client/scenes/SearchBarCtrl.java index da40e3a..065455c 100644 --- a/client/src/main/java/client/scenes/SearchBarCtrl.java +++ b/client/src/main/java/client/scenes/SearchBarCtrl.java @@ -3,7 +3,7 @@ package client.scenes; import client.utils.ConfigService; import client.utils.LocaleAware; import client.utils.LocaleManager; -import client.utils.ServerUtils; +import client.utils.server.ServerUtils; import com.google.inject.Inject; import commons.Recipe; import javafx.animation.PauseTransition; diff --git a/client/src/main/java/client/scenes/recipe/IngredientsPopupCtrl.java b/client/src/main/java/client/scenes/recipe/IngredientsPopupCtrl.java index 5c55684..de27245 100644 --- a/client/src/main/java/client/scenes/recipe/IngredientsPopupCtrl.java +++ b/client/src/main/java/client/scenes/recipe/IngredientsPopupCtrl.java @@ -1,6 +1,6 @@ package client.scenes.recipe; -import client.utils.ServerUtils; +import client.utils.server.ServerUtils; import commons.Ingredient; import jakarta.inject.Inject; import javafx.fxml.FXML; diff --git a/client/src/main/java/client/scenes/recipe/RecipeDetailCtrl.java b/client/src/main/java/client/scenes/recipe/RecipeDetailCtrl.java index 608ac44..9601242 100644 --- a/client/src/main/java/client/scenes/recipe/RecipeDetailCtrl.java +++ b/client/src/main/java/client/scenes/recipe/RecipeDetailCtrl.java @@ -7,7 +7,7 @@ import client.utils.ConfigService; import client.utils.LocaleAware; import client.utils.LocaleManager; import client.utils.PrintExportService; -import client.utils.ServerUtils; +import client.utils.server.ServerUtils; import client.utils.WebSocketDataService; import com.google.inject.Inject; import commons.Recipe; diff --git a/client/src/main/java/client/utils/server/Endpoints.java b/client/src/main/java/client/utils/server/Endpoints.java new file mode 100644 index 0000000..f7ae27f --- /dev/null +++ b/client/src/main/java/client/utils/server/Endpoints.java @@ -0,0 +1,87 @@ +package client.utils.server; + +import client.utils.ConfigService; +import com.google.inject.Inject; + +import java.net.URI; +import java.net.http.HttpRequest; +import java.util.List; + +public class Endpoints { + private final ConfigService configService; + + @Inject + public Endpoints(ConfigService configService) { + this.configService = configService; + } + + private HttpRequest.Builder http(String url) { + return HttpRequest.newBuilder() + .uri(URI.create(url)) + .header("Content-Type", "application/json"); + } + + public String baseUrl() { + return this.configService.getConfig().getServerUrl(); + } + + public HttpRequest.Builder fetchAllRecipes(List locales) { + String url = this.baseUrl() + "/recipes" + "?locales=" + String.join(",", locales); + + return this.http(url).GET(); + } + + public HttpRequest.Builder fetchRecipe(long recipeId) { + String url = this.baseUrl() + "/recipe/" + recipeId; + + return this.http(url).GET(); + } + + public HttpRequest.Builder createNewRecipe(HttpRequest.BodyPublisher body) { + String url = this.baseUrl() + "/recipe/new"; + + return this.http(url).PUT(body); + } + + public HttpRequest.Builder updateRecipe(long recipeId, HttpRequest.BodyPublisher body) { + String url = this.baseUrl() + "/recipe/" + recipeId; + + return this.http(url).POST(body); + } + + public HttpRequest.Builder deleteRecipe(long recipeId) { + String url = this.baseUrl() + "/recipe/" + recipeId; + + return this.http(url).DELETE(); + } + + public HttpRequest.Builder fetchIngredientUsage(long ingredientId) { + String url = this.baseUrl() + "/ingredients/" + ingredientId + "/usage"; + + return this.http(url).GET(); + } + + public HttpRequest.Builder deleteIngredient(long ingredientId) { + String url = this.baseUrl() + "/ingredients/" + ingredientId; + + return this.http(url).DELETE(); + } + + public HttpRequest.Builder getIngredients() { + String url = this.baseUrl() + "/ingredients"; + + return this.http(url).GET(); + } + + public HttpRequest.Builder createIngredient(HttpRequest.BodyPublisher body) { + String url = this.baseUrl() + "/ingredients"; + + return this.http(url).POST(body); + } + + public HttpRequest.Builder updateIngredient(long ingredientId, HttpRequest.BodyPublisher body) { + String url = this.baseUrl() + "/ingredients/" + ingredientId; + + return this.http(url).method("PATCH", body); + } +} diff --git a/client/src/main/java/client/utils/ServerUtils.java b/client/src/main/java/client/utils/server/ServerUtils.java similarity index 78% rename from client/src/main/java/client/utils/ServerUtils.java rename to client/src/main/java/client/utils/server/ServerUtils.java index 3f8bc91..1fe5ae0 100644 --- a/client/src/main/java/client/utils/ServerUtils.java +++ b/client/src/main/java/client/utils/server/ServerUtils.java @@ -1,4 +1,4 @@ -package client.utils; +package client.utils.server; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; @@ -13,7 +13,6 @@ import org.glassfish.jersey.client.ClientConfig; import java.io.IOException; import java.net.ConnectException; -import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; @@ -25,15 +24,17 @@ import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; public class ServerUtils { - private static final String SERVER = "http://localhost:8080/api"; private Logger logger = Logger.getLogger(ServerUtils.class.getName()); private final HttpClient client; private final ObjectMapper objectMapper = new ObjectMapper(); private final int statusOK = 200; + private final Endpoints endpoints; + @Inject - public ServerUtils(HttpClient client) { + public ServerUtils(HttpClient client, Endpoints endpoints) { this.client = client; + this.endpoints = endpoints; } /** @@ -41,25 +42,16 @@ public class ServerUtils { * @return a JSON string with all the recipes */ public List getRecipes(List locales) throws IOException, InterruptedException { + HttpRequest request = this.endpoints.fetchAllRecipes(locales).build(); - String uri = - SERVER + - "/recipes" + - "?locales=" + - String.join(",", locales); - - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(uri)) - .GET() - .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); - if(response.statusCode() != statusOK){ + if (response.statusCode() != statusOK) { throw new IOException("No recipe to get. Server responds with " + response.body()); } - List list = objectMapper.readValue(response.body(), new TypeReference>() { - }); + List list = objectMapper.readValue(response.body(), new TypeReference>() {}); + logger.info("Received response from server: " + list); return list; // JSON string-> List (Jackson) } @@ -75,10 +67,8 @@ public class ServerUtils { * @return a singe recipe with the given id */ public Recipe findId(long id) throws IOException, InterruptedException { - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(SERVER +"/recipe/" + id)) - .GET() - .build(); + HttpRequest request = this.endpoints.fetchRecipe(id).build(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); if(response.statusCode() != statusOK){ @@ -111,11 +101,9 @@ public class ServerUtils { String json = objectMapper.writeValueAsString(newRecipe); //Recipe to backend - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(SERVER + "/recipe/new")) - .header("Content-Type", "application/json") - .PUT(HttpRequest.BodyPublishers.ofString(json)) - .build(); + HttpRequest request = + this.endpoints.createNewRecipe(HttpRequest.BodyPublishers.ofString(json)).build(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); if(response.statusCode() != statusOK){ @@ -129,10 +117,8 @@ public class ServerUtils { * @param id the recipe that get deleted */ public void deleteRecipe(long id) throws IOException, InterruptedException { - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(SERVER + "/recipe/" + id)) - .DELETE() - .build(); + HttpRequest request = this.endpoints.deleteRecipe(id).build(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); if(response.statusCode() != statusOK){ @@ -147,10 +133,8 @@ public class ServerUtils { */ public Recipe cloneRecipe(long id) throws IOException, InterruptedException { //Get the recipe - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(SERVER + "/recipe/" + id)) - .GET() - .build(); + HttpRequest request = this.endpoints.fetchRecipe(id).build(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); //200 is the status code for success, other codes can mean there is no recipe to clone @@ -165,7 +149,7 @@ public class ServerUtils { public boolean isServerAvailable() { try { ClientBuilder.newClient(new ClientConfig()) // - .target(SERVER) // + .target(this.endpoints.baseUrl()) // .request(APPLICATION_JSON) // .get(); } catch (ProcessingException e) { @@ -194,11 +178,9 @@ public class ServerUtils { public void updateRecipe(Recipe recipe) throws IOException, InterruptedException { String json = objectMapper.writeValueAsString(recipe); - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(SERVER + "/recipe/" + recipe.getId())) - .header("Content-Type", "application/json") - .POST(HttpRequest.BodyPublishers.ofString((json))) // Needs to be changed to PUT() when api changed + HttpRequest request = this.endpoints.updateRecipe(recipe.getId(), HttpRequest.BodyPublishers.ofString(json)) .build(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); if(response.statusCode() != statusOK){ @@ -224,10 +206,7 @@ public class ServerUtils { * @throws InterruptedException if operation is interrupted. */ public long getIngredientUsage(long ingredientId) throws IOException, InterruptedException { - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(SERVER + "/ingredients/" + ingredientId + "/usage")) - .GET() - .build(); + HttpRequest request = this.endpoints.fetchIngredientUsage(ingredientId).build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); if (response.statusCode() != statusOK) { @@ -245,10 +224,7 @@ public class ServerUtils { public void deleteIngredient(long ingredientId) throws IOException, InterruptedException { // Send delete request to remove the ingredient - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(SERVER + "/ingredients/" + ingredientId)) - .DELETE() - .build(); + HttpRequest request = this.endpoints.deleteIngredient(ingredientId).build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); @@ -263,10 +239,7 @@ public class ServerUtils { //retrieves the list of ingredients saved to backend public List getIngredients() throws IOException, InterruptedException { - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(SERVER + "/ingredients")) - .GET() - .build(); + HttpRequest request = this.endpoints.getIngredients().build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); if (response.statusCode() != statusOK) { @@ -282,10 +255,7 @@ public class ServerUtils { Ingredient ingredient = new Ingredient(name, 0.0, 0.0, 0.0); String json = objectMapper.writeValueAsString(ingredient); - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(SERVER + "/ingredients")) - .header("Content-Type", "application/json") - .POST(HttpRequest.BodyPublishers.ofString(json)) + HttpRequest request = this.endpoints.createIngredient(HttpRequest.BodyPublishers.ofString(json)) .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); @@ -298,21 +268,15 @@ public class ServerUtils { public Ingredient updateIngredient(Ingredient newIngredient) throws IOException, InterruptedException { logger.info("PATCH ingredient with id: " + newIngredient.getId()); - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(SERVER + "/ingredients/" + newIngredient.getId())) - .header("Content-Type", "application/json") - .method( - "PATCH", - HttpRequest.BodyPublishers.ofString(objectMapper.writeValueAsString(newIngredient))) - .build(); + HttpRequest request = this.endpoints.updateIngredient( + newIngredient.getId(), + HttpRequest.BodyPublishers.ofString(objectMapper.writeValueAsString(newIngredient)) + ).build(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); if (response.statusCode() != statusOK) { throw new IOException("Failed to update ingredient with id: " + newIngredient.getId() + " body: " + response.body()); } return objectMapper.readValue(response.body(), Ingredient.class); } - - - - } diff --git a/client/src/test/java/client/ServerUtilsMockTest.java b/client/src/test/java/client/ServerUtilsMockTest.java index f7cc958..55ff5c9 100644 --- a/client/src/test/java/client/ServerUtilsMockTest.java +++ b/client/src/test/java/client/ServerUtilsMockTest.java @@ -1,6 +1,8 @@ package client; -import client.utils.ServerUtils; +import client.utils.ConfigService; +import client.utils.server.Endpoints; +import client.utils.server.ServerUtils; import com.fasterxml.jackson.databind.ObjectMapper; import com.github.tomakehurst.wiremock.junit5.WireMockTest; import commons.FormalIngredient; @@ -10,9 +12,11 @@ import commons.RecipeIngredient; import commons.VagueIngredient; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import java.io.IOException; import java.net.http.HttpClient; +import java.nio.file.Path; import java.util.ArrayList; import java.util.List; @@ -38,10 +42,18 @@ class ServerUtilsMockTest { static final List testPrepSteps = List.of("1. do smth", "2. do smth else"); + @TempDir + Path tempDir; + @BeforeEach void setup() { + var configPath = tempDir.resolve("configServiceTest.json"); + var configService = new ConfigService(configPath); + + var endpoints = new Endpoints(configService); + objectMapper = new ObjectMapper(); - serverUtils = new ServerUtils(HttpClient.newHttpClient()); + serverUtils = new ServerUtils(HttpClient.newHttpClient(), endpoints); } /** diff --git a/client/src/test/java/client/ServerUtilsTest.java b/client/src/test/java/client/ServerUtilsTest.java index 9583d8c..7b6b419 100644 --- a/client/src/test/java/client/ServerUtilsTest.java +++ b/client/src/test/java/client/ServerUtilsTest.java @@ -1,6 +1,8 @@ package client; -import client.utils.ServerUtils; +import client.utils.ConfigService; +import client.utils.server.Endpoints; +import client.utils.server.ServerUtils; import commons.Ingredient; import commons.Recipe; import commons.RecipeIngredient; @@ -9,9 +11,11 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import java.io.IOException; import java.net.http.HttpClient; +import java.nio.file.Path; import java.util.List; import static org.junit.jupiter.api.Assertions.*; @@ -31,10 +35,17 @@ class ServerUtilsTest { ); final int fakeId = -1; // If suppose ID's are only positive + @TempDir + Path tempDir; + @BeforeEach void setup() throws IOException, InterruptedException { - // FIXME: Prefer Guice-provided instance via a unit test Module. - dv = new ServerUtils(HttpClient.newHttpClient()); + var configPath = tempDir.resolve("configServiceTest.json"); + var configService = new ConfigService(configPath); + configService.getConfig().setServerUrl("http://localhost:8080"); + + var endpoints = new Endpoints(configService); + dv = new ServerUtils(HttpClient.newHttpClient(), endpoints); Assumptions.assumeTrue(dv.isServerAvailable(), "Server not available");