finish 3rd practical
This commit is contained in:
@@ -1,20 +0,0 @@
|
|||||||
# AGENTS.md
|
|
||||||
|
|
||||||
## Build/Test Commands
|
|
||||||
- Build: `gradle build`
|
|
||||||
- Test all: `gradle test --rerun-tasks`
|
|
||||||
- Run single test: `gradle test --tests "FreightIntegrationTest.getByIdReturnsEntity"`
|
|
||||||
- Run app: `gradle bootRun`
|
|
||||||
|
|
||||||
## Code Style Guidelines
|
|
||||||
- Package structure: `ua.com.dxrkness.{controller,service,repository,model}`
|
|
||||||
- Use Spring Boot annotations (@RestController, @Service, etc.)
|
|
||||||
- Records for models with Jackson @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
|
|
||||||
- Constructor injection for dependencies
|
|
||||||
- JSpecify annotations (@NullMarked, @Nullable) for null safety
|
|
||||||
- Integration tests with @SpringBootTest and parameterized tests
|
|
||||||
- REST controllers support both JSON and XML media types
|
|
||||||
- Use ResponseEntity for HTTP responses with proper status codes
|
|
||||||
- OpenAPI documentation with Swagger annotations on controllers
|
|
||||||
|
|
||||||
# Use pdftotext tool to read PDF files!
|
|
||||||
@@ -15,8 +15,6 @@ dependencies {
|
|||||||
implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES))
|
implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES))
|
||||||
implementation(libs.spring.boot.starter.web)
|
implementation(libs.spring.boot.starter.web)
|
||||||
implementation(libs.spring.boot.starter.web.test)
|
implementation(libs.spring.boot.starter.web.test)
|
||||||
implementation(libs.spring.boot.starter.hateoas)
|
|
||||||
developmentOnly(libs.spring.boot.devtools)
|
|
||||||
|
|
||||||
// http client
|
// http client
|
||||||
implementation(libs.apache.http.client)
|
implementation(libs.apache.http.client)
|
||||||
@@ -24,15 +22,15 @@ dependencies {
|
|||||||
// openapi docs
|
// openapi docs
|
||||||
implementation(libs.springdoc.openapi.starter.webmvc.ui)
|
implementation(libs.springdoc.openapi.starter.webmvc.ui)
|
||||||
|
|
||||||
// xml
|
|
||||||
implementation(libs.jackson.dataformat.xml)
|
|
||||||
|
|
||||||
// testing
|
// testing
|
||||||
testImplementation(platform(libs.junit.bom))
|
testImplementation(platform(libs.junit.bom))
|
||||||
testImplementation(libs.junit.jupiter)
|
testImplementation(libs.junit.jupiter)
|
||||||
testRuntimeOnly(libs.junit.platform.launcher)
|
testRuntimeOnly(libs.junit.platform.launcher)
|
||||||
|
|
||||||
implementation(libs.jspecify)
|
implementation(libs.jspecify)
|
||||||
|
|
||||||
|
implementation(project(":models"))
|
||||||
|
implementation(project(":shared"))
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.test {
|
tasks.test {
|
||||||
+2
-2
@@ -4,8 +4,8 @@ import org.springframework.boot.SpringApplication;
|
|||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class LogisticsApplication {
|
public class FreightServiceApp {
|
||||||
static void main(String[] args) {
|
static void main(String[] args) {
|
||||||
SpringApplication.run(LogisticsApplication.class, args);
|
SpringApplication.run(FreightServiceApp.class, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-3
@@ -6,7 +6,6 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
|||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import ua.com.dxrkness.model.Freight;
|
import ua.com.dxrkness.model.Freight;
|
||||||
import ua.com.dxrkness.service.FreightService;
|
import ua.com.dxrkness.service.FreightService;
|
||||||
@@ -58,8 +57,8 @@ public class FreightController {
|
|||||||
description = "Freight not found"
|
description = "Freight not found"
|
||||||
)
|
)
|
||||||
@GetMapping(value = "/{id}", consumes = MediaType.ALL_VALUE)
|
@GetMapping(value = "/{id}", consumes = MediaType.ALL_VALUE)
|
||||||
public Freight getById(@PathVariable("id") long id) {
|
public List<Freight> getById(@PathVariable("id") long id) {
|
||||||
return service.getById(id);
|
return List.of(service.getById(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(
|
@Operation(
|
||||||
+3
-3
@@ -1,6 +1,5 @@
|
|||||||
package ua.com.dxrkness.service;
|
package ua.com.dxrkness.service;
|
||||||
|
|
||||||
import org.jspecify.annotations.Nullable;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import ua.com.dxrkness.exception.FreightNotFoundException;
|
import ua.com.dxrkness.exception.FreightNotFoundException;
|
||||||
import ua.com.dxrkness.model.Freight;
|
import ua.com.dxrkness.model.Freight;
|
||||||
@@ -21,8 +20,9 @@ public final class FreightService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Freight add(Freight freight) {
|
public Freight add(Freight freight) {
|
||||||
int id = repo.add(freight);
|
var newFreight = new Freight(repo.lastId(), freight.name(), freight.description(), freight.weightKg(), freight.dimensions(), freight.status());
|
||||||
return new Freight(id, freight.name(), freight.description(), freight.weightKg(), freight.dimensions(), freight.status());
|
repo.add(newFreight);
|
||||||
|
return newFreight;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Freight getById(long id) {
|
public Freight getById(long id) {
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: freight-service
|
||||||
|
server:
|
||||||
|
port: 8080
|
||||||
@@ -4,6 +4,7 @@ spring-boot-plugin = "4.0.0"
|
|||||||
jspecify = "1.0.0"
|
jspecify = "1.0.0"
|
||||||
springdoc = "3.0.0"
|
springdoc = "3.0.0"
|
||||||
apache-http-client = "4.5.14"
|
apache-http-client = "4.5.14"
|
||||||
|
json-schema-validator = "3.0.0"
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
spring-boot = { id = "org.springframework.boot", version.ref = "spring-boot-plugin" }
|
spring-boot = { id = "org.springframework.boot", version.ref = "spring-boot-plugin" }
|
||||||
@@ -21,8 +22,9 @@ apache-http-client = { group = "org.apache.httpcomponents", name = "httpclient",
|
|||||||
# openapi
|
# openapi
|
||||||
springdoc-openapi-starter-webmvc-ui = { group = "org.springdoc", name = "springdoc-openapi-starter-webmvc-ui", version.ref = "springdoc" }
|
springdoc-openapi-starter-webmvc-ui = { group = "org.springdoc", name = "springdoc-openapi-starter-webmvc-ui", version.ref = "springdoc" }
|
||||||
|
|
||||||
# xml
|
# jackson
|
||||||
jackson-dataformat-xml = { group = "tools.jackson.dataformat", name = "jackson-dataformat-xml" }
|
jackson-dataformat-xml = { group = "tools.jackson.dataformat", name = "jackson-dataformat-xml" }
|
||||||
|
oldjackson-databind = { group = "com.fasterxml.jackson.core", name = "jackson-databind" }
|
||||||
|
|
||||||
# testing
|
# testing
|
||||||
junit-bom = { group = "org.junit", name = "junit-bom", version.ref = "junit" }
|
junit-bom = { group = "org.junit", name = "junit-bom", version.ref = "junit" }
|
||||||
@@ -30,3 +32,5 @@ junit-jupiter = { group = "org.junit.jupiter", name = "junit-jupiter" }
|
|||||||
junit-platform-launcher = { group = "org.junit.platform", name = "junit-platform-launcher" }
|
junit-platform-launcher = { group = "org.junit.platform", name = "junit-platform-launcher" }
|
||||||
|
|
||||||
jspecify = { group = "org.jspecify", name = "jspecify", version.ref = "jspecify" }
|
jspecify = { group = "org.jspecify", name = "jspecify", version.ref = "jspecify" }
|
||||||
|
|
||||||
|
json-schema-validator = { group = 'com.networknt', name = 'json-schema-validator', version.ref = 'json-schema-validator' }
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
plugins {
|
||||||
|
`java-library`
|
||||||
|
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))
|
||||||
|
|
||||||
|
// jackson
|
||||||
|
api(libs.jackson.dataformat.xml)
|
||||||
|
implementation(libs.oldjackson.databind)
|
||||||
|
}
|
||||||
Executable
+92
@@ -0,0 +1,92 @@
|
|||||||
|
#!/usr/bin/env fish
|
||||||
|
|
||||||
|
function publish_correct
|
||||||
|
set vehicle '{
|
||||||
|
"id": 444,
|
||||||
|
"brand": "test vehicle",
|
||||||
|
"model": "test vehicle",
|
||||||
|
"license_plate": "AB4444AB",
|
||||||
|
"year": 1980,
|
||||||
|
"capacity_kg": 3321,
|
||||||
|
"status": "AVAILABLE"
|
||||||
|
}'
|
||||||
|
|
||||||
|
set freight1 '{
|
||||||
|
"id": 444,
|
||||||
|
"name": "test freight",
|
||||||
|
"description": "test freight",
|
||||||
|
"weight_kg": 444,
|
||||||
|
"dimensions": {
|
||||||
|
"width_cm": 4,
|
||||||
|
"height_cm": 4,
|
||||||
|
"length_cm": 4
|
||||||
|
},
|
||||||
|
"status": "PENDING"
|
||||||
|
}'
|
||||||
|
|
||||||
|
set freight2 '{
|
||||||
|
"id": 555,
|
||||||
|
"name": "test freight 2",
|
||||||
|
"description": "test freight 2",
|
||||||
|
"weight_kg": 555,
|
||||||
|
"dimensions": {
|
||||||
|
"width_cm": 8,
|
||||||
|
"height_cm": 8,
|
||||||
|
"length_cm": 8
|
||||||
|
},
|
||||||
|
"status": "IN_TRANSIT"
|
||||||
|
}'
|
||||||
|
|
||||||
|
set route '{
|
||||||
|
"id": 444,
|
||||||
|
"vehicle_id": 1,
|
||||||
|
"freight_id": [
|
||||||
|
1, 2
|
||||||
|
],
|
||||||
|
"start_location": "string",
|
||||||
|
"end_location": "string",
|
||||||
|
"distance_km": 0.1,
|
||||||
|
"estimated_duration_hours": 0.1,
|
||||||
|
"status": "PLANNED"
|
||||||
|
}'
|
||||||
|
|
||||||
|
printf '\n\n'
|
||||||
|
curl -X POST http://localhost:8081/vehicles \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d $vehicle
|
||||||
|
|
||||||
|
printf '\n\n'
|
||||||
|
curl -X POST http://localhost:8080/freights \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d $freight1
|
||||||
|
|
||||||
|
printf '\n\n'
|
||||||
|
curl -X POST http://localhost:8080/freights \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d $freight2
|
||||||
|
|
||||||
|
printf '\n\n'
|
||||||
|
curl -X POST http://localhost:8082/routes \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d $route
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function add_invalid_route
|
||||||
|
set route '{
|
||||||
|
"id": 444,
|
||||||
|
"vehicle_id": 444,
|
||||||
|
"freight_id": [
|
||||||
|
1, 2
|
||||||
|
],
|
||||||
|
"start_location": "string",
|
||||||
|
"end_location": "string",
|
||||||
|
"distance_km": 0.1,
|
||||||
|
"estimated_duration_hours": 0.1,
|
||||||
|
"status": "PLANNED"
|
||||||
|
}'
|
||||||
|
|
||||||
|
curl -X POST http://localhost:8082/routes \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d $route
|
||||||
|
end
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
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(libs.spring.boot.starter.web)
|
||||||
|
implementation(libs.spring.boot.starter.web.test)
|
||||||
|
|
||||||
|
// http client
|
||||||
|
implementation(libs.apache.http.client)
|
||||||
|
|
||||||
|
// openapi docs
|
||||||
|
implementation(libs.springdoc.openapi.starter.webmvc.ui)
|
||||||
|
|
||||||
|
// testing
|
||||||
|
testImplementation(platform(libs.junit.bom))
|
||||||
|
testImplementation(libs.junit.jupiter)
|
||||||
|
testRuntimeOnly(libs.junit.platform.launcher)
|
||||||
|
|
||||||
|
implementation(libs.jspecify)
|
||||||
|
|
||||||
|
implementation(project(":models"))
|
||||||
|
implementation(project(":shared"))
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package ua.com.dxrkness;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class RouteServiceApp {
|
||||||
|
static void main(String[] args) {
|
||||||
|
SpringApplication.run(RouteServiceApp.class, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package ua.com.dxrkness.client;
|
||||||
|
|
||||||
|
import com.networknt.schema.InputFormat;
|
||||||
|
import com.networknt.schema.Schema;
|
||||||
|
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;
|
||||||
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
import ua.com.dxrkness.model.Freight;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class FreightClient {
|
||||||
|
private final RestClient freightRestClient;
|
||||||
|
private final Schema freightSchema;
|
||||||
|
private final JsonMapper mapper = JsonMapper.shared();
|
||||||
|
|
||||||
|
public FreightClient(RestClient freightRestClient, Schema freightSchema) {
|
||||||
|
this.freightRestClient = freightRestClient;
|
||||||
|
this.freightSchema = freightSchema;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Freight getById(long id) {
|
||||||
|
var resp = freightRestClient.get().uri("/{id}", id)
|
||||||
|
.accept(MediaType.APPLICATION_JSON)
|
||||||
|
.retrieve()
|
||||||
|
.onStatus(HttpStatusCode::is4xxClientError, (req, res) -> {
|
||||||
|
throw new ResponseStatusException(res.getStatusCode(), res.getStatusText());
|
||||||
|
})
|
||||||
|
.body(String.class);
|
||||||
|
System.out.println(resp);
|
||||||
|
List<com.networknt.schema.Error> errs = freightSchema.validate(resp, InputFormat.JSON);
|
||||||
|
if (!errs.isEmpty()) {
|
||||||
|
System.out.println("Some errors have occured!");
|
||||||
|
errs.forEach(err -> {
|
||||||
|
System.out.print(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return mapper.readValue(resp, new TypeReference<List<Freight>>() {
|
||||||
|
}).getFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package ua.com.dxrkness.client;
|
||||||
|
|
||||||
|
import com.networknt.schema.Error;
|
||||||
|
import com.networknt.schema.InputFormat;
|
||||||
|
import com.networknt.schema.Schema;
|
||||||
|
import org.springframework.http.HttpStatusCode;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.client.RestClient;
|
||||||
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
import tools.jackson.core.type.TypeReference;
|
||||||
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
import ua.com.dxrkness.model.Vehicle;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class VehicleClient {
|
||||||
|
private final RestClient vehicleRestClient;
|
||||||
|
private final Schema vehicleSchema;
|
||||||
|
private final JsonMapper mapper = JsonMapper.shared();
|
||||||
|
|
||||||
|
public VehicleClient(RestClient vehicleRestClient, Schema vehicleSchema) {
|
||||||
|
this.vehicleRestClient = vehicleRestClient;
|
||||||
|
this.vehicleSchema = vehicleSchema;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vehicle getById(long id) {
|
||||||
|
var resp = vehicleRestClient.get().uri("/{id}", id)
|
||||||
|
.accept(MediaType.APPLICATION_JSON)
|
||||||
|
.retrieve()
|
||||||
|
.onStatus(HttpStatusCode::is4xxClientError, (req, res) -> {
|
||||||
|
throw new ResponseStatusException(res.getStatusCode(), res.getStatusText());
|
||||||
|
})
|
||||||
|
.body(String.class);
|
||||||
|
System.out.println(resp);
|
||||||
|
List<Error> errs = vehicleSchema.validate(resp, InputFormat.JSON);
|
||||||
|
if (!errs.isEmpty()) {
|
||||||
|
System.out.println("Some errors have occured!");
|
||||||
|
errs.forEach(err -> {
|
||||||
|
System.out.print(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return mapper.readValue(resp, new TypeReference<List<Vehicle>>() {
|
||||||
|
}).getFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package ua.com.dxrkness.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.client.RestClient;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class ClientConfiguration {
|
||||||
|
@Bean
|
||||||
|
public RestClient vehicleRestClient() {
|
||||||
|
return RestClient.create("http://localhost:8081/vehicles");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RestClient freightRestClient() {
|
||||||
|
return RestClient.create("http://localhost:8080/freights");
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
-10
@@ -8,12 +8,12 @@ import org.jspecify.annotations.NullMarked;
|
|||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import ua.com.dxrkness.client.FreightClient;
|
||||||
|
import ua.com.dxrkness.client.VehicleClient;
|
||||||
import ua.com.dxrkness.model.Freight;
|
import ua.com.dxrkness.model.Freight;
|
||||||
import ua.com.dxrkness.model.Route;
|
import ua.com.dxrkness.model.Route;
|
||||||
import ua.com.dxrkness.model.Vehicle;
|
import ua.com.dxrkness.model.Vehicle;
|
||||||
import ua.com.dxrkness.service.FreightService;
|
|
||||||
import ua.com.dxrkness.service.RouteService;
|
import ua.com.dxrkness.service.RouteService;
|
||||||
import ua.com.dxrkness.service.VehicleService;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -28,15 +28,15 @@ import java.util.List;
|
|||||||
@NullMarked
|
@NullMarked
|
||||||
public class RouteController {
|
public class RouteController {
|
||||||
private final RouteService routeService;
|
private final RouteService routeService;
|
||||||
private final VehicleService vehicleService;
|
private final VehicleClient vehicleClient;
|
||||||
private final FreightService freightService;
|
private final FreightClient freightClient;
|
||||||
|
|
||||||
public RouteController(RouteService routeService,
|
public RouteController(RouteService routeService,
|
||||||
VehicleService vehicleService,
|
VehicleClient vehicleClient,
|
||||||
FreightService freightService) {
|
FreightClient freightClient) {
|
||||||
this.routeService = routeService;
|
this.routeService = routeService;
|
||||||
this.vehicleService = vehicleService;
|
this.vehicleClient = vehicleClient;
|
||||||
this.freightService = freightService;
|
this.freightClient = freightClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(
|
@Operation(
|
||||||
@@ -105,7 +105,7 @@ public class RouteController {
|
|||||||
public Vehicle getVehicleById(
|
public Vehicle getVehicleById(
|
||||||
@Parameter(description = "ID of the route to retrieve", required = true)
|
@Parameter(description = "ID of the route to retrieve", required = true)
|
||||||
@PathVariable("id") long id) {
|
@PathVariable("id") long id) {
|
||||||
return vehicleService.getById(routeService.getById(id).vehicleId());
|
return vehicleClient.getById(routeService.getById(id).vehicleId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(
|
@Operation(
|
||||||
@@ -126,7 +126,7 @@ public class RouteController {
|
|||||||
var route = routeService.getById(id);
|
var route = routeService.getById(id);
|
||||||
var freights = new ArrayList<Freight>();
|
var freights = new ArrayList<Freight>();
|
||||||
for (var freightId : route.freightId()) {
|
for (var freightId : route.freightId()) {
|
||||||
freights.add(freightService.getById(freightId));
|
freights.add(freightClient.getById(freightId));
|
||||||
}
|
}
|
||||||
return freights;
|
return freights;
|
||||||
}
|
}
|
||||||
+13
-10
@@ -2,6 +2,8 @@ package ua.com.dxrkness.service;
|
|||||||
|
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import ua.com.dxrkness.client.FreightClient;
|
||||||
|
import ua.com.dxrkness.client.VehicleClient;
|
||||||
import ua.com.dxrkness.dto.FreightDto;
|
import ua.com.dxrkness.dto.FreightDto;
|
||||||
import ua.com.dxrkness.dto.VehicleDto;
|
import ua.com.dxrkness.dto.VehicleDto;
|
||||||
import ua.com.dxrkness.exception.FreightNotFoundException;
|
import ua.com.dxrkness.exception.FreightNotFoundException;
|
||||||
@@ -15,15 +17,15 @@ import java.util.List;
|
|||||||
@Service
|
@Service
|
||||||
public final class RouteService {
|
public final class RouteService {
|
||||||
private final RouteRepository repo;
|
private final RouteRepository repo;
|
||||||
private final VehicleService vehicleService;
|
private final VehicleClient vehicleClient;
|
||||||
private final FreightService freightService;
|
private final FreightClient freightClient;
|
||||||
|
|
||||||
public RouteService(RouteRepository repo,
|
public RouteService(RouteRepository repo,
|
||||||
VehicleService vehicleService,
|
VehicleClient vehicleClient,
|
||||||
FreightService freightService) {
|
FreightClient freightClient) {
|
||||||
this.repo = repo;
|
this.repo = repo;
|
||||||
this.vehicleService = vehicleService;
|
this.vehicleClient = vehicleClient;
|
||||||
this.freightService = freightService;
|
this.freightClient = freightClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Route> getAll() {
|
public List<Route> getAll() {
|
||||||
@@ -42,8 +44,7 @@ public final class RouteService {
|
|||||||
VehicleDto vehicleDto = validateAndGetVehicle(route.vehicleId());
|
VehicleDto vehicleDto = validateAndGetVehicle(route.vehicleId());
|
||||||
List<FreightDto> freightDtos = validateAndGetFreights(route.freightId());
|
List<FreightDto> freightDtos = validateAndGetFreights(route.freightId());
|
||||||
|
|
||||||
int id = repo.add(route);
|
var newRoute = new Route(repo.lastId(),
|
||||||
return new Route(id,
|
|
||||||
route.vehicleId(),
|
route.vehicleId(),
|
||||||
route.freightId(),
|
route.freightId(),
|
||||||
route.startLocation(),
|
route.startLocation(),
|
||||||
@@ -51,11 +52,13 @@ public final class RouteService {
|
|||||||
route.distanceKm(),
|
route.distanceKm(),
|
||||||
route.estimatedDurationHours(),
|
route.estimatedDurationHours(),
|
||||||
route.status());
|
route.status());
|
||||||
|
repo.add(route);
|
||||||
|
return newRoute;
|
||||||
}
|
}
|
||||||
|
|
||||||
private VehicleDto validateAndGetVehicle(long vehicleId) {
|
private VehicleDto validateAndGetVehicle(long vehicleId) {
|
||||||
try {
|
try {
|
||||||
var vehicle = vehicleService.getById(vehicleId);
|
var vehicle = vehicleClient.getById(vehicleId);
|
||||||
return VehicleDto.fromVehicle(vehicle);
|
return VehicleDto.fromVehicle(vehicle);
|
||||||
} catch (VehicleNotFoundException e) {
|
} catch (VehicleNotFoundException e) {
|
||||||
throw new VehicleNotFoundException(
|
throw new VehicleNotFoundException(
|
||||||
@@ -67,7 +70,7 @@ public final class RouteService {
|
|||||||
List<FreightDto> freightDtos = new java.util.ArrayList<>();
|
List<FreightDto> freightDtos = new java.util.ArrayList<>();
|
||||||
for (long freightId : freightIds) {
|
for (long freightId : freightIds) {
|
||||||
try {
|
try {
|
||||||
var freight = freightService.getById(freightId);
|
var freight = freightClient.getById(freightId);
|
||||||
freightDtos.add(FreightDto.fromFreight(freight));
|
freightDtos.add(FreightDto.fromFreight(freight));
|
||||||
} catch (FreightNotFoundException e) {
|
} catch (FreightNotFoundException e) {
|
||||||
throw new FreightNotFoundException(
|
throw new FreightNotFoundException(
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: route-service
|
||||||
|
server:
|
||||||
|
port: 8082
|
||||||
@@ -1,2 +1,4 @@
|
|||||||
rootProject.name = "itroi"
|
rootProject.name = "itroi"
|
||||||
enableFeaturePreview("STABLE_CONFIGURATION_CACHE")
|
enableFeaturePreview("STABLE_CONFIGURATION_CACHE")
|
||||||
|
|
||||||
|
include("models", "vehicle-service", "route-service", "freight-service", "shared")
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
plugins {
|
||||||
|
`java-library`
|
||||||
|
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(libs.spring.boot.starter.web)
|
||||||
|
|
||||||
|
// http client
|
||||||
|
implementation(libs.apache.http.client)
|
||||||
|
|
||||||
|
// xml
|
||||||
|
implementation(libs.jackson.dataformat.xml)
|
||||||
|
|
||||||
|
implementation(libs.jspecify)
|
||||||
|
|
||||||
|
implementation(project(":models"))
|
||||||
|
|
||||||
|
api(libs.json.schema.validator);
|
||||||
|
|
||||||
|
implementation("org.jruby.joni:joni:2.2.6")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package ua.com.dxrkness.config;
|
||||||
|
|
||||||
|
import com.networknt.schema.*;
|
||||||
|
import com.networknt.schema.regex.JoniRegularExpressionFactory;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class JsonSchemaConfiguration {
|
||||||
|
@Bean
|
||||||
|
SchemaRegistry schemaRegistry() {
|
||||||
|
var schemaRegistryConfig = SchemaRegistryConfig.builder()
|
||||||
|
.regularExpressionFactory(JoniRegularExpressionFactory.getInstance())
|
||||||
|
.failFast(true).build();
|
||||||
|
|
||||||
|
return SchemaRegistry.withDefaultDialect(SpecificationVersion.DRAFT_2020_12,
|
||||||
|
builder -> builder.schemaRegistryConfig(schemaRegistryConfig)
|
||||||
|
/*
|
||||||
|
* This creates a mapping from $id which starts with
|
||||||
|
* https://www.example.org/schema to the retrieval IRI classpath:schema.
|
||||||
|
*/
|
||||||
|
.schemaIdResolvers(schemaIdResolvers -> schemaIdResolvers
|
||||||
|
.mapPrefix("https://nure.ua/itroi", "classpath:json-schema")));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Schema vehicleSchema(SchemaRegistry schemaRegistry) {
|
||||||
|
return schemaRegistry.getSchema(SchemaLocation.of("https://nure.ua/itroi/vehicle-schema.json"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Schema routeSchema(SchemaRegistry schemaRegistry) {
|
||||||
|
return schemaRegistry.getSchema(SchemaLocation.of("https://nure.ua/itroi/route-schema.json"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Schema freightSchema(SchemaRegistry schemaRegistry) {
|
||||||
|
return schemaRegistry.getSchema(SchemaLocation.of("https://nure.ua/itroi/freight-schema.json"));
|
||||||
|
}
|
||||||
|
}
|
||||||
+6
@@ -5,6 +5,7 @@ import org.springframework.http.HttpStatus;
|
|||||||
import org.springframework.web.ErrorResponse;
|
import org.springframework.web.ErrorResponse;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
import ua.com.dxrkness.exception.FreightNotFoundException;
|
import ua.com.dxrkness.exception.FreightNotFoundException;
|
||||||
import ua.com.dxrkness.exception.RouteNotFoundException;
|
import ua.com.dxrkness.exception.RouteNotFoundException;
|
||||||
import ua.com.dxrkness.exception.VehicleNotFoundException;
|
import ua.com.dxrkness.exception.VehicleNotFoundException;
|
||||||
@@ -28,6 +29,11 @@ public class GlobalExceptionHandler {
|
|||||||
return constructExceptionBody(HttpStatus.BAD_REQUEST, ex);
|
return constructExceptionBody(HttpStatus.BAD_REQUEST, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(ResponseStatusException.class)
|
||||||
|
public ErrorResponse handleResponseStatusException(ResponseStatusException ex) {
|
||||||
|
return ex;
|
||||||
|
}
|
||||||
|
|
||||||
@ExceptionHandler(Exception.class)
|
@ExceptionHandler(Exception.class)
|
||||||
public ErrorResponse handleGeneralException(Exception ex) {
|
public ErrorResponse handleGeneralException(Exception ex) {
|
||||||
return constructExceptionBody(HttpStatus.INTERNAL_SERVER_ERROR, ex);
|
return constructExceptionBody(HttpStatus.INTERNAL_SERVER_ERROR, ex);
|
||||||
+6
@@ -5,9 +5,11 @@ import ua.com.dxrkness.model.Identifiable;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
abstract class CrudRepository<T extends Identifiable> {
|
abstract class CrudRepository<T extends Identifiable> {
|
||||||
protected final List<T> STORAGE = new ArrayList<>();
|
protected final List<T> STORAGE = new ArrayList<>();
|
||||||
|
private final AtomicLong id = new AtomicLong(0);
|
||||||
|
|
||||||
public List<T> getAll() {
|
public List<T> getAll() {
|
||||||
return new ArrayList<>(STORAGE); // defensive copy
|
return new ArrayList<>(STORAGE); // defensive copy
|
||||||
@@ -55,4 +57,8 @@ abstract class CrudRepository<T extends Identifiable> {
|
|||||||
public void deleteAll() {
|
public void deleteAll() {
|
||||||
STORAGE.clear();
|
STORAGE.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long lastId() {
|
||||||
|
return id.incrementAndGet();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package ua.com.dxrkness.service;
|
||||||
|
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import ua.com.dxrkness.model.Freight;
|
||||||
|
import ua.com.dxrkness.model.Vehicle;
|
||||||
|
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@NullMarked
|
||||||
|
public class PopulateService {
|
||||||
|
|
||||||
|
public PopulateService() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void populate(int vals){
|
||||||
|
for (int i = 0; i < vals; i++) {
|
||||||
|
var f = new Freight(i, "", "", 0, null, null);
|
||||||
|
// freightRepository.add(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < vals; i++) {
|
||||||
|
var v = new Vehicle(i, "", "", "", 0, 0, null);
|
||||||
|
// vehicleRepository.add(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < vals; i++) {}
|
||||||
|
// routeRepository.add(new Route(i, i, List.of((long)i), "", "", 0., 0., null));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
// routeRepository.deleteAll();
|
||||||
|
// freightRepository.deleteAll();
|
||||||
|
// vehicleRepository.deleteAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$id": "https://nure.ua/itroi/freight-schema.json",
|
||||||
|
"title": "Freight management schema",
|
||||||
|
"description": "Describes domain objects of freights",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 3,
|
||||||
|
"maxLength": 128
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string",
|
||||||
|
"maxLength": 500
|
||||||
|
},
|
||||||
|
"weight_kg": {
|
||||||
|
"type": "number",
|
||||||
|
"exclusiveMinimum": 0,
|
||||||
|
"exclusiveMaximum": 4294967296
|
||||||
|
},
|
||||||
|
"dimensions": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"width_cm": {
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 1,
|
||||||
|
"maximum": 150000
|
||||||
|
},
|
||||||
|
"height_cm": {
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 1,
|
||||||
|
"maximum": 150000
|
||||||
|
},
|
||||||
|
"length_cm": {
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 1,
|
||||||
|
"maximum": 150000
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"width_cm",
|
||||||
|
"height_cm",
|
||||||
|
"length_cm"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"PENDING",
|
||||||
|
"IN_TRANSIT",
|
||||||
|
"DELIVERED"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"weight_kg",
|
||||||
|
"dimensions",
|
||||||
|
"status"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$id": "https://nure.ua/itroi/route-schema.json",
|
||||||
|
"title": "Routes management schema",
|
||||||
|
"description": "Describes domain objects of routes",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"vehicle_id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"freight_id": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"minItems": 1
|
||||||
|
},
|
||||||
|
"start_location": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"end_location": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"distance_km": {
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 0
|
||||||
|
},
|
||||||
|
"estimated_duration_hours": {
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 0
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"PLANNED",
|
||||||
|
"IN_PROGRESS",
|
||||||
|
"COMPLETED",
|
||||||
|
"CANCELLED"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"vehicle_id",
|
||||||
|
"freight_id",
|
||||||
|
"start_location",
|
||||||
|
"end_location",
|
||||||
|
"distance_km",
|
||||||
|
"status"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$id": "https://nure.ua/itroi/vehicle-schema.json",
|
||||||
|
"title": "Vehicles management schema",
|
||||||
|
"description": "Describes domain objects of vehicles",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1,
|
||||||
|
"maximum": 4294967295
|
||||||
|
},
|
||||||
|
"brand": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 2,
|
||||||
|
"maxLength": 64
|
||||||
|
},
|
||||||
|
"model": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 1,
|
||||||
|
"maxLength": 128
|
||||||
|
},
|
||||||
|
"license_plate": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^[A-Z]{2}[0-9]{4}[A-Z]{2}$",
|
||||||
|
"minLength": 8,
|
||||||
|
"maxLength": 8
|
||||||
|
},
|
||||||
|
"year": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1980
|
||||||
|
},
|
||||||
|
"capacity_kg": {
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 100,
|
||||||
|
"exclusiveMaximum": 4294967296
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"AVAILABLE",
|
||||||
|
"IN_TRANSIT",
|
||||||
|
"MAINTENANCE"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"brand",
|
||||||
|
"model",
|
||||||
|
"license_plate",
|
||||||
|
"year",
|
||||||
|
"capacity_kg",
|
||||||
|
"status"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-4
@@ -89,8 +89,8 @@ class InterServiceCommunicationTest {
|
|||||||
.expectBody(String.class)
|
.expectBody(String.class)
|
||||||
.consumeWith(res -> {
|
.consumeWith(res -> {
|
||||||
String body = res.getResponseBody();
|
String body = res.getResponseBody();
|
||||||
then(body).isNotNull();
|
BDDAssertions.then(body).isNotNull();
|
||||||
then(body).contains("Not Found").contains("vehicle");
|
BDDAssertions.then(body).contains("Not Found").contains("vehicle");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,8 +115,8 @@ class InterServiceCommunicationTest {
|
|||||||
.expectBody(String.class)
|
.expectBody(String.class)
|
||||||
.consumeWith(res -> {
|
.consumeWith(res -> {
|
||||||
String body = res.getResponseBody();
|
String body = res.getResponseBody();
|
||||||
then(body).isNotNull();
|
BDDAssertions.then(body).isNotNull();
|
||||||
then(body).contains("Not Found").contains("freight");
|
BDDAssertions.then(body).contains("Not Found").contains("freight");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
+6
-10
@@ -7,15 +7,11 @@ import org.junit.jupiter.params.ParameterizedTest;
|
|||||||
import org.junit.jupiter.params.provider.MethodSource;
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.core.ParameterizedTypeReference;
|
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.test.web.servlet.client.RestTestClient;
|
import org.springframework.test.web.servlet.client.RestTestClient;
|
||||||
import org.springframework.web.context.WebApplicationContext;
|
import org.springframework.web.context.WebApplicationContext;
|
||||||
import ua.com.dxrkness.model.Freight;
|
|
||||||
import ua.com.dxrkness.model.Route;
|
|
||||||
import ua.com.dxrkness.service.PopulateService;
|
import ua.com.dxrkness.service.PopulateService;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static org.assertj.core.api.BDDAssertions.then;
|
import static org.assertj.core.api.BDDAssertions.then;
|
||||||
@@ -64,8 +60,8 @@ class SubResourcesAndFilteringTest {
|
|||||||
.expectBody(String.class)
|
.expectBody(String.class)
|
||||||
.consumeWith(res -> {
|
.consumeWith(res -> {
|
||||||
String body = res.getResponseBody();
|
String body = res.getResponseBody();
|
||||||
then(body).isNotNull();
|
BDDAssertions.then(body).isNotNull();
|
||||||
then(body).contains("Not Found");
|
BDDAssertions.then(body).contains("Not Found");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,8 +81,8 @@ class SubResourcesAndFilteringTest {
|
|||||||
.expectBody(String.class)
|
.expectBody(String.class)
|
||||||
.consumeWith(res -> {
|
.consumeWith(res -> {
|
||||||
String body = res.getResponseBody();
|
String body = res.getResponseBody();
|
||||||
then(body).isNotNull();
|
BDDAssertions.then(body).isNotNull();
|
||||||
then(body).contains("Not Found");
|
BDDAssertions.then(body).contains("Not Found");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,8 +102,8 @@ class SubResourcesAndFilteringTest {
|
|||||||
.expectBody(String.class)
|
.expectBody(String.class)
|
||||||
.consumeWith(res -> {
|
.consumeWith(res -> {
|
||||||
String body = res.getResponseBody();
|
String body = res.getResponseBody();
|
||||||
then(body).isNotNull();
|
BDDAssertions.then(body).isNotNull();
|
||||||
then(body).contains("Not Found");
|
BDDAssertions.then(body).contains("Not Found");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
@NullMarked
|
|
||||||
package ua.com.dxrkness;
|
|
||||||
|
|
||||||
import org.jspecify.annotations.NullMarked;
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
package ua.com.dxrkness.service;
|
|
||||||
|
|
||||||
import org.jspecify.annotations.NullMarked;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import ua.com.dxrkness.model.Freight;
|
|
||||||
import ua.com.dxrkness.model.Route;
|
|
||||||
import ua.com.dxrkness.model.Vehicle;
|
|
||||||
import ua.com.dxrkness.repository.FreightRepository;
|
|
||||||
import ua.com.dxrkness.repository.RouteRepository;
|
|
||||||
import ua.com.dxrkness.repository.VehicleRepository;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
@NullMarked
|
|
||||||
public class PopulateService {
|
|
||||||
private final FreightRepository freightRepository;
|
|
||||||
private final RouteRepository routeRepository;
|
|
||||||
private final VehicleRepository vehicleRepository;
|
|
||||||
|
|
||||||
public PopulateService(FreightRepository freightRepository, RouteRepository routeRepository, VehicleRepository vehicleRepository) {
|
|
||||||
this.freightRepository = freightRepository;
|
|
||||||
this.routeRepository = routeRepository;
|
|
||||||
this.vehicleRepository = vehicleRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void populate(int vals){
|
|
||||||
for (int i = 0; i < vals; i++) {
|
|
||||||
var f = new Freight(i, "", "", 0, null, null);
|
|
||||||
freightRepository.add(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < vals; i++) {
|
|
||||||
var v = new Vehicle(i, "", "", "", 0, 0, null);
|
|
||||||
vehicleRepository.add(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < vals; i++)
|
|
||||||
routeRepository.add(new Route(i, i, List.of((long)i), "", "", 0., 0., null));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear() {
|
|
||||||
routeRepository.deleteAll();
|
|
||||||
freightRepository.deleteAll();
|
|
||||||
vehicleRepository.deleteAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
spring:
|
|
||||||
application:
|
|
||||||
name: itroi
|
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
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(libs.spring.boot.starter.web)
|
||||||
|
implementation(libs.spring.boot.starter.web.test)
|
||||||
|
|
||||||
|
// http client
|
||||||
|
implementation(libs.apache.http.client)
|
||||||
|
|
||||||
|
// openapi docs
|
||||||
|
implementation(libs.springdoc.openapi.starter.webmvc.ui)
|
||||||
|
|
||||||
|
// testing
|
||||||
|
testImplementation(platform(libs.junit.bom))
|
||||||
|
testImplementation(libs.junit.jupiter)
|
||||||
|
testRuntimeOnly(libs.junit.platform.launcher)
|
||||||
|
|
||||||
|
implementation(libs.jspecify)
|
||||||
|
|
||||||
|
implementation(project(":models"))
|
||||||
|
implementation(project(":shared"))
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package ua.com.dxrkness;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class VehicleServiceApp {
|
||||||
|
static void main(String[] args) {
|
||||||
|
SpringApplication.run(VehicleServiceApp.class, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -50,10 +50,10 @@ public class VehicleController {
|
|||||||
@ApiResponse(responseCode = "200", description = "Vehicle found")
|
@ApiResponse(responseCode = "200", description = "Vehicle found")
|
||||||
@ApiResponse(responseCode = "404", description = "Vehicle not found")
|
@ApiResponse(responseCode = "404", description = "Vehicle not found")
|
||||||
@GetMapping(value = "/{id}", consumes = MediaType.ALL_VALUE)
|
@GetMapping(value = "/{id}", consumes = MediaType.ALL_VALUE)
|
||||||
public Vehicle getById(
|
public List<Vehicle> getById(
|
||||||
@Parameter(description = "ID of the vehicle to retrieve", required = true)
|
@Parameter(description = "ID of the vehicle to retrieve", required = true)
|
||||||
@PathVariable("id") long id) {
|
@PathVariable("id") long id) {
|
||||||
return service.getById(id);
|
return List.of(service.getById(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(
|
@Operation(
|
||||||
+3
-2
@@ -26,8 +26,9 @@ public final class VehicleService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Vehicle add(Vehicle veh) {
|
public Vehicle add(Vehicle veh) {
|
||||||
int id = repo.add(veh);
|
var newVehicle = new Vehicle(repo.lastId(), veh.brand(), veh.model(), veh.licensePlate(), veh.year(), veh.capacityKg(), veh.status());
|
||||||
return new Vehicle(id, veh.brand(), veh.model(), veh.licensePlate(), veh.year(), veh.capacityKg(), veh.status());
|
repo.add(newVehicle);
|
||||||
|
return newVehicle;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vehicle getById(long id) {
|
public Vehicle getById(long id) {
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: vehicle-service
|
||||||
|
server:
|
||||||
|
port: 8081
|
||||||
Reference in New Issue
Block a user