Merge branch 'basicServerUtils' into 'main'
Basic Server Utilities See merge request cse1105/2025-2026/teams/csep-team-76!9
This commit is contained in:
commit
fb9b413351
6 changed files with 317 additions and 57 deletions
|
|
@ -25,7 +25,7 @@ import com.google.inject.Injector;
|
|||
import client.scenes.AddQuoteCtrl;
|
||||
import client.scenes.MainCtrl;
|
||||
import client.scenes.QuoteOverviewCtrl;
|
||||
import client.utils.ServerUtils;
|
||||
import client.utils.ServerUtilsExample;
|
||||
import javafx.application.Application;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ public class Main extends Application {
|
|||
@Override
|
||||
public void start(Stage primaryStage) throws Exception {
|
||||
|
||||
var serverUtils = INJECTOR.getInstance(ServerUtils.class);
|
||||
var serverUtils = INJECTOR.getInstance(ServerUtilsExample.class);
|
||||
if (!serverUtils.isServerAvailable()) {
|
||||
var msg = "Server needs to be started before the client, but it does not seem to be available. Shutting down.";
|
||||
System.err.println(msg);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ package client.scenes;
|
|||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import client.utils.ServerUtils;
|
||||
import client.utils.ServerUtilsExample;
|
||||
import commons.Person;
|
||||
import commons.Quote;
|
||||
import jakarta.ws.rs.WebApplicationException;
|
||||
|
|
@ -29,7 +29,7 @@ import javafx.stage.Modality;
|
|||
|
||||
public class AddQuoteCtrl {
|
||||
|
||||
private final ServerUtils server;
|
||||
private final ServerUtilsExample server;
|
||||
private final MainCtrl mainCtrl;
|
||||
|
||||
@FXML
|
||||
|
|
@ -42,7 +42,7 @@ public class AddQuoteCtrl {
|
|||
private TextField quote;
|
||||
|
||||
@Inject
|
||||
public AddQuoteCtrl(ServerUtils server, MainCtrl mainCtrl) {
|
||||
public AddQuoteCtrl(ServerUtilsExample server, MainCtrl mainCtrl) {
|
||||
this.mainCtrl = mainCtrl;
|
||||
this.server = server;
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import java.util.ResourceBundle;
|
|||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import client.utils.ServerUtils;
|
||||
import client.utils.ServerUtilsExample;
|
||||
import commons.Quote;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
|
|
@ -32,7 +32,7 @@ import javafx.scene.control.TableView;
|
|||
|
||||
public class QuoteOverviewCtrl implements Initializable {
|
||||
|
||||
private final ServerUtils server;
|
||||
private final ServerUtilsExample server;
|
||||
private final MainCtrl mainCtrl;
|
||||
|
||||
private ObservableList<Quote> data;
|
||||
|
|
@ -47,7 +47,7 @@ public class QuoteOverviewCtrl implements Initializable {
|
|||
private TableColumn<Quote, String> colQuote;
|
||||
|
||||
@Inject
|
||||
public QuoteOverviewCtrl(ServerUtils server, MainCtrl mainCtrl) {
|
||||
public QuoteOverviewCtrl(ServerUtilsExample server, MainCtrl mainCtrl) {
|
||||
this.server = server;
|
||||
this.mainCtrl = mainCtrl;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,64 +1,146 @@
|
|||
/*
|
||||
* Copyright 2021 Delft University of Technology
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package client.utils;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import commons.Recipe;
|
||||
import jakarta.ws.rs.ProcessingException;
|
||||
import jakarta.ws.rs.client.ClientBuilder;
|
||||
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;
|
||||
import java.util.List;
|
||||
|
||||
import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.ConnectException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
|
||||
import org.glassfish.jersey.client.ClientConfig;
|
||||
|
||||
import commons.Quote;
|
||||
import jakarta.ws.rs.ProcessingException;
|
||||
import jakarta.ws.rs.client.ClientBuilder;
|
||||
import jakarta.ws.rs.client.Entity;
|
||||
import jakarta.ws.rs.core.GenericType;
|
||||
|
||||
public class ServerUtils {
|
||||
private static final String SERVER = "http://localhost:8080/api";
|
||||
private final HttpClient client;
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
private final int statusOK = 200;
|
||||
|
||||
private static final String SERVER = "http://localhost:8080/";
|
||||
public ServerUtils() {
|
||||
client = HttpClient.newHttpClient();
|
||||
}
|
||||
|
||||
public void getQuotesTheHardWay() throws IOException, URISyntaxException {
|
||||
var url = new URI("http://localhost:8080/api/quotes").toURL();
|
||||
var is = url.openConnection().getInputStream();
|
||||
var br = new BufferedReader(new InputStreamReader(is));
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
System.out.println(line);
|
||||
/**
|
||||
* Gets all the recipes from the backend
|
||||
* @return a JSON string with all the recipes
|
||||
*/
|
||||
public List<Recipe> getRecipes() throws IOException, InterruptedException {
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(SERVER + "/recipes"))
|
||||
.GET()
|
||||
.build();
|
||||
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
if(response.statusCode() != statusOK){
|
||||
throw new IOException("No recipe to get. Server responds with " + response.body());
|
||||
}
|
||||
|
||||
|
||||
return objectMapper.readValue(response.body(), new TypeReference<List<Recipe>>() {
|
||||
});// JSON string-> List<Recipe> (Jackson)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a single recipe based on its id
|
||||
* @param id every recipe has it's unique id
|
||||
* @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();
|
||||
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
if(response.statusCode() != statusOK){
|
||||
throw new IOException("failed finding recipe with id: "+ id + " body: " + response.body());
|
||||
}
|
||||
|
||||
return objectMapper.readValue(response.body(),Recipe.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a recipe to the backend
|
||||
* @param newRecipe the recipe to be added
|
||||
* @return a recipe
|
||||
*/
|
||||
public Recipe addRecipe(Recipe newRecipe) throws IOException, InterruptedException {
|
||||
//Make sure the name of the newRecipe is unique
|
||||
List<Recipe> allRecipes = getRecipes();
|
||||
|
||||
|
||||
int version = 1;
|
||||
String originalName = newRecipe.getName();
|
||||
while (allRecipes.stream().anyMatch(r -> r.getName().equals(newRecipe.getName()))) {
|
||||
String newName = originalName + "(" + version++ + ")";
|
||||
newRecipe.setName(newName);
|
||||
}
|
||||
|
||||
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();
|
||||
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
if(response.statusCode() != statusOK){
|
||||
throw new IOException("Failed to add Recipe: " + newRecipe.toDetailedString() + "body: " + response.body());
|
||||
}
|
||||
|
||||
return objectMapper.readValue(response.body(),Recipe.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a recipe
|
||||
* @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();
|
||||
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
if(response.statusCode() != statusOK){
|
||||
throw new IOException("Failed removing recipe with id: " + id + "body: " + response.body());
|
||||
}
|
||||
}
|
||||
|
||||
public List<Quote> getQuotes() {
|
||||
return ClientBuilder.newClient(new ClientConfig()) //
|
||||
.target(SERVER).path("api/quotes") //
|
||||
.request(APPLICATION_JSON) //
|
||||
.get(new GenericType<List<Quote>>() {});
|
||||
}
|
||||
/**
|
||||
* Clones a recipe
|
||||
* @param id the id of the recipe to be cloned
|
||||
* @return a duplicated recipe of the given recipe
|
||||
*/
|
||||
public Recipe cloneRecipe(long id) throws IOException, InterruptedException {
|
||||
//Get the recipe
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(SERVER + "/recipe/" + id))
|
||||
.GET()
|
||||
.build();
|
||||
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
public Quote addQuote(Quote quote) {
|
||||
return ClientBuilder.newClient(new ClientConfig()) //
|
||||
.target(SERVER).path("api/quotes") //
|
||||
.request(APPLICATION_JSON) //
|
||||
.post(Entity.entity(quote, APPLICATION_JSON), Quote.class);
|
||||
//200 is the status code for success, other codes can mean there is no recipe to clone
|
||||
if(response.statusCode() != statusOK){
|
||||
throw new IOException("Failed to get recipe to clone with id: " + id + "body: " + response.body());
|
||||
}
|
||||
// recipe exists so you can make a "new" recipe aka the clone
|
||||
Recipe recipe = objectMapper.readValue(response.body(), Recipe.class);
|
||||
|
||||
recipe.setId(null); // otherwise the id is the same as the original, and that's wrong
|
||||
|
||||
return addRecipe(recipe);
|
||||
}
|
||||
|
||||
public boolean isServerAvailable() {
|
||||
|
|
|
|||
72
client/src/main/java/client/utils/ServerUtilsExample.java
Normal file
72
client/src/main/java/client/utils/ServerUtilsExample.java
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright 2021 Delft University of Technology
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package client.utils;
|
||||
|
||||
import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;
|
||||
|
||||
import java.net.ConnectException;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.ws.rs.core.GenericType;
|
||||
import org.glassfish.jersey.client.ClientConfig;
|
||||
|
||||
import commons.Quote;
|
||||
import jakarta.ws.rs.ProcessingException;
|
||||
import jakarta.ws.rs.client.ClientBuilder;
|
||||
import jakarta.ws.rs.client.Entity;
|
||||
|
||||
public class ServerUtilsExample {
|
||||
|
||||
private static final String SERVER = "http://localhost:8080/";
|
||||
|
||||
// public void getQuotesTheHardWay() throws IOException, URISyntaxException {
|
||||
// var url = new URI("http://localhost:8080/api/quotes").toURL();
|
||||
// var is = url.openConnection().getInputStream();
|
||||
// var br = new BufferedReader(new InputStreamReader(is));
|
||||
// String line;
|
||||
// while ((line = br.readLine()) != null) {
|
||||
// System.out.println(line);
|
||||
// }
|
||||
// }
|
||||
|
||||
public List<Quote> getQuotes() {
|
||||
return ClientBuilder.newClient(new ClientConfig()) //
|
||||
.target(SERVER).path("api/quotes") //
|
||||
.request(APPLICATION_JSON) //
|
||||
.get(new GenericType<List<Quote>>() {});
|
||||
}
|
||||
|
||||
public Quote addQuote(Quote quote) {
|
||||
return ClientBuilder.newClient(new ClientConfig()) //
|
||||
.target(SERVER).path("api/quotes") //
|
||||
.request(APPLICATION_JSON) //
|
||||
.post(Entity.entity(quote, APPLICATION_JSON), Quote.class);
|
||||
}
|
||||
|
||||
public boolean isServerAvailable() {
|
||||
try {
|
||||
ClientBuilder.newClient(new ClientConfig()) //
|
||||
.target(SERVER) //
|
||||
.request(APPLICATION_JSON) //
|
||||
.get();
|
||||
} catch (ProcessingException e) {
|
||||
if (e.getCause() instanceof ConnectException) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue