diff --git a/application/pom.xml b/application/pom.xml index 5c05b4d33520af90ce63d0e90f7bace770b8f57a..68e172032e0bda65aeb8b57e7a8845fbd644b74b 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -164,5 +164,10 @@ <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-webflux</artifactId> + <version>6.0.6</version> + </dependency> </dependencies> </project> diff --git a/application/src/main/java/cz/muni/pa165/config/ServiceConfig.java b/application/src/main/java/cz/muni/pa165/config/ServiceConfig.java index 9113f55d6e41232aa18163acd24753af63aaaec9..659bb487e2103f30814d3e18d8e72b04074f664c 100644 --- a/application/src/main/java/cz/muni/pa165/config/ServiceConfig.java +++ b/application/src/main/java/cz/muni/pa165/config/ServiceConfig.java @@ -4,7 +4,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.transaction.annotation.EnableTransactionManagement; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; /** * @author Michal Badin @@ -14,7 +14,7 @@ import org.springframework.web.client.RestTemplate; @EnableTransactionManagement public class ServiceConfig { @Bean - public RestTemplate restTemplate() { - return new RestTemplate(); + public WebClient.Builder getWebClientBuilder() { + return WebClient.builder(); } } \ No newline at end of file diff --git a/application/src/main/java/cz/muni/pa165/service/ApplicationService.java b/application/src/main/java/cz/muni/pa165/service/ApplicationService.java index 56ba43b0882cd54fb17753744c62adbed1e7af5e..a2d8779629233f3fe7238a20dcdb605c42a7060b 100644 --- a/application/src/main/java/cz/muni/pa165/service/ApplicationService.java +++ b/application/src/main/java/cz/muni/pa165/service/ApplicationService.java @@ -7,13 +7,12 @@ import cz.muni.pa165.exceptions.ResourceNotFoundException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; +import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.MediaType; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; import java.time.LocalDate; import java.util.HashMap; @@ -27,17 +26,18 @@ import java.util.Optional; @Service public class ApplicationService { private static final Logger log = LoggerFactory.getLogger(ApplicationService.class); - private static final String NOTIFICATION_MODULE_URL_NEW = "http://localhost:8083/notification/application/new"; - private static final String NOTIFICATION_MODULE_URL_STATUS = "http://localhost:8083/notification/application/status"; + private static final String NOTIFICATION_MODULE_URL = "http://localhost:8083"; + private static final String NOTIFICATION_MODULE_URI_NEW = "/notification/application/new"; + private static final String NOTIFICATION_MODULE_URI_STATUS = "/notification/application/status"; private static final List<String> NOTIFICATION_RECEIVERS = List.of("formula.team.management@gmail.com"); private final ApplicationRepository applicationRepository; - private final RestTemplate restTemplate; + private final WebClient webClient; @Autowired - public ApplicationService(ApplicationRepository applicationRepository, RestTemplate restTemplate) { + public ApplicationService(ApplicationRepository applicationRepository, WebClient.Builder webClientBuilder) { this.applicationRepository = applicationRepository; - this.restTemplate = restTemplate; + this.webClient = webClientBuilder.baseUrl(NOTIFICATION_MODULE_URL).build(); } @Transactional(readOnly = true) @@ -52,9 +52,9 @@ public class ApplicationService { var savedApplication = applicationRepository.save(application); try { - sendPostRequest(savedApplication, NOTIFICATION_MODULE_URL_NEW, List.of(savedApplication.getEmail())); + sendPostRequest(savedApplication, NOTIFICATION_MODULE_URI_NEW, List.of(savedApplication.getEmail())); } catch (RestClientException | IllegalArgumentException e) { - log.debug(String.format("The notification module is not reachable on the URL: %s", NOTIFICATION_MODULE_URL_NEW)); + log.debug(String.format("The notification module is not reachable on the URL: %s, exception %s", NOTIFICATION_MODULE_URL + NOTIFICATION_MODULE_URI_NEW, e)); } return savedApplication; @@ -79,23 +79,29 @@ public class ApplicationService { if (savedApplication.getStatus() != ApplicationStatusEnum.PENDING) { try { - sendPostRequest(savedApplication, NOTIFICATION_MODULE_URL_STATUS, NOTIFICATION_RECEIVERS); + sendPostRequest(savedApplication, NOTIFICATION_MODULE_URI_STATUS, NOTIFICATION_RECEIVERS); } catch (RestClientException | IllegalArgumentException e) { - log.debug(String.format("The notification module is not reachable on the URL: %s", NOTIFICATION_MODULE_URL_NEW)); + log.debug(String.format("The notification module is not reachable on the URL: %s, exception %s", NOTIFICATION_MODULE_URL + NOTIFICATION_MODULE_URI_STATUS, e)); } } return savedApplication; } - private void sendPostRequest(Application application, String url, List<String> receivers) { + public void sendPostRequest(Application application, String uri, List<String> receivers) throws RestClientException { Map<String, Object> notification = new HashMap<>(); notification.put("application", application); notification.put("receivers", receivers); - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - HttpEntity<Map<String, Object>> request = new HttpEntity<>(notification, headers); - restTemplate.postForObject(url, request, String.class); + webClient.post() + .uri(uri) + .contentType(MediaType.APPLICATION_JSON) + .bodyValue(notification) + .retrieve() + .bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {}) + .doOnError(error -> { + throw new RestClientException("Failed to send POST request", error); + }) + .block(); } } diff --git a/application/src/test/java/cz/muni/pa165/service/ApplicationServiceTest.java b/application/src/test/java/cz/muni/pa165/service/ApplicationServiceTest.java index 9d04ac4e32bc8d94c1cfc7f1e5f42b7c4320c217..5715cd0f1c90c45a691a38f1467b0f082d30a6d7 100644 --- a/application/src/test/java/cz/muni/pa165/service/ApplicationServiceTest.java +++ b/application/src/test/java/cz/muni/pa165/service/ApplicationServiceTest.java @@ -8,6 +8,7 @@ import org.junit.jupiter.api.Test; import org.mockito.Mockito; import org.springframework.test.context.ActiveProfiles; import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; import java.time.LocalDate; import java.util.Optional; @@ -18,8 +19,8 @@ import static org.mockito.Mockito.when; class ApplicationServiceTest { ApplicationRepository applicationRepository = Mockito.mock(ApplicationRepository.class); - RestTemplate restTemplate = Mockito.mock(RestTemplate.class); - ApplicationService service = new ApplicationService(applicationRepository, restTemplate); + WebClient.Builder webClientBuilder = WebClient.builder(); + ApplicationService service = new ApplicationService(applicationRepository, webClientBuilder); Application application = new Application(ApplicationStatusEnum.ACCEPTED, "John", "Doe", LocalDate.now().minusYears(20), "john.doe@example.com", LocalDate.now()); diff --git a/core/pom.xml b/core/pom.xml index 361cc7d112f7df370e80a0c1fe549090c926a561..b2ab489b547b418b3da6a856628f14f7e003dbe1 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -170,6 +170,11 @@ <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-webflux</artifactId> + <version>6.0.6</version> + </dependency> </dependencies> diff --git a/core/src/main/java/cz/muni/pa165/config/ServiceConfig.java b/core/src/main/java/cz/muni/pa165/config/ServiceConfig.java index 925b3c5594ef2902bb4983c2035aa5eee7f75e3d..4af3803cff63a52b4558a83b2d42bcd38b2292e8 100644 --- a/core/src/main/java/cz/muni/pa165/config/ServiceConfig.java +++ b/core/src/main/java/cz/muni/pa165/config/ServiceConfig.java @@ -4,14 +4,14 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.transaction.annotation.EnableTransactionManagement; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; @Configuration @ComponentScan @EnableTransactionManagement public class ServiceConfig { @Bean - public RestTemplate restTemplate() { - return new RestTemplate(); + public WebClient.Builder getWebClientBuilder() { + return WebClient.builder(); } } diff --git a/core/src/main/java/cz/muni/pa165/service/CarComponentService.java b/core/src/main/java/cz/muni/pa165/service/CarComponentService.java index eb8c89a38ef514ccde47c96634252e02fa05d2f3..206402e0d515cc556d96c8f191dcecd8150a1bbe 100644 --- a/core/src/main/java/cz/muni/pa165/service/CarComponentService.java +++ b/core/src/main/java/cz/muni/pa165/service/CarComponentService.java @@ -7,12 +7,12 @@ import cz.muni.pa165.exceptions.ResourceNotFoundException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; +import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.MediaType; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.client.*; +import org.springframework.web.reactive.function.client.WebClient; import java.util.*; @@ -21,24 +21,26 @@ public class CarComponentService extends DomainService<CarComponent> { private static final Logger log = LoggerFactory.getLogger(CarComponentService.class); private final CarComponentRepository componentRepository; - private final RestTemplate restTemplate; + private final WebClient webClient; - private static final String NOTIFICATION_MODULE_URL = "http://localhost:8083/notification/component"; + private static final String NOTIFICATION_MODULE_URL = "http://localhost:8083"; + private static final String NOTIFICATION_MODULE_URI = "/notification/component"; private static final List<String> NOTIFICATION_RECEIVERS = List.of("formula.team.management@gmail.com"); @Autowired - public CarComponentService(CarComponentRepository repository, RestTemplate restTemplate) { + public CarComponentService(CarComponentRepository repository, WebClient.Builder webClientBuilder) { super(repository, CarComponent.class); this.componentRepository = repository; - this.restTemplate = restTemplate; + this.webClient = webClientBuilder.baseUrl(NOTIFICATION_MODULE_URL).build(); } + @Override public CarComponent create(CarComponent component) { CarComponent savedComponent = repository.save(component); try { sendPostRequest(savedComponent); } catch (RestClientException | IllegalArgumentException e) { - log.debug(String.format("The notification module is not reachable on the URL: %s", NOTIFICATION_MODULE_URL)); + log.debug(String.format("The notification module is not reachable on the URL: %s, exception %s", NOTIFICATION_MODULE_URL + NOTIFICATION_MODULE_URI, e)); } return savedComponent; } @@ -72,9 +74,15 @@ public class CarComponentService extends DomainService<CarComponent> { notification.put("carComponent", component); notification.put("receivers", NOTIFICATION_RECEIVERS); - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - HttpEntity<Map<String, Object>> request = new HttpEntity<>(notification, headers); - restTemplate.postForObject(NOTIFICATION_MODULE_URL, request, String.class); + webClient.post() + .uri(NOTIFICATION_MODULE_URI) + .contentType(MediaType.APPLICATION_JSON) + .bodyValue(notification) + .retrieve() + .bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {}) + .doOnError(error -> { + throw new RestClientException("Failed to send POST request", error); + }) + .block(); } } diff --git a/core/src/main/java/cz/muni/pa165/service/CarService.java b/core/src/main/java/cz/muni/pa165/service/CarService.java index 0ccc051378f01c6a73f1dea568369efaa54da638..171f5abf830ad943a7eb4b244c98d6353c0a2383 100644 --- a/core/src/main/java/cz/muni/pa165/service/CarService.java +++ b/core/src/main/java/cz/muni/pa165/service/CarService.java @@ -11,16 +11,15 @@ import cz.muni.pa165.exceptions.ResourceNotFoundException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; import java.util.HashMap; import java.util.List; @@ -30,22 +29,21 @@ import java.util.Optional; @Service public class CarService extends DomainService<Car> { private static final Logger log = LoggerFactory.getLogger(CarService.class); + private static final String VISUALIZATION_MODULE_URL = "http://localhost:8082"; + private static final String VISUALIZATION_MODULE_URI = "/visualization"; private final DriverRepository driverRepository; private final CarRepository carRepository; private final CarComponentRepository carComponentRepository; - - private final RestTemplate restTemplate; - - private static final String VISUALIZATION_MODULE_URL = "http://localhost:8082/visualization"; + private final WebClient webClient; @Autowired public CarService(CarRepository carRepository, DriverRepository driverRepository, - CarComponentRepository carComponentRepository, RestTemplate restTemplate) { + CarComponentRepository carComponentRepository, WebClient.Builder webClientBuilder) { super(carRepository, Car.class); this.driverRepository = driverRepository; this.carRepository = carRepository; this.carComponentRepository = carComponentRepository; - this.restTemplate = restTemplate; + this.webClient = webClientBuilder.baseUrl(VISUALIZATION_MODULE_URL).build(); } public Car create(List<Long> componentIds) { @@ -54,6 +52,7 @@ public class CarService extends DomainService<Car> { return car; } + @Override public void delete(Long id) { Optional<Car> carFromDb = carRepository.findById(id); if (carFromDb.isEmpty()) { @@ -114,7 +113,7 @@ public class CarService extends DomainService<Car> { try { sendPostRequest(savedCar); } catch (RestClientException | IllegalArgumentException e) { - log.debug(String.format("The visualization module is not reachable on the URL: %s, exception %s", VISUALIZATION_MODULE_URL, e)); + log.debug(String.format("The visualization module is not reachable on the URL: %s, exception %s", VISUALIZATION_MODULE_URL + VISUALIZATION_MODULE_URI, e)); } return savedCar; @@ -176,13 +175,20 @@ public class CarService extends DomainService<Car> { } } - private void sendPostRequest(Car car) { + public void sendPostRequest(Car car) throws RestClientException { Map<String, Object> visualization = new HashMap<>(); visualization.put("car", car); - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - HttpEntity<Map<String, Object>> request = new HttpEntity<>(visualization, headers); - restTemplate.postForObject(VISUALIZATION_MODULE_URL, request, String.class); + webClient.post() + .uri(VISUALIZATION_MODULE_URI) + .contentType(MediaType.APPLICATION_JSON) + .bodyValue(visualization) + .retrieve() + .bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() { + }) + .doOnError(error -> { + throw new RestClientException("Failed to send POST request", error); + }) + .block(); } } diff --git a/core/src/test/java/cz/muni/pa165/service/CarComponentServiceTest.java b/core/src/test/java/cz/muni/pa165/service/CarComponentServiceTest.java index 00bfe0d805578a271a35892d40c25e8878c7dafb..de84639d90a6c1ea408c3286ae8a4c619225aeca 100644 --- a/core/src/test/java/cz/muni/pa165/service/CarComponentServiceTest.java +++ b/core/src/test/java/cz/muni/pa165/service/CarComponentServiceTest.java @@ -7,7 +7,7 @@ import cz.muni.pa165.data.repository.CarComponentRepository; import cz.muni.pa165.exceptions.ResourceNotFoundException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; import java.util.List; import java.util.Optional; @@ -19,12 +19,13 @@ import static org.mockito.Mockito.*; class CarComponentServiceTest { private CarComponentService carComponentService; private CarComponentRepository carComponentRepository; + private WebClient.Builder webClientBuilder; @BeforeEach void setUp() { carComponentRepository = mock(CarComponentRepository.class); - RestTemplate restTemplate = mock(RestTemplate.class); - carComponentService = new CarComponentService(carComponentRepository, restTemplate); + webClientBuilder = WebClient.builder(); + carComponentService = new CarComponentService(carComponentRepository, webClientBuilder); } @Test diff --git a/core/src/test/java/cz/muni/pa165/service/CarServiceTest.java b/core/src/test/java/cz/muni/pa165/service/CarServiceTest.java index 71dd68663fa4718674e1c4317c3610ee4eb1a7b9..23feaf494a07027c24851ef5827ef495f4dd424b 100644 --- a/core/src/test/java/cz/muni/pa165/service/CarServiceTest.java +++ b/core/src/test/java/cz/muni/pa165/service/CarServiceTest.java @@ -17,7 +17,7 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.function.client.WebClient; import java.util.Arrays; import java.util.List; @@ -33,25 +33,22 @@ import static org.mockito.Mockito.*; */ public class CarServiceTest { - @Mock private CarRepository carRepository; - - @Mock private DriverRepository driverRepository; - - @Mock private CarComponentRepository carComponentRepository; + private WebClient.Builder webClientBuilder; - @Mock - private RestTemplate restTemplate; - - @InjectMocks private CarService carService; private Car car; @BeforeEach public void setUp() { - MockitoAnnotations.openMocks(this); + carComponentRepository = mock(CarComponentRepository.class); + carRepository = mock(CarRepository.class); + driverRepository = mock(DriverRepository.class); + webClientBuilder = WebClient.builder(); + carService = new CarService(carRepository, driverRepository, carComponentRepository, webClientBuilder); + car = new Car(); car.setId(1L); } diff --git a/core/src/test/java/cz/muni/pa165/service/DriverServiceTest.java b/core/src/test/java/cz/muni/pa165/service/DriverServiceTest.java index 5a068711033d61450240baec7c405344d101c623..842f2678ada8eec16bb2ff1eee257e473ad7d532 100644 --- a/core/src/test/java/cz/muni/pa165/service/DriverServiceTest.java +++ b/core/src/test/java/cz/muni/pa165/service/DriverServiceTest.java @@ -9,7 +9,6 @@ import cz.muni.pa165.exceptions.BadRequestException; import cz.muni.pa165.exceptions.ResourceNotFoundException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.web.client.RestTemplate; import java.time.LocalDate; import java.util.HashSet;