finish 4th practical

This commit is contained in:
2025-12-21 18:14:27 +02:00
parent d203544a6f
commit 4f1fa86833
22 changed files with 265 additions and 102 deletions

View File

@@ -0,0 +1,24 @@
plugins {
id("java")
alias(libs.plugins.spring.boot)
}
group = "ua.com.dxrkness"
version = "1.0-SNAPSHOT"
repositories {
mavenCentral()
}
dependencies {
// spring
implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES))
implementation(platform(libs.spring.cloud.dependencies))
implementation("org.springframework.cloud:spring-cloud-starter-gateway-server-webflux")
implementation("org.springframework.cloud:spring-cloud-starter-netflix-eureka-client")
implementation("org.springframework.cloud:spring-cloud-starter-loadbalancer")
}
tasks.test {
useJUnitPlatform()
}

View File

@@ -0,0 +1,11 @@
package ua.com.dxrkness.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ApiGatewayApplication {
static void main(String[] args) {
SpringApplication.run(ApiGatewayApplication.class, args);
}
}

View File

@@ -0,0 +1,18 @@
server:
port: 8079
spring:
cloud:
gateway:
server:
webflux:
discovery:
locator:
enabled: true
lower-case-service-id: true
application:
name: api-gateway
eureka:
client:
service-url:
defaultZone: http://localhost:8070/eureka
register-with-eureka: false

View File

@@ -0,0 +1,22 @@
plugins {
id("java")
alias(libs.plugins.spring.boot)
}
group = "ua.com.dxrkness"
version = "1.0-SNAPSHOT"
repositories {
mavenCentral()
}
dependencies {
// spring
implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES))
implementation(platform(libs.spring.cloud.dependencies))
implementation("org.springframework.cloud:spring-cloud-starter-netflix-eureka-server")
}
tasks.test {
useJUnitPlatform()
}

View File

@@ -0,0 +1,13 @@
package ua.com.dxrkness;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}

View File

@@ -0,0 +1,11 @@
server:
port: 8070
spring:
application:
name: eureka-server
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false
fetch-registry: false

View File

@@ -13,6 +13,8 @@ repositories {
dependencies {
// spring
implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES))
implementation(platform(libs.spring.cloud.dependencies))
implementation("org.springframework.cloud:spring-cloud-starter-netflix-eureka-client")
implementation(libs.spring.boot.starter.web)
implementation(libs.spring.boot.starter.web.test)

View File

@@ -3,3 +3,7 @@ spring:
name: freight-service
server:
port: 8080
eureka:
client:
service-url:
defaultZone: http://localhost:8070/eureka

View File

@@ -5,6 +5,7 @@ jspecify = "1.0.0"
springdoc = "3.0.0"
apache-http-client = "4.5.14"
json-schema-validator = "3.0.0"
spring-cloud = "2025.1.0"
[plugins]
spring-boot = { id = "org.springframework.boot", version.ref = "spring-boot-plugin" }
@@ -15,6 +16,7 @@ spring-boot-starter-web = { group = "org.springframework.boot", name = "spring-b
spring-boot-starter-web-test = { group = "org.springframework.boot", name = "spring-boot-starter-webmvc-test" }
spring-boot-starter-hateoas = { group = "org.springframework.boot", name = "spring-boot-starter-hateoas" }
spring-boot-devtools = { group = "org.springframework.boot", name = "spring-boot-devtools" }
spring-cloud-dependencies = { group = "org.springframework.cloud", name = "spring-cloud-dependencies", version.ref = "spring-cloud" }
# http client
apache-http-client = { group = "org.apache.httpcomponents", name = "httpclient", version.ref = "apache-http-client" }
@@ -25,6 +27,7 @@ springdoc-openapi-starter-webmvc-ui = { group = "org.springdoc", name = "springd
# jackson
jackson-dataformat-xml = { group = "tools.jackson.dataformat", name = "jackson-dataformat-xml" }
oldjackson-databind = { group = "com.fasterxml.jackson.core", name = "jackson-databind" }
oldjackson-dataformat-xml = { group = "com.fasterxml.jackson.dataformat", name = "jackson-dataformat-xml" }
# testing
junit-bom = { group = "org.junit", name = "junit-bom", version.ref = "junit" }

View File

@@ -16,5 +16,6 @@ dependencies {
// jackson
api(libs.jackson.dataformat.xml)
api(libs.oldjackson.dataformat.xml)
implementation(libs.oldjackson.databind)
}

View File

@@ -51,22 +51,22 @@ function publish_correct
}'
printf '\n\n'
curl -X POST http://localhost:8081/vehicles \
curl -X POST http://localhost:8079/vehicle-service/vehicles \
-H "Content-Type: application/json" \
-d $vehicle
printf '\n\n'
curl -X POST http://localhost:8080/freights \
curl -X POST http://localhost:8079/freight-service/freights \
-H "Content-Type: application/json" \
-d $freight1
printf '\n\n'
curl -X POST http://localhost:8080/freights \
curl -X POST http://localhost:8079/freight-service/freights \
-H "Content-Type: application/json" \
-d $freight2
printf '\n\n'
curl -X POST http://localhost:8082/routes \
curl -X POST http://localhost:8079/route-service/routes \
-H "Content-Type: application/json" \
-d $route
end
@@ -86,7 +86,8 @@ function add_invalid_route
"status": "PLANNED"
}'
curl -X POST http://localhost:8082/routes \
# 404 status is expected, since vehicle svc propagates it's error code to route svc
curl -X POST http://localhost:8082/routes \
-H "Content-Type: application/json" \
-d $route
end

View File

@@ -13,6 +13,9 @@ repositories {
dependencies {
// spring
implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES))
implementation(platform(libs.spring.cloud.dependencies))
implementation("org.springframework.cloud:spring-cloud-starter-netflix-eureka-client")
implementation("org.springframework.cloud:spring-cloud-starter-loadbalancer")
implementation(libs.spring.boot.starter.web)
implementation(libs.spring.boot.starter.web.test)

View File

@@ -2,10 +2,10 @@ package ua.com.dxrkness.client;
import com.networknt.schema.InputFormat;
import com.networknt.schema.Schema;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.ErrorResponseException;
import org.springframework.web.client.RestClient;
import org.springframework.web.server.ResponseStatusException;
import tools.jackson.core.type.TypeReference;
@@ -20,8 +20,8 @@ public class FreightClient {
private final Schema freightSchema;
private final JsonMapper mapper = JsonMapper.shared();
public FreightClient(RestClient freightRestClient, Schema freightSchema) {
this.freightRestClient = freightRestClient;
public FreightClient(@Qualifier("freightRestClient") RestClient.Builder freightRestClient, Schema freightSchema) {
this.freightRestClient = freightRestClient.build();
this.freightSchema = freightSchema;
}

View File

@@ -3,6 +3,7 @@ package ua.com.dxrkness.client;
import com.networknt.schema.Error;
import com.networknt.schema.InputFormat;
import com.networknt.schema.Schema;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
@@ -20,8 +21,8 @@ public class VehicleClient {
private final Schema vehicleSchema;
private final JsonMapper mapper = JsonMapper.shared();
public VehicleClient(RestClient vehicleRestClient, Schema vehicleSchema) {
this.vehicleRestClient = vehicleRestClient;
public VehicleClient(@Qualifier("vehicleRestClient") RestClient.Builder vehicleRestClient, Schema vehicleSchema) {
this.vehicleRestClient = vehicleRestClient.build();
this.vehicleSchema = vehicleSchema;
}

View File

@@ -1,18 +1,28 @@
package ua.com.dxrkness.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.web.client.RestClient;
@Configuration
public class ClientConfiguration {
@Bean
public RestClient vehicleRestClient() {
return RestClient.create("http://localhost:8081/vehicles");
@LoadBalanced
public RestClient.Builder vehicleRestClient() {
return RestClient.builder().baseUrl("http://vehicle-service/vehicles");
}
@Bean
public RestClient freightRestClient() {
return RestClient.create("http://localhost:8080/freights");
@LoadBalanced
public RestClient.Builder freightRestClient() {
return RestClient.builder().baseUrl("http://freight-service/freights");
}
@Bean
@Primary
public RestClient.Builder defaultRestClient() {
return RestClient.builder();
}
}

View File

@@ -52,7 +52,7 @@ public final class RouteService {
route.distanceKm(),
route.estimatedDurationHours(),
route.status());
repo.add(route);
repo.add(newRoute);
return newRoute;
}

View File

@@ -1,5 +1,13 @@
spring:
application:
name: route-service
cloud:
loadbalancer:
cache:
enabled: false
server:
port: 8082
port: 8082
eureka:
client:
service-url:
defaultZone: http://localhost:8070/eureka

View File

@@ -1,4 +1,4 @@
rootProject.name = "itroi"
enableFeaturePreview("STABLE_CONFIGURATION_CACHE")
include("models", "vehicle-service", "route-service", "freight-service", "shared")
include("models", "vehicle-service", "route-service", "freight-service", "shared", "api-gateway", "eureka-server")

View File

@@ -7,7 +7,7 @@ import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.json.JsonMapper;
import tools.jackson.dataformat.xml.XmlMapper;
import ua.com.dxrkness.model.Freight;
import ua.com.dxrkness.model.Route;
@@ -16,9 +16,9 @@ import ua.com.dxrkness.model.Vehicle;
import java.util.List;
public class ApplicationClient {
private static final String BASE_URL = "http://localhost:8080";
private static final ObjectMapper jsonMapper = new ObjectMapper();
private static final XmlMapper xmlMapper = new XmlMapper();
private static final String BASE_URL = "http://localhost:8079";
private static final JsonMapper jsonMapper = JsonMapper.builder().build();
private static final XmlMapper xmlMapper = XmlMapper.builder().build();
static void main() {
try (CloseableHttpClient client = HttpClients.createDefault()) {
@@ -31,144 +31,144 @@ public class ApplicationClient {
testInterServiceValidation(client);
} catch (Exception e) {
System.out.println("error: " + e.getMessage());
IO.println("error: " + e.getMessage());
e.printStackTrace();
}
}
private static void testVehicles(CloseableHttpClient client) throws Exception {
System.out.println("--- VEHICLES ---");
private static void testVehicles(CloseableHttpClient client) {
IO.println("--- VEHICLES ---");
execute(client, new HttpGet(BASE_URL + "/vehicles"), "GET all vehicles");
execute(client, new HttpGet(BASE_URL + "/vehicle-service/vehicles"), "GET all vehicles");
Vehicle newVehicle = new Vehicle(0, "Mercedes", "Actros", "AA1234BB", 2023, 18000, Vehicle.Status.AVAILABLE);
String vehicleXml = xmlMapper.writeValueAsString(newVehicle);
HttpPost post = new HttpPost(BASE_URL + "/vehicles");
HttpPost post = new HttpPost(BASE_URL + "/vehicle-service/vehicles");
post.setEntity(new StringEntity(vehicleXml, "UTF-8"));
post.setHeader("Content-Type", "application/xml");
post.setHeader("Accept", "application/xml");
String createdVehicle = execute(client, post, "POST new vehicle");
var get = new HttpGet(BASE_URL + "/vehicles/0");
var get = new HttpGet(BASE_URL + "/vehicle-service/vehicles/1");
get.setHeader("Content-Type", "application/xml");
execute(client, get, "GET vehicle by ID=0");
execute(client, new HttpGet(BASE_URL + "/vehicles/999"), "GET vehicle by ID=999 (not found)");
execute(client, get, "GET vehicle by ID=1");
execute(client, new HttpGet(BASE_URL + "/vehicle-service/vehicles/999"), "GET vehicle by ID=999 (not found)");
Vehicle updateVehicle = new Vehicle(1, "Volvo", "FH16", "BB5678CC", 2024, 20000, Vehicle.Status.MAINTENANCE);
var vehiclePut = createHttpRequest(updateVehicle, "/vehicles/0", HttpMethod.PUT);
execute(client, vehiclePut, "PUT update vehicle ID=0");
var vehiclePut = createHttpRequest(updateVehicle, "/vehicle-service/vehicles/1", HttpMethod.PUT);
execute(client, vehiclePut, "PUT update vehicle ID=1");
Vehicle patchVehicle = new Vehicle(1, "Volvo", "FH16", "BB5678CC", 2024, 20000, Vehicle.Status.IN_TRANSIT);
var vehiclePatch = createHttpRequest(patchVehicle, "/vehicles/0", HttpMethod.PATCH);
execute(client, vehiclePatch, "PATCH update vehicle ID=0");
var vehiclePatch = createHttpRequest(patchVehicle, "/vehicle-service/vehicles/1", HttpMethod.PATCH);
execute(client, vehiclePatch, "PATCH update vehicle ID=1");
execute(client, new HttpDelete(BASE_URL + "/vehicles/999"), "DELETE vehicle ID=999 (not found)");
execute(client, new HttpDelete(BASE_URL + "/vehicle-service/vehicles/999"), "DELETE vehicle ID=999 (not found)");
System.out.println();
IO.println();
}
private static void testFreights(CloseableHttpClient client) throws Exception {
System.out.println("--- FREIGHTS ---");
private static void testFreights(CloseableHttpClient client) {
IO.println("--- FREIGHTS ---");
execute(client, new HttpGet(BASE_URL + "/freights"), "GET all freights");
execute(client, new HttpGet(BASE_URL + "/freight-service" + "/freights"), "GET all freights");
Freight.Dimensions dims = new Freight.Dimensions(120, 100, 200);
Freight newFreight = new Freight(0, "Electronics", "Laptops and monitors", 500, dims, Freight.Status.PENDING);
var freightPost = createHttpRequest(newFreight, "/freights", HttpMethod.POST);
Freight newFreight = new Freight(1, "Electronics", "Laptops and monitors", 500, dims, Freight.Status.PENDING);
var freightPost = createHttpRequest(newFreight, "/freight-service/freights", HttpMethod.POST);
execute(client, freightPost, "POST new freight");
execute(client, new HttpGet(BASE_URL + "/freights/0"), "GET freight by ID=0");
execute(client, new HttpGet(BASE_URL + "/freights/999"), "GET freight by ID=999 (not found)");
execute(client, new HttpGet(BASE_URL + "/freight-service/freights/1"), "GET freight by ID=1");
execute(client, new HttpGet(BASE_URL + "/freight-service/freights/999"), "GET freight by ID=999 (not found)");
Freight updateFreight = new Freight(1, "Furniture", "Office desks", 800, dims, Freight.Status.IN_TRANSIT);
var freightPut = createHttpRequest(updateFreight, "/freights/0", HttpMethod.PUT);
execute(client, freightPut, "PUT update freight ID=0");
var freightPut = createHttpRequest(updateFreight, "/freight-service/freights/1", HttpMethod.PUT);
execute(client, freightPut, "PUT update freight ID=1");
Freight patchFreight = new Freight(1, "Furniture", "Office desks", 800, dims, Freight.Status.DELIVERED);
var freightPatch = createHttpRequest(patchFreight, "/freights/0", HttpMethod.PATCH);
execute(client, freightPatch, "PATCH update freight ID=0");
var freightPatch = createHttpRequest(patchFreight, "/freight-service/freights/1", HttpMethod.PATCH);
execute(client, freightPatch, "PATCH update freight ID=1");
execute(client, new HttpDelete(BASE_URL + "/freights/999"), "DELETE freight ID=999 (not found)");
execute(client, new HttpDelete(BASE_URL + "/freight-service/freights/999"), "DELETE freight ID=999 (not found)");
System.out.println();
IO.println();
}
private static void testRoutes(CloseableHttpClient client) throws Exception {
System.out.println("--- ROUTES ---");
private static void testRoutes(CloseableHttpClient client) {
IO.println("--- ROUTES ---");
Route newRoute = new Route(0, 0, List.of(0L), "Kyiv", "Lviv", 540.0, 8.5, Route.Status.PLANNED);
var routePost = createHttpRequest(newRoute, "/routes", HttpMethod.POST);
Route newRoute = new Route(1, 1, List.of(1L), "Kyiv", "Lviv", 540.0, 8.5, Route.Status.PLANNED);
var routePost = createHttpRequest(newRoute, "/route-service/routes", HttpMethod.POST);
execute(client, routePost, "POST new route");
execute(client, new HttpGet(BASE_URL + "/routes"), "GET all routes");
execute(client, new HttpGet(BASE_URL + "/route-service" + "/routes"), "GET all routes");
execute(client, new HttpGet(BASE_URL + "/routes/0"), "GET route by ID=0");
execute(client, new HttpGet(BASE_URL + "/routes/999"), "GET route by ID=999 (not found)");
execute(client, new HttpGet(BASE_URL + "/route-service" + "/routes/1"), "GET route by ID=1");
execute(client, new HttpGet(BASE_URL + "/route-service" + "/routes/999"), "GET route by ID=999 (not found)");
Route updateRoute = new Route(0, 0, List.of(0L), "Kyiv", "Odesa", 480.0, 7.0, Route.Status.IN_PROGRESS);
var routePut = createHttpRequest(updateRoute, "/routes/0", HttpMethod.PUT);
execute(client, routePut, "PUT update route ID=0");
Route updateRoute = new Route(1, 1, List.of(1L), "Kyiv", "Odesa", 480.0, 7.0, Route.Status.IN_PROGRESS);
var routePut = createHttpRequest(updateRoute, "/route-service/routes/1", HttpMethod.PUT);
execute(client, routePut, "PUT update route ID=1");
Route patchRoute = new Route(0, 0, List.of(0L), "Kyiv", "Odesa", 480.0, 7.0, Route.Status.COMPLETED);
var routePatch = createHttpRequest(patchRoute, "/routes/0", HttpMethod.PATCH);
execute(client, routePatch, "PATCH update route ID=0");
Route patchRoute = new Route(1, 1, List.of(1L), "Kyiv", "Odesa", 480.0, 7.0, Route.Status.COMPLETED);
var routePatch = createHttpRequest(patchRoute, "/route-service/routes/1", HttpMethod.PATCH);
execute(client, routePatch, "PATCH update route ID=1");
execute(client, new HttpDelete(BASE_URL + "/routes/999"), "DELETE route ID=999 (not found)");
execute(client, new HttpDelete(BASE_URL + "/route-service" + "/routes/999"), "DELETE route ID=999 (not found)");
System.out.println();
IO.println();
}
private static void testSubResources(CloseableHttpClient client) throws Exception {
System.out.println("--- SUB-RESOURCES ---");
private static void testSubResources(CloseableHttpClient client) {
IO.println("--- SUB-RESOURCES ---");
execute(client, new HttpGet(BASE_URL + "/routes/0/freights"), "GET freights for route ID=0 (sub-resource)");
execute(client, new HttpGet(BASE_URL + "/routes/0/vehicle"), "GET vehicle for route ID=0 (sub-resource)");
execute(client, new HttpGet(BASE_URL + "/route-service/routes/1/freights"), "GET freights for route ID=1 (sub-resource)");
execute(client, new HttpGet(BASE_URL + "/route-service/routes/1/vehicle"), "GET vehicle for route ID=1 (sub-resource)");
System.out.println();
IO.println();
}
private static void testStatusFiltering(CloseableHttpClient client) throws Exception {
System.out.println("--- STATUS FILTERING ---");
private static void testStatusFiltering(CloseableHttpClient client) {
IO.println("--- STATUS FILTERING ---");
execute(client, new HttpGet(BASE_URL + "/vehicles?status=AVAILABLE"), "GET vehicles with status=AVAILABLE");
execute(client, new HttpGet(BASE_URL + "/vehicles?status=IN_TRANSIT"), "GET vehicles with status=IN_TRANSIT");
execute(client, new HttpGet(BASE_URL + "/freights?status=PENDING"), "GET freights with status=PENDING");
execute(client, new HttpGet(BASE_URL + "/freights?status=DELIVERED"), "GET freights with status=DELIVERED");
execute(client, new HttpGet(BASE_URL + "/routes?status=PLANNED"), "GET routes with status=PLANNED");
execute(client, new HttpGet(BASE_URL + "/routes?status=COMPLETED"), "GET routes with status=COMPLETED");
execute(client, new HttpGet(BASE_URL + "/vehicle-service/vehicles?status=AVAILABLE"), "GET vehicles with status=AVAILABLE");
execute(client, new HttpGet(BASE_URL + "/vehicle-service/vehicles?status=IN_TRANSIT"), "GET vehicles with status=IN_TRANSIT");
execute(client, new HttpGet(BASE_URL + "/freight-service/freights?status=PENDING"), "GET freights with status=PENDING");
execute(client, new HttpGet(BASE_URL + "/freight-service/freights?status=DELIVERED"), "GET freights with status=DELIVERED");
execute(client, new HttpGet(BASE_URL + "/route-service/routes?status=PLANNED"), "GET routes with status=PLANNED");
execute(client, new HttpGet(BASE_URL + "/route-service/routes?status=COMPLETED"), "GET routes with status=COMPLETED");
System.out.println();
IO.println();
}
private static void testErrorCases(CloseableHttpClient client) throws Exception {
System.out.println("--- ERROR CASES (TESTING EXCEPTION HANDLING) ---");
private static void testErrorCases(CloseableHttpClient client) {
IO.println("--- ERROR CASES (TESTING EXCEPTION HANDLING) ---");
execute(client, new HttpGet(BASE_URL + "/vehicles/999"), "GET non-existent vehicle (404 Not Found)");
execute(client, new HttpGet(BASE_URL + "/freights/-1"), "GET freight with invalid ID (404 Not Found)");
execute(client, new HttpGet(BASE_URL + "/routes/-1"), "GET route with invalid ID (404 Not Found)");
execute(client, new HttpGet(BASE_URL + "/vehicle-service/vehicles/999"), "GET non-existent vehicle (404 Not Found)");
execute(client, new HttpGet(BASE_URL + "/freight-service/freights/-1"), "GET freight with invalid ID (404 Not Found)");
execute(client, new HttpGet(BASE_URL + "/route-service/routes/-1"), "GET route with invalid ID (404 Not Found)");
System.out.println();
IO.println();
}
private static void testInterServiceValidation(CloseableHttpClient client) throws Exception {
System.out.println("--- INTER-SERVICE COMMUNICATION & VALIDATION ---");
private static void testInterServiceValidation(CloseableHttpClient client) {
IO.println("--- INTER-SERVICE COMMUNICATION & VALIDATION ---");
// Test 1: Create route with valid references (should succeed)
System.out.println("[INTER-SERVICE TEST 1] Creating route with valid vehicle and freight references:");
Route validRoute = new Route(0, 0, List.of(0L), "Kyiv", "Lviv", 540.0, 8.5, Route.Status.PLANNED);
var validRoutePost = createHttpRequest(validRoute, "/routes", HttpMethod.POST);
IO.println("[INTER-SERVICE TEST 1] Creating route with valid vehicle and freight references:");
Route validRoute = new Route(1, 1, List.of(1L), "Kyiv", "Lviv", 540.0, 8.5, Route.Status.PLANNED);
var validRoutePost = createHttpRequest(validRoute, "/route-service/routes", HttpMethod.POST);
execute(client, validRoutePost, "POST route with valid vehicle and freights (should succeed)");
// Test 2: Create route with invalid vehicle (should fail with 404)
System.out.println("[INTER-SERVICE TEST 2] Creating route with INVALID vehicle ID:");
Route invalidVehicleRoute = new Route(0, -999, List.of(1L), "Kyiv", "Lviv", 540.0, 8.5, Route.Status.PLANNED);
var invalidRoutePost = createHttpRequest(invalidVehicleRoute, "/routes", HttpMethod.POST);
IO.println("[INTER-SERVICE TEST 2] Creating route with INVALID vehicle ID:");
Route invalidVehicleRoute = new Route(1, -999, List.of(1L), "Kyiv", "Lviv", 540.0, 8.5, Route.Status.PLANNED);
var invalidRoutePost = createHttpRequest(invalidVehicleRoute, "/route-service/routes", HttpMethod.POST);
execute(client, invalidRoutePost, "POST route with invalid vehicle ID, should result in 404");
// Test 3: Create route with invalid freight (should fail with 404)
System.out.println("[INTER-SERVICE TEST 3] Creating route with INVALID freight ID:");
Route invalidFreightRoute = new Route(0, 0, List.of(-999L), "Kyiv", "Lviv", 540.0, 8.5, Route.Status.PLANNED);
var invalidFreightPost = createHttpRequest(invalidFreightRoute, "/routes", HttpMethod.POST);
IO.println("[INTER-SERVICE TEST 3] Creating route with INVALID freight ID:");
Route invalidFreightRoute = new Route(1, 1, List.of(-999L), "Kyiv", "Lviv", 540.0, 8.5, Route.Status.PLANNED);
var invalidFreightPost = createHttpRequest(invalidFreightRoute, "/route-service/routes", HttpMethod.POST);
execute(client, invalidFreightPost, "POST route with invalid freight ID, should result in 404");
}
@@ -202,26 +202,26 @@ public class ApplicationClient {
private static String execute(CloseableHttpClient client, HttpUriRequest request, String description) {
try {
System.out.println("[" + request.getMethod() + "] " + description);
IO.println("[" + request.getMethod() + "] " + description);
CloseableHttpResponse response = client.execute(request);
int statusCode = response.getStatusLine().getStatusCode();
String body = response.getEntity() != null ? EntityUtils.toString(response.getEntity()) : "";
System.out.println("Status: " + statusCode);
IO.println("Status: " + statusCode);
if (!body.isEmpty()) {
System.out.println("Response: " + body);
IO.println("Response: " + body);
}
if (HttpStatus.valueOf(statusCode).isError()) {
System.out.println("ERROR: Request failed with status " + statusCode);
IO.println("ERROR: Request failed with status " + statusCode);
}
System.out.println();
IO.println();
return body;
} catch (Exception e) {
System.out.println("EXCEPTION: " + e.getMessage());
IO.println("EXCEPTION: " + e.getMessage());
e.printStackTrace();
System.out.println();
IO.println();
return null;
}
}

View File

@@ -13,6 +13,9 @@ repositories {
dependencies {
// spring
implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES))
implementation(platform(libs.spring.cloud.dependencies))
implementation("org.springframework.cloud:spring-cloud-starter-netflix-eureka-client")
implementation("org.springframework.boot:spring-boot-starter-aop:4.0.0-M2")
implementation(libs.spring.boot.starter.web)
implementation(libs.spring.boot.starter.web.test)

View File

@@ -0,0 +1,24 @@
package ua.com.dxrkness.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
@Value("${server.port}")
private String port;
@Before("execution(* ua.com.dxrkness.controller.VehicleController.*(..))")
public void logBeforeMethod(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
logger.info(">>> [Instance Port: {}] - Calling method: {}", port, methodName);
}
}

View File

@@ -2,4 +2,8 @@ spring:
application:
name: vehicle-service
server:
port: 8081
port: 8081
eureka:
client:
service-url:
defaultZone: http://localhost:8070/eureka