From 6cff93045d285cf5ed30ef676a3d9e66c11d484f Mon Sep 17 00:00:00 2001 From: Henry Borasch <Henry.Borasch@sinc.de> Date: Mon, 17 Apr 2023 10:08:17 +0200 Subject: [PATCH] 978: removed spring-web - removed dependency - added OkHttpClient - created intermediate client to abstract between logic and HTTP handling - adjusted tests --- api/pom.xml | 4 - .../fitconnect/api/config/ResourcePaths.java | 10 +- .../api/exceptions/RestApiException.java | 19 ++ .../client/factory/ClientFactory.java | 75 +++--- .../client/subscriber/SubmissionReceiver.java | 3 +- .../client/SubscriberClientTest.java | 9 +- core/pom.xml | 9 +- .../core/auth/DefaultOAuthService.java | 42 ++-- .../core/events/EventLogApiService.java | 47 ++-- .../core/http/ApiRequestInterceptor.java | 21 +- .../fitconnect/core/http/HttpClient.java | 115 +++++++++ .../fitconnect/core/http/HttpHeaders.java | 10 + .../fitconnect/core/http/HttpResponse.java | 11 + .../fitko/fitconnect/core/http/MimeTypes.java | 9 + .../fitconnect/core/http/RestService.java | 50 +--- .../core/http/UserAgentInterceptor.java | 23 +- .../core/keys/PublicKeyService.java | 45 ++-- .../core/routing/RoutingApiService.java | 72 +++--- .../core/schema/SchemaResourceProvider.java | 10 +- .../core/submission/SubmissionApiService.java | 229 ++++++------------ .../core/auth/DefaultOAuthServiceTest.java | 8 +- .../core/events/EventLogApiServiceTest.java | 18 +- .../events/SecurityEventTokenServiceTest.java | 4 +- .../core/http/ProxyRestTemplateTest.java | 10 +- .../fitconnect/core/http/RestServiceTest.java | 10 +- .../core/http/RestTemplateTest.java | 44 +--- .../core/keys/PublicKeyServiceTest.java | 24 +- .../core/routing/RoutingApiServiceTest.java | 8 +- .../schema/SchemaResourceProviderTest.java | 39 +-- .../submission/SubmissionApiServiceTest.java | 30 ++- .../DefaultValidationServiceTest.java | 6 +- .../integrationtests/AuthenticationIT.java | 2 +- pom.xml | 6 - 33 files changed, 508 insertions(+), 514 deletions(-) create mode 100644 core/src/main/java/dev/fitko/fitconnect/core/http/HttpClient.java create mode 100644 core/src/main/java/dev/fitko/fitconnect/core/http/HttpHeaders.java create mode 100644 core/src/main/java/dev/fitko/fitconnect/core/http/HttpResponse.java create mode 100644 core/src/main/java/dev/fitko/fitconnect/core/http/MimeTypes.java diff --git a/api/pom.xml b/api/pom.xml index 60bee28c9..e8fee6738 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -30,10 +30,6 @@ <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> - <dependency> - <groupId>org.springframework</groupId> - <artifactId>spring-web</artifactId> - </dependency> </dependencies> <build> diff --git a/api/src/main/java/dev/fitko/fitconnect/api/config/ResourcePaths.java b/api/src/main/java/dev/fitko/fitconnect/api/config/ResourcePaths.java index 0f429301b..367aee5f1 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/config/ResourcePaths.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/config/ResourcePaths.java @@ -7,14 +7,14 @@ final class ResourcePaths { static final String AUTH_TOKEN_PATH = "/token"; - static final String DESTINATIONS_PATH = "/v1/destinations/{destinationId}"; - static final String DESTINATIONS_KEY_PATH = "/v1/destinations/{destinationId}/keys/{kid}"; + static final String DESTINATIONS_PATH = "/v1/destinations/%s"; + static final String DESTINATIONS_KEY_PATH = "/v1/destinations/%s/keys/%s"; - static final String EVENTS_PATH = "/v1/cases/{caseId}/events"; + static final String EVENTS_PATH = "/v1/cases/%s/events"; - static final String SUBMISSION_PATH = "/v1/submissions/{submissionId}"; + static final String SUBMISSION_PATH = "/v1/submissions/%s"; static final String SUBMISSIONS_PATH = "/v1/submissions"; - static final String SUBMISSION_ATTACHMENT_PATH = "/v1/submissions/{submissionId}/attachments/{attachmentId}"; + static final String SUBMISSION_ATTACHMENT_PATH = "/v1/submissions/%s/attachments/%s"; static final String ROUTING_AREA_PATH = "/v1/areas"; static final String ROUTING_ROUTE_PATH = "/v1/routes"; diff --git a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/RestApiException.java b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/RestApiException.java index 6fdfc7cd3..ef121c601 100644 --- a/api/src/main/java/dev/fitko/fitconnect/api/exceptions/RestApiException.java +++ b/api/src/main/java/dev/fitko/fitconnect/api/exceptions/RestApiException.java @@ -2,11 +2,30 @@ package dev.fitko.fitconnect.api.exceptions; public class RestApiException extends RuntimeException { + private int statusCode = 400; + public RestApiException(final String errorMessage, final Throwable error) { super(errorMessage, error); } + public RestApiException(final String errorMessage, final Throwable error, final int statusCode) { + super(errorMessage, error); + this.statusCode = statusCode; + } + public RestApiException(final String errorMessage) { super(errorMessage); } + + public RestApiException(final String errorMessage, int statusCode) { + super(errorMessage); + } + + public int getStatusCode() { + return statusCode; + } + + public boolean isNotFound() { + return this.statusCode == 404; + } } diff --git a/client/src/main/java/dev/fitko/fitconnect/client/factory/ClientFactory.java b/client/src/main/java/dev/fitko/fitconnect/client/factory/ClientFactory.java index 849f8bc39..856c8c6a3 100644 --- a/client/src/main/java/dev/fitko/fitconnect/client/factory/ClientFactory.java +++ b/client/src/main/java/dev/fitko/fitconnect/client/factory/ClientFactory.java @@ -34,6 +34,7 @@ import dev.fitko.fitconnect.core.crypto.JWECryptoService; import dev.fitko.fitconnect.core.events.EventLogApiService; import dev.fitko.fitconnect.core.events.EventLogVerifier; import dev.fitko.fitconnect.core.events.SecurityEventTokenService; +import dev.fitko.fitconnect.core.http.HttpClient; import dev.fitko.fitconnect.core.http.RestService; import dev.fitko.fitconnect.core.keys.PublicKeyService; import dev.fitko.fitconnect.core.routing.RouteVerifier; @@ -44,7 +45,6 @@ import dev.fitko.fitconnect.core.util.CertificateLoader; import dev.fitko.fitconnect.core.validation.DefaultValidationService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.web.client.RestTemplate; import org.yaml.snakeyaml.Yaml; import java.io.IOException; @@ -102,6 +102,7 @@ public final class ClientFactory { return new SubscriberClient(subscriber, submissionReceiver); } + /** * Create a new {@link RoutingClient} to find destinations and services that is automatically configured via a provided {@link ApplicationConfig}. * @@ -112,74 +113,74 @@ public final class ClientFactory { checkNotNull(config); LOGGER.info("Initializing routing client ..."); - final RestTemplate restTemplate = getRestTemplate(config, loadBuildInfo()); - final SchemaProvider schemaProvider = getSchemaProvider(restTemplate, config.getSubmissionDataSchemaPath()); - final OAuthService authService = getSenderConfiguredAuthService(config, restTemplate); + final HttpClient httpClient = getHttpClient(config, loadBuildInfo()); + final SchemaProvider schemaProvider = getSchemaProvider(httpClient, config.getSubmissionDataSchemaPath()); + final OAuthService authService = getSenderConfiguredAuthService(config, httpClient); final MessageDigestService messageDigestService = getMessageDigestService(); final ValidationService validator = getValidationService(config, schemaProvider, messageDigestService); - final SubmissionService submissionService = getSubmissionService(config, restTemplate, authService); - final KeyService keyService = getKeyService(config, restTemplate, authService, submissionService, validator); + final SubmissionService submissionService = getSubmissionService(config, httpClient, authService); + final KeyService keyService = getKeyService(config, httpClient, authService, submissionService, validator); final RouteVerifier routeVerifier = getRouteVerifier(keyService, validator); - final RoutingService routingService = getRoutingService(config, restTemplate); + final RoutingService routingService = getRoutingService(config, httpClient); return new RoutingClient(routingService, routeVerifier); } private static Sender getSender(final ApplicationConfig config, final BuildInfo buildInfo) { - final RestTemplate restTemplate = getRestTemplate(config, buildInfo); - final SchemaProvider schemaProvider = getSchemaProvider(restTemplate, config.getSubmissionDataSchemaPath()); + final HttpClient httpClient = getHttpClient(config, buildInfo); + final SchemaProvider schemaProvider = getSchemaProvider(httpClient, config.getSubmissionDataSchemaPath()); final MessageDigestService messageDigestService = getMessageDigestService(); final CryptoService cryptoService = getCryptoService(messageDigestService); final ValidationService validator = getValidationService(config, schemaProvider, messageDigestService); - final OAuthService authService = getSenderConfiguredAuthService(config, restTemplate); + final OAuthService authService = getSenderConfiguredAuthService(config, httpClient); - final SubmissionService submissionService = getSubmissionService(config, restTemplate, authService); - final KeyService keyService = getKeyService(config, restTemplate, authService, submissionService, validator); + final SubmissionService submissionService = getSubmissionService(config, httpClient, authService); + final KeyService keyService = getKeyService(config, httpClient, authService, submissionService, validator); final EventLogVerificationService eventLogVerifier = getEventLogVerifier(keyService, validator); - final EventLogService eventLogService = getEventLogService(config, restTemplate, eventLogVerifier, authService); + final EventLogService eventLogService = getEventLogService(config, httpClient, eventLogVerifier, authService); return new SubmissionSender(submissionService, eventLogService, cryptoService, validator, keyService); } private static Subscriber getSubscriber(final ApplicationConfig config, final BuildInfo buildInfo) { - final RestTemplate restTemplate = getRestTemplate(config, buildInfo); - final SchemaProvider schemaProvider = getSchemaProvider(restTemplate, config.getSubmissionDataSchemaPath()); + final HttpClient httpClient = getHttpClient(config, buildInfo); + final SchemaProvider schemaProvider = getSchemaProvider(httpClient, config.getSubmissionDataSchemaPath()); final MessageDigestService messageDigestService = getMessageDigestService(); final CryptoService cryptoService = getCryptoService(messageDigestService); final ValidationService validator = getValidationService(config, schemaProvider, messageDigestService); - final OAuthService authService = getSubscriberConfiguredAuthService(config, restTemplate); + final OAuthService authService = getSubscriberConfiguredAuthService(config, httpClient); - final SubmissionService submissionService = getSubmissionService(config, restTemplate, authService); - final KeyService keyService = getKeyService(config, restTemplate, authService, submissionService, validator); + final SubmissionService submissionService = getSubmissionService(config, httpClient, authService); + final KeyService keyService = getKeyService(config, httpClient, authService, submissionService, validator); final EventLogVerificationService eventLogVerifier = getEventLogVerifier(keyService, validator); - final EventLogService eventLogService = getEventLogService(config, restTemplate, eventLogVerifier, authService); + final EventLogService eventLogService = getEventLogService(config, httpClient, eventLogVerifier, authService); final SecurityEventService setService = getSecurityEventTokenService(config, validator); return new SubmissionSubscriber(submissionService, eventLogService, cryptoService, validator, setService); } - private static OAuthService getSenderConfiguredAuthService(final ApplicationConfig config, final RestTemplate restTemplate) { + private static OAuthService getSenderConfiguredAuthService(final ApplicationConfig config, final HttpClient httpClient) { final String clientId = config.getSenderConfig().getClientId(); final String clientSecret = config.getSenderConfig().getClientSecret(); - return new DefaultOAuthService(restTemplate, clientId, clientSecret, config.getOAuthTokenEndpoint()); + return new DefaultOAuthService(httpClient, clientId, clientSecret, config.getOAuthTokenEndpoint()); } - private static OAuthService getSubscriberConfiguredAuthService(final ApplicationConfig config, final RestTemplate restTemplate) { + private static OAuthService getSubscriberConfiguredAuthService(final ApplicationConfig config, final HttpClient httpClient) { final String clientId = config.getSubscriberConfig().getClientId(); final String clientSecret = config.getSubscriberConfig().getClientSecret(); - return new DefaultOAuthService(restTemplate, clientId, clientSecret, config.getOAuthTokenEndpoint()); + return new DefaultOAuthService(httpClient, clientId, clientSecret, config.getOAuthTokenEndpoint()); } - private static SubmissionService getSubmissionService(final ApplicationConfig config, final RestTemplate restTemplate, final OAuthService authService) { - return new SubmissionApiService(authService, restTemplate, config); + private static SubmissionService getSubmissionService(final ApplicationConfig config, final HttpClient httpClient, final OAuthService authService) { + return new SubmissionApiService(authService, httpClient, config); } - private static EventLogService getEventLogService(final ApplicationConfig config, final RestTemplate restTemplate, final EventLogVerificationService eventLogVerifier, final OAuthService authService) { - return new EventLogApiService(config, authService, restTemplate, eventLogVerifier); + private static EventLogService getEventLogService(final ApplicationConfig config, final HttpClient httpClient, final EventLogVerificationService eventLogVerifier, final OAuthService authService) { + return new EventLogApiService(config, authService, httpClient, eventLogVerifier); } private static ValidationService getValidationService(final ApplicationConfig config, final SchemaProvider schemaProvider, final MessageDigestService messageDigestService) { @@ -190,9 +191,9 @@ public final class ClientFactory { return new JWECryptoService(messageDigestService); } - private static RestTemplate getRestTemplate(final ApplicationConfig config, final BuildInfo buildInfo) { + private static HttpClient getHttpClient(final ApplicationConfig config, final BuildInfo buildInfo) { final RestService restService = new RestService(config.getHttpProxyHost(), config.getHttpProxyPort(), buildInfo); - return restService.getRestTemplate(); + return restService.getHttpClient(); } private static MessageDigestService getMessageDigestService() { @@ -206,24 +207,24 @@ public final class ClientFactory { return new SecurityEventTokenService(config, validationService, rsaKey); } - private static KeyService getKeyService(final ApplicationConfig config, final RestTemplate restTemplate, final OAuthService authService, final SubmissionService submissionService, final ValidationService validator) { - return new PublicKeyService(config, restTemplate, authService, submissionService, validator); + private static KeyService getKeyService(final ApplicationConfig config, final HttpClient httpClient, final OAuthService authService, final SubmissionService submissionService, final ValidationService validator) { + return new PublicKeyService(config, httpClient, authService, submissionService, validator); } private static EventLogVerificationService getEventLogVerifier(final KeyService keyService, final ValidationService validationService) { return new EventLogVerifier(keyService, validationService); } - private static SchemaProvider getSchemaProvider(RestTemplate restTemplate, String submissionDataSchemaPath) { + private static SchemaProvider getSchemaProvider(HttpClient httpClient, String submissionDataSchemaPath) { final List<String> setSchemaFiles = SchemaConfig.getSetSchemaFilePaths(SET_SCHEMA_DIR); final List<String> metadataSchemaFiles = SchemaConfig.getMetadataSchemaFileNames(METADATA_SCHEMA_DIR); final List<String> destinationSchemaFiles = SchemaConfig.getDestinationSchemaPaths(DESTINATION_SCHEMA_DIR); final SchemaResources schemaResources = new SchemaResources(setSchemaFiles, metadataSchemaFiles, destinationSchemaFiles, submissionDataSchemaPath); - return new SchemaResourceProvider(restTemplate, schemaResources); + return new SchemaResourceProvider(httpClient, schemaResources); } - private static RoutingService getRoutingService(final ApplicationConfig config, final RestTemplate restTemplate) { - return new RoutingApiService(config, restTemplate); + private static RoutingService getRoutingService(final ApplicationConfig config, final HttpClient httpClient) { + return new RoutingApiService(config, httpClient); } private static RouteVerifier getRouteVerifier(final KeyService keyService, final ValidationService validationService) { @@ -254,13 +255,13 @@ public final class ClientFactory { } private static void checkNotNull(final ApplicationConfig config) { - if(config == null){ + if (config == null) { throw new InitializationException("application config must not be null"); } } private static String getPrivateDecryptionKeyPathFromSubscriber(final SubscriberConfig subscriberConfig) { - if(subscriberConfig.getPrivateDecryptionKeyPaths().size() != 1){ + if (subscriberConfig.getPrivateDecryptionKeyPaths().size() != 1) { throw new InitializationException("Currently only one configured private key per subscriber is allowed !"); } final String keyPath = subscriberConfig.getPrivateDecryptionKeyPaths().get(0); diff --git a/client/src/main/java/dev/fitko/fitconnect/client/subscriber/SubmissionReceiver.java b/client/src/main/java/dev/fitko/fitconnect/client/subscriber/SubmissionReceiver.java index 14a3385d9..ab00bfff2 100644 --- a/client/src/main/java/dev/fitko/fitconnect/client/subscriber/SubmissionReceiver.java +++ b/client/src/main/java/dev/fitko/fitconnect/client/subscriber/SubmissionReceiver.java @@ -34,7 +34,6 @@ import dev.fitko.fitconnect.client.subscriber.model.ReceivedData; import dev.fitko.fitconnect.core.util.StopWatch; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.web.client.HttpClientErrorException; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -193,7 +192,7 @@ public class SubmissionReceiver { LOGGER.info("Downloading attachment {} took {}", metadata.getAttachmentId(), StopWatch.stopWithFormattedTime(startDownload)); return encryptedAttachment; } catch (final RestApiException e) { - if (e.getCause() instanceof HttpClientErrorException.NotFound) { + if (e.isNotFound()) { rejectSubmissionWithProblem(submission, new MissingAttachment(metadata.getAttachmentId())); } throw new SubmissionRequestException(e.getMessage(), e); diff --git a/client/src/test/java/dev/fitko/fitconnect/client/SubscriberClientTest.java b/client/src/test/java/dev/fitko/fitconnect/client/SubscriberClientTest.java index c8deaf7d0..ad116a730 100644 --- a/client/src/test/java/dev/fitko/fitconnect/client/SubscriberClientTest.java +++ b/client/src/test/java/dev/fitko/fitconnect/client/SubscriberClientTest.java @@ -43,8 +43,6 @@ import dev.fitko.fitconnect.core.crypto.JWECryptoService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; -import org.springframework.http.HttpStatus; -import org.springframework.web.client.HttpClientErrorException; import java.io.File; import java.io.IOException; @@ -62,7 +60,10 @@ import java.util.UUID; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.Mockito.anyLong; @@ -730,7 +731,7 @@ class SubscriberClientTest { when(subscriberMock.decryptStringContent(encryptionKey, submission.getEncryptedData())).thenReturn(dataPayload.getBytes()); when(subscriberMock.decryptStringContent(encryptionKey, submission.getEncryptedMetadata())).thenReturn(metadataBytes); when(subscriberMock.getAuthenticationTagsForEvent(any(), any())).thenReturn(authenticationTags); - when(subscriberMock.fetchAttachment(any(), any())).thenThrow(new RestApiException("Attachment download failed", HttpClientErrorException.create(HttpStatus.NOT_FOUND, "attachment not found", null, null, null))); + when(subscriberMock.fetchAttachment(any(), any())).thenThrow(new RestApiException("Attachment download failed", 404)); // When final SubmissionRequestException exception = assertThrows(SubmissionRequestException.class, () -> underTest.requestSubmission(submissionId)); diff --git a/core/pom.xml b/core/pom.xml index 3ed1acb16..44b2e3b05 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -30,10 +30,6 @@ <groupId>com.nimbusds</groupId> <artifactId>nimbus-jose-jwt</artifactId> </dependency> - <dependency> - <groupId>org.springframework</groupId> - <artifactId>spring-web</artifactId> - </dependency> <dependency> <groupId>com.networknt</groupId> <artifactId>json-schema-validator</artifactId> @@ -51,6 +47,11 @@ <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> </dependency> + <dependency> + <groupId>com.squareup.okhttp3</groupId> + <artifactId>okhttp</artifactId> + <version>4.10.0</version> + </dependency> <!-- Tests --> <dependency> diff --git a/core/src/main/java/dev/fitko/fitconnect/core/auth/DefaultOAuthService.java b/core/src/main/java/dev/fitko/fitconnect/core/auth/DefaultOAuthService.java index 908d0b2ce..d84d38fa1 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/auth/DefaultOAuthService.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/auth/DefaultOAuthService.java @@ -4,28 +4,28 @@ import dev.fitko.fitconnect.api.domain.auth.OAuthToken; import dev.fitko.fitconnect.api.exceptions.AuthenticationException; import dev.fitko.fitconnect.api.exceptions.RestApiException; import dev.fitko.fitconnect.api.services.auth.OAuthService; +import dev.fitko.fitconnect.core.http.HttpClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; +import java.io.IOException; import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; -import java.util.Collections; import java.util.HashMap; -import java.util.List; +import java.util.Map; +import static dev.fitko.fitconnect.core.http.HttpHeaders.ACCEPT; +import static dev.fitko.fitconnect.core.http.HttpHeaders.ACCEPT_CHARSET; +import static dev.fitko.fitconnect.core.http.HttpHeaders.CONTENT_TYPE; +import static dev.fitko.fitconnect.core.http.MimeTypes.APPLICATION_FORM_URLENCODED; +import static dev.fitko.fitconnect.core.http.MimeTypes.APPLICATION_JSON; import static java.util.stream.Collectors.joining; public class DefaultOAuthService implements OAuthService { private static final Logger LOGGER = LoggerFactory.getLogger(DefaultOAuthService.class); - private final RestTemplate restTemplate; + private final HttpClient httpClient; private final String tokenUrl; private final String clientId; @@ -34,8 +34,8 @@ public class DefaultOAuthService implements OAuthService { private OAuthToken currentToken; private LocalDateTime tokenExpirationTime; - public DefaultOAuthService(final RestTemplate restTemplate, final String clientId, final String clientSecret, final String authUrl) { - this.restTemplate = restTemplate; + public DefaultOAuthService(final HttpClient httpClient, final String clientId, final String clientSecret, final String authUrl) { + this.httpClient = httpClient; this.clientId = clientId; this.clientSecret = clientSecret; tokenUrl = authUrl; @@ -91,23 +91,21 @@ public class DefaultOAuthService implements OAuthService { } private OAuthToken performTokenRequest(final String requestBody) throws RestApiException { - final HttpHeaders headers = getHeaders(); - final HttpEntity<String> entity = new HttpEntity<>(requestBody, headers); + try { LOGGER.info("Sending authentication request"); - return restTemplate.exchange(tokenUrl, HttpMethod.POST, entity, OAuthToken.class).getBody(); - } catch (final RestClientException e) { + return this.httpClient.post(tokenUrl, getHeaders(), requestBody, OAuthToken.class).getBody(); + } catch (final IOException e) { LOGGER.error(e.getMessage(), e); throw new RestApiException("Could not retrieve OAuth token", e); } } - private HttpHeaders getHeaders() { - final var headers = new HttpHeaders(); - headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); - headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); - headers.setAcceptCharset(List.of(StandardCharsets.UTF_8)); - return headers; - } + private Map<String, String> getHeaders() { + return new HashMap<>(Map.of( + ACCEPT, APPLICATION_JSON, + CONTENT_TYPE, APPLICATION_FORM_URLENCODED, + ACCEPT_CHARSET, StandardCharsets.UTF_8.toString())); + } } diff --git a/core/src/main/java/dev/fitko/fitconnect/core/events/EventLogApiService.java b/core/src/main/java/dev/fitko/fitconnect/core/events/EventLogApiService.java index 7284f40a7..37faa6e5f 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/events/EventLogApiService.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/events/EventLogApiService.java @@ -17,19 +17,19 @@ import dev.fitko.fitconnect.api.exceptions.SubmitEventNotFoundException; import dev.fitko.fitconnect.api.services.auth.OAuthService; import dev.fitko.fitconnect.api.services.events.EventLogService; import dev.fitko.fitconnect.api.services.events.EventLogVerificationService; +import dev.fitko.fitconnect.core.http.HttpClient; +import dev.fitko.fitconnect.core.http.HttpHeaders; +import dev.fitko.fitconnect.core.http.MimeTypes; import dev.fitko.fitconnect.core.util.EventLogUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; +import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.Comparator; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.UUID; import java.util.stream.Collectors; @@ -43,20 +43,19 @@ import static dev.fitko.fitconnect.core.util.EventLogUtil.mapEventLogToEntries; public class EventLogApiService implements EventLogService { private static final Logger LOGGER = LoggerFactory.getLogger(EventLogApiService.class); - public static final MediaType MEDIA_TYPE_JOSE = MediaType.parseMediaType("application/jose"); private final ApplicationConfig config; private final OAuthService authService; - private final RestTemplate restTemplate; + private final HttpClient httpClient; private final EventLogVerificationService eventLogVerifier; public EventLogApiService(final ApplicationConfig config, final OAuthService authService, - final RestTemplate restTemplate, + final HttpClient httpClient, final EventLogVerificationService eventLogVerifier) { this.config = config; this.authService = authService; - this.restTemplate = restTemplate; + this.httpClient = httpClient; this.eventLogVerifier = eventLogVerifier; } @@ -111,33 +110,29 @@ public class EventLogApiService implements EventLogService { @Override public void sendEvent(final UUID caseId, final String signedAndSerializedSET) { - final String url = config.getEventsEndpoint(); - final HttpHeaders headers = getHttpHeaders(MEDIA_TYPE_JOSE); - final HttpEntity<String> entity = new HttpEntity<>(signedAndSerializedSET, headers); + final String url = String.format(config.getEventsEndpoint(), caseId); try { - restTemplate.exchange(url, HttpMethod.POST, entity, Void.class, caseId); - } catch (final RestClientException e) { + this.httpClient.post(url, getHttpHeaders(MimeTypes.APPLICATION_JOSE), signedAndSerializedSET, Void.class); + } catch (final IOException e) { throw new RestApiException("Sending event failed", e); } } private EventLog loadEventLog(final UUID caseId) { - final String url = config.getEventsEndpoint(); - final HttpHeaders headers = getHttpHeaders(MediaType.APPLICATION_JSON); - final HttpEntity<String> entity = new HttpEntity<>(headers); + final String url = String.format(config.getEventsEndpoint(), caseId); try { - return restTemplate.exchange(url, HttpMethod.GET, entity, EventLog.class, caseId).getBody(); - } catch (final RestClientException e) { + return this.httpClient.get(url, getHttpHeaders(MimeTypes.APPLICATION_JSON), EventLog.class).getBody(); + } catch (final IOException e) { throw new EventLogException("EventLog query failed", e); } } - private HttpHeaders getHttpHeaders(final MediaType mediaType) { - final var headers = new HttpHeaders(); - headers.setBearerAuth(authService.getCurrentToken().getAccessToken()); - headers.setContentType(mediaType); - headers.setAcceptCharset(List.of(StandardCharsets.UTF_8)); - return headers; + private Map<String, String> getHttpHeaders(final String mediaType) { + + return new HashMap<>(Map.of( + HttpHeaders.AUTHORIZATION, "Bearer " + authService.getCurrentToken().getAccessToken(), + HttpHeaders.CONTENT_TYPE, mediaType, + HttpHeaders.ACCEPT_CHARSET, StandardCharsets.UTF_8.toString())); } private SubmissionStatus getVerifiedStatus(final ValidationContext validationContext, final SignedJWT latestEvent) { diff --git a/core/src/main/java/dev/fitko/fitconnect/core/http/ApiRequestInterceptor.java b/core/src/main/java/dev/fitko/fitconnect/core/http/ApiRequestInterceptor.java index d4bbd501e..1cf88cfb5 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/http/ApiRequestInterceptor.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/http/ApiRequestInterceptor.java @@ -1,25 +1,28 @@ package dev.fitko.fitconnect.core.http; +import okhttp3.Interceptor; +import okhttp3.Request; +import okhttp3.Response; +import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.http.HttpRequest; -import org.springframework.http.client.ClientHttpRequestExecution; -import org.springframework.http.client.ClientHttpRequestInterceptor; -import org.springframework.http.client.ClientHttpResponse; import java.io.IOException; /** * Intercepts HTTP calls and logs the request url */ -public class ApiRequestInterceptor implements ClientHttpRequestInterceptor { +public class ApiRequestInterceptor implements Interceptor { private static final Logger LOGGER = LoggerFactory.getLogger(ApiRequestInterceptor.class); + @NotNull @Override - public ClientHttpResponse intercept(final HttpRequest req, final byte[] reqBody, - final ClientHttpRequestExecution ex) throws IOException { - LOGGER.info("{}", req.getURI()); - return ex.execute(req, reqBody); + public Response intercept(@NotNull Chain chain) throws IOException { + + Request request = chain.request(); + LOGGER.info("{}", request.url()); + + return chain.proceed(request); } } diff --git a/core/src/main/java/dev/fitko/fitconnect/core/http/HttpClient.java b/core/src/main/java/dev/fitko/fitconnect/core/http/HttpClient.java new file mode 100644 index 000000000..ebf7f4c3b --- /dev/null +++ b/core/src/main/java/dev/fitko/fitconnect/core/http/HttpClient.java @@ -0,0 +1,115 @@ +package dev.fitko.fitconnect.core.http; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import dev.fitko.fitconnect.api.exceptions.RestApiException; +import okhttp3.Headers; +import okhttp3.Interceptor; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; + +import java.io.IOException; +import java.net.Proxy; +import java.util.List; +import java.util.Map; + +public class HttpClient { + + private final OkHttpClient httpClient; + private final ObjectMapper objectMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + private final boolean throwExceptionsOnFailure; + + public HttpClient(boolean throwExceptionsOnFailure) { + this.httpClient = new OkHttpClient(); + this.throwExceptionsOnFailure = throwExceptionsOnFailure; + } + + public HttpClient(boolean throwExceptionsOnFailure, List<Interceptor> interceptors) { + this.httpClient = builderWithInterceptors(interceptors).build(); + this.throwExceptionsOnFailure = throwExceptionsOnFailure; + } + + public HttpClient(boolean throwExceptionsOnFailure, List<Interceptor> interceptors, Proxy proxy) { + this.httpClient = builderWithInterceptors(interceptors).proxy(proxy).build(); + this.throwExceptionsOnFailure = throwExceptionsOnFailure; + } + + private OkHttpClient.Builder builderWithInterceptors(List<Interceptor> interceptors) { + + OkHttpClient.Builder builder = new OkHttpClient.Builder(); + interceptors.forEach(builder::addInterceptor); + + return builder; + } + + public <R> HttpResponse<R> get(String url, Class<R> responseType) throws IOException { + return get(url, Map.of(), responseType); + } + + public <R> HttpResponse<R> get(String url, Map<String, String> headers, Class<R> responseType) throws IOException { + + Request request = new Request.Builder() + .url(url) + .get() + .headers(Headers.of(headers)) + .build(); + + try (Response response = this.httpClient.newCall(request).execute()) { + return this.evaluateStatusAndRespond(response, responseType); + } + } + + public <P, R> HttpResponse<R> post(String url, P httpPayload, Class<R> responseType) throws IOException { + return post(url, Map.of(), httpPayload, responseType); + } + + public <P, R> HttpResponse<R> post(String url, Map<String, String> headers, P httpPayload, Class<R> responseType) throws IOException { + + RequestBody requestBody = RequestBody.create(this.objectMapper.writeValueAsString(httpPayload), MediaType.get(MimeTypes.APPLICATION_JSON)); + Request request = new Request.Builder() + .url(url) + .post(requestBody) + .headers(Headers.of(headers)) + .build(); + + try (Response response = this.httpClient.newCall(request).execute()) { + return this.evaluateStatusAndRespond(response, responseType); + } + } + + public <P, R> HttpResponse<R> put(String url, P httpPayload, Class<R> responseType) throws IOException { + return put(url, Map.of(), httpPayload, responseType); + } + + public <P, R> HttpResponse<R> put(String url, Map<String, String> headers, P httpPayload, Class<R> responseType) throws IOException { + + RequestBody requestBody = RequestBody.create(this.objectMapper.writeValueAsString(httpPayload), MediaType.get(MimeTypes.APPLICATION_JSON)); + Request request = new Request.Builder() + .url(url) + .put(requestBody) + .headers(Headers.of(headers)) + .build(); + + try (Response response = this.httpClient.newCall(request).execute()) { + return this.evaluateStatusAndRespond(response, responseType); + } + } + + private <R> HttpResponse<R> evaluateStatusAndRespond(Response response, Class<R> responseType) throws IOException { + + if (this.throwExceptionsOnFailure && !response.isSuccessful()) { + throw new RestApiException("The Request failed.", response.code()); + } + + ResponseBody responseBody = response.body(); + if (responseBody == null) { + throw new IOException("Response body is null."); + } + + return new HttpResponse<R>(response.code(), this.objectMapper.readValue(responseBody.string(), responseType)); + } +} diff --git a/core/src/main/java/dev/fitko/fitconnect/core/http/HttpHeaders.java b/core/src/main/java/dev/fitko/fitconnect/core/http/HttpHeaders.java new file mode 100644 index 000000000..23e41078f --- /dev/null +++ b/core/src/main/java/dev/fitko/fitconnect/core/http/HttpHeaders.java @@ -0,0 +1,10 @@ +package dev.fitko.fitconnect.core.http; + +public class HttpHeaders { + + public final static String ACCEPT = "Accept"; + public final static String ACCEPT_CHARSET = "Accept-Charset"; + public final static String AUTHORIZATION = "Authorization"; + public final static String CONTENT_TYPE = "Content-Type"; + public final static String USER_AGENT = "User-Agent"; +} diff --git a/core/src/main/java/dev/fitko/fitconnect/core/http/HttpResponse.java b/core/src/main/java/dev/fitko/fitconnect/core/http/HttpResponse.java new file mode 100644 index 000000000..fe4d08c1d --- /dev/null +++ b/core/src/main/java/dev/fitko/fitconnect/core/http/HttpResponse.java @@ -0,0 +1,11 @@ +package dev.fitko.fitconnect.core.http; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class HttpResponse<T> { + private int statusCode; + private T body; +} diff --git a/core/src/main/java/dev/fitko/fitconnect/core/http/MimeTypes.java b/core/src/main/java/dev/fitko/fitconnect/core/http/MimeTypes.java new file mode 100644 index 000000000..846fe5310 --- /dev/null +++ b/core/src/main/java/dev/fitko/fitconnect/core/http/MimeTypes.java @@ -0,0 +1,9 @@ +package dev.fitko.fitconnect.core.http; + +public class MimeTypes { + + public final static String APPLICATION_FORM_URLENCODED = "application/x-www-form-urlencoded"; + public final static String APPLICATION_JOSE = "application/jose"; + public final static String APPLICATION_JSON = "application/json; charset=utf-8"; + public final static String APPLICATION_PROBLEM_JSON = "application/problem+json"; +} diff --git a/core/src/main/java/dev/fitko/fitconnect/core/http/RestService.java b/core/src/main/java/dev/fitko/fitconnect/core/http/RestService.java index 7711d95ad..91663ff29 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/http/RestService.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/http/RestService.java @@ -1,21 +1,14 @@ package dev.fitko.fitconnect.core.http; -import com.fasterxml.jackson.databind.ObjectMapper; import dev.fitko.fitconnect.api.config.BuildInfo; import dev.fitko.fitconnect.core.util.Strings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.http.client.ClientHttpRequestInterceptor; -import org.springframework.http.client.SimpleClientHttpRequestFactory; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.web.client.RestTemplate; import java.net.InetSocketAddress; import java.net.Proxy; import java.util.List; -import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES; - public class RestService { private static final Logger LOGGER = LoggerFactory.getLogger(RestService.class); @@ -34,44 +27,15 @@ public class RestService { this(null, 0, buildInfo); } - public RestTemplate getRestTemplate() { - return hasProxySet() ? getProxyRestTemplate() : getDefaultRestTemplate(); - } + public HttpClient getHttpClient() { - private RestTemplate getDefaultRestTemplate() { + if (hasProxySet()) { + LOGGER.info("Using proxy {}", this); + return new HttpClient(true, List.of(new ApiRequestInterceptor(), new UserAgentInterceptor(buildInfo)), + new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort))); + } LOGGER.info("No proxy configured"); - final RestTemplate restTemplate = new RestTemplate(); - setupTemplate(restTemplate); - return restTemplate; - } - - private RestTemplate getProxyRestTemplate() { - LOGGER.info("Using proxy {}", this); - final var requestFactory = new SimpleClientHttpRequestFactory(); - final var proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort)); - requestFactory.setProxy(proxy); - - final RestTemplate proxyRestTemplate = new RestTemplate(requestFactory); - setupTemplate(proxyRestTemplate); - return proxyRestTemplate; - } - - private void setMappingConverters(final RestTemplate restTemplate) { - final MappingJackson2HttpMessageConverter jacksonMessageConverter = new MappingJackson2HttpMessageConverter(); - jacksonMessageConverter.setObjectMapper(new ObjectMapper().configure(FAIL_ON_UNKNOWN_PROPERTIES, false)); - restTemplate.getMessageConverters().add(jacksonMessageConverter); - } - - private void setLoggingInterceptors(final RestTemplate restTemplate) { - final List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors(); - interceptors.add(new ApiRequestInterceptor()); - interceptors.add(new UserAgentInterceptor(buildInfo)); - restTemplate.setInterceptors(interceptors); - } - - private void setupTemplate(final RestTemplate restTemplate) { - setLoggingInterceptors(restTemplate); - setMappingConverters(restTemplate); + return new HttpClient(true, List.of(new ApiRequestInterceptor(), new UserAgentInterceptor(buildInfo))); } boolean hasProxySet() { diff --git a/core/src/main/java/dev/fitko/fitconnect/core/http/UserAgentInterceptor.java b/core/src/main/java/dev/fitko/fitconnect/core/http/UserAgentInterceptor.java index c6d0d4e71..6aa9ec61c 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/http/UserAgentInterceptor.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/http/UserAgentInterceptor.java @@ -1,15 +1,16 @@ package dev.fitko.fitconnect.core.http; import dev.fitko.fitconnect.api.config.BuildInfo; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpRequest; -import org.springframework.http.client.ClientHttpRequestExecution; -import org.springframework.http.client.ClientHttpRequestInterceptor; -import org.springframework.http.client.ClientHttpResponse; +import okhttp3.Interceptor; +import okhttp3.Request; +import okhttp3.Response; +import org.jetbrains.annotations.NotNull; import java.io.IOException; -public class UserAgentInterceptor implements ClientHttpRequestInterceptor { +import static dev.fitko.fitconnect.core.http.HttpHeaders.USER_AGENT; + +public class UserAgentInterceptor implements Interceptor { private final String productName; private final String productVersion; @@ -21,13 +22,13 @@ public class UserAgentInterceptor implements ClientHttpRequestInterceptor { this.commit = buildInfo.getCommit(); } + @NotNull @Override - public ClientHttpResponse intercept(final HttpRequest req, final byte[] reqBody, - final ClientHttpRequestExecution ex) throws IOException { + public Response intercept(@NotNull Chain chain) throws IOException { - req.getHeaders().set(HttpHeaders.USER_AGENT, String.format("%s/%s (commit:%s;os:%s)", - this.productName, this.productVersion, this.commit, System.getProperty("os.name"))); + Request request = chain.request().newBuilder().header(USER_AGENT,String.format("%s/%s (commit:%s;os:%s)", + this.productName, this.productVersion, this.commit, System.getProperty("os.name"))).build(); - return ex.execute(req, reqBody); + return chain.proceed(request); } } diff --git a/core/src/main/java/dev/fitko/fitconnect/core/keys/PublicKeyService.java b/core/src/main/java/dev/fitko/fitconnect/core/keys/PublicKeyService.java index 2445d98c3..cd1de61d6 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/keys/PublicKeyService.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/keys/PublicKeyService.java @@ -15,18 +15,18 @@ import dev.fitko.fitconnect.api.services.auth.OAuthService; import dev.fitko.fitconnect.api.services.keys.KeyService; import dev.fitko.fitconnect.api.services.submission.SubmissionService; import dev.fitko.fitconnect.api.services.validation.ValidationService; +import dev.fitko.fitconnect.core.http.HttpClient; +import dev.fitko.fitconnect.core.http.HttpHeaders; +import dev.fitko.fitconnect.core.http.MimeTypes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; +import java.io.IOException; import java.nio.charset.StandardCharsets; import java.text.ParseException; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.UUID; public class PublicKeyService implements KeyService { @@ -38,17 +38,17 @@ public class PublicKeyService implements KeyService { private final ApplicationConfig config; private final ValidationService validationService; private final SubmissionService submissionService; - private final RestTemplate restTemplate; + private final HttpClient httpClient; private final OAuthService authService; public PublicKeyService( final ApplicationConfig config, - final RestTemplate restTemplate, + final HttpClient httpClient, final OAuthService authService, final SubmissionService submissionService, final ValidationService validationService) { this.config = config; - this.restTemplate = restTemplate; + this.httpClient = httpClient; this.authService = authService; this.submissionService = submissionService; this.validationService = validationService; @@ -90,10 +90,11 @@ public class PublicKeyService implements KeyService { validateSignatureKey(signatureKey); return signatureKey; } + @Override public RSAKey getWellKnownKeysForSubmissionUrl(final String url, final String keyId) { final var requestUrl = !url.endsWith("/") ? url + config.getWellKnownKeysPath() : url; - final ApiJwkSet wellKnownKeys = performRequest(requestUrl, ApiJwkSet.class, getHeadersWithoutAuth(), keyId); + final ApiJwkSet wellKnownKeys = performRequest(requestUrl, ApiJwkSet.class, getHeadersWithoutAuth(), keyId); final RSAKey signatureKey = filterKeysById(keyId, wellKnownKeys.getKeys()); validateSignatureKey(signatureKey); return signatureKey; @@ -135,24 +136,26 @@ public class PublicKeyService implements KeyService { } } - private <T> T performRequest(final String url, final Class<T> responseType, final HttpHeaders headers, final Object... params) { - final HttpEntity<String> entity = new HttpEntity<>(headers); + private <T> T performRequest(final String url, final Class<T> responseType, final Map<String, String> headers, final Object... params) { try { - return restTemplate.exchange(url, HttpMethod.GET, entity, responseType, params).getBody(); - } catch (final RestClientException e) { + return this.httpClient.get(String.format(url, params), headers, responseType).getBody(); + } catch (final IOException e) { throw new RestApiException("Request failed", e); } } - private HttpHeaders getHeadersWithoutAuth() { - final var headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - headers.setAcceptCharset(List.of(StandardCharsets.UTF_8)); - return headers; + private Map<String, String> getHeadersWithoutAuth() { + + return new HashMap<>(Map.of( + HttpHeaders.CONTENT_TYPE, MimeTypes.APPLICATION_JSON, + HttpHeaders.ACCEPT_CHARSET, StandardCharsets.UTF_8.toString())); } - private HttpHeaders getHeaders() { + + private Map<String, String> getHeaders() { + final var headers = getHeadersWithoutAuth(); - headers.setBearerAuth(authService.getCurrentToken().getAccessToken()); + getHeadersWithoutAuth().put(HttpHeaders.AUTHORIZATION, "Bearer: " + authService.getCurrentToken().getAccessToken()); + return headers; } } diff --git a/core/src/main/java/dev/fitko/fitconnect/core/routing/RoutingApiService.java b/core/src/main/java/dev/fitko/fitconnect/core/routing/RoutingApiService.java index fe18cf66f..27d2fc5a8 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/routing/RoutingApiService.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/routing/RoutingApiService.java @@ -5,46 +5,45 @@ import dev.fitko.fitconnect.api.domain.model.route.AreaResult; import dev.fitko.fitconnect.api.domain.model.route.RouteResult; import dev.fitko.fitconnect.api.exceptions.RestApiException; import dev.fitko.fitconnect.api.services.routing.RoutingService; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.util.UriComponentsBuilder; +import dev.fitko.fitconnect.core.http.HttpClient; +import dev.fitko.fitconnect.core.http.HttpHeaders; +import dev.fitko.fitconnect.core.http.MimeTypes; +import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.function.Predicate; import static java.util.function.Predicate.not; public class RoutingApiService implements RoutingService { - private final RestTemplate restTemplate; + private final HttpClient httpClient; private final ApplicationConfig config; - public RoutingApiService(final ApplicationConfig config, final RestTemplate restTemplate) { + public RoutingApiService(final ApplicationConfig config, final HttpClient httpClient) { this.config = config; - this.restTemplate = restTemplate; + this.httpClient = httpClient; } @Override public AreaResult getAreas(final List<String> searchExpressions, final int offset, final int limit) { final String url = config.getAreaEndpoint(); - final HttpHeaders headers = getHttpHeaders(MediaType.parseMediaType("application/problem+json")); - final HttpEntity<String> entity = new HttpEntity<>(headers); - final UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUriString(url); - searchExpressions.forEach(search -> uriBuilder.queryParam("areaSearchexpression", search)); - uriBuilder.queryParam("offset", offset); - uriBuilder.queryParam("limit", limit); + List<String> queryParameters = new ArrayList<>(); + searchExpressions.forEach(search -> queryParameters.add("areaSearchexpression=" + search)); + queryParameters.add("offset=" + offset); + queryParameters.add("limit=" + limit); + String queryparameterString = String.join("&", queryParameters); try { - return restTemplate.exchange(uriBuilder.toUriString(), HttpMethod.GET, entity, AreaResult.class).getBody(); - } catch (final RestClientException e) { + return this.httpClient.get(url + "?" + queryparameterString, getHttpHeaders(MimeTypes.APPLICATION_PROBLEM_JSON), AreaResult.class).getBody(); + } catch (final IOException e) { throw new RestApiException("Area query failed", e); } } @@ -55,28 +54,24 @@ public class RoutingApiService implements RoutingService { testIfSearchCriterionIsSet(ars, ags, areaId); final String url = config.getRoutesEndpoint(); - final HttpHeaders headers = getHttpHeaders(MediaType.APPLICATION_JSON); - final HttpEntity<String> entity = new HttpEntity<>(headers); - - final UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUriString(url); - uriBuilder.queryParam("leikaKey", leikaKey); + List<String> queryParameters = new ArrayList<>(); if (ars != null) { - uriBuilder.queryParam("ars", ars); + queryParameters.add("ars=" + ars); } if (ags != null) { - uriBuilder.queryParam("ags", ags); + queryParameters.add("ags=" + ags); } if (areaId != null) { - uriBuilder.queryParam("areaId", areaId); + queryParameters.add("areaId=" + areaId); } - - uriBuilder.queryParam("offset", offset); - uriBuilder.queryParam("limit", limit); + queryParameters.add("offset=" + offset); + queryParameters.add("limit=" + limit); + String queryparameterString = String.join("&", queryParameters); try { - return restTemplate.exchange(uriBuilder.toUriString(), HttpMethod.GET, entity, RouteResult.class).getBody(); - } catch (final RestClientException e) { + return this.httpClient.get(url + "?" + queryparameterString, getHttpHeaders(MimeTypes.APPLICATION_JSON), RouteResult.class).getBody(); + } catch (final IOException e) { throw new RestApiException("Route query failed", e); } } @@ -84,11 +79,11 @@ public class RoutingApiService implements RoutingService { private static void testIfSearchCriterionIsSet(final String ars, final String ags, final String areaId) { final List<String> areaSearchCriteria = Arrays.asList(ars, ags, areaId); - if(areaSearchCriteria.stream().allMatch(CriterionEmpty())){ + if (areaSearchCriteria.stream().allMatch(CriterionEmpty())) { throw new RestApiException("At least one search criterion out of ags, ars or areaId must be set"); } - if(areaSearchCriteria.stream().filter(not(CriterionEmpty())).count() > 1){ + if (areaSearchCriteria.stream().filter(not(CriterionEmpty())).count() > 1) { throw new RestApiException("Only one of ars, ags or areaId must be specified."); } } @@ -97,10 +92,11 @@ public class RoutingApiService implements RoutingService { return criterion -> criterion == null || criterion.isEmpty(); } - private HttpHeaders getHttpHeaders(final MediaType mediaType) { - final var headers = new HttpHeaders(); - headers.setAccept(List.of(mediaType)); - headers.setAcceptCharset(List.of(StandardCharsets.UTF_8)); - return headers; + private Map<String, String> getHttpHeaders(final String mediaType) { + + return new HashMap<>(Map.of( + HttpHeaders.ACCEPT, mediaType, + HttpHeaders.ACCEPT_CHARSET, StandardCharsets.UTF_8.toString() + )); } } diff --git a/core/src/main/java/dev/fitko/fitconnect/core/schema/SchemaResourceProvider.java b/core/src/main/java/dev/fitko/fitconnect/core/schema/SchemaResourceProvider.java index d88766126..e2221dd75 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/schema/SchemaResourceProvider.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/schema/SchemaResourceProvider.java @@ -7,9 +7,9 @@ import dev.fitko.fitconnect.api.domain.schema.SchemaResources; import dev.fitko.fitconnect.api.exceptions.InitializationException; import dev.fitko.fitconnect.api.exceptions.SchemaNotFoundException; import dev.fitko.fitconnect.api.services.schema.SchemaProvider; +import dev.fitko.fitconnect.core.http.HttpClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.web.client.RestTemplate; import java.io.BufferedReader; import java.io.File; @@ -39,16 +39,16 @@ public class SchemaResourceProvider implements SchemaProvider { private final Map<URI, String> submissionDataSchemas; - private final RestTemplate restTemplate; + private final HttpClient httpClient; private static final ObjectMapper MAPPER = new ObjectMapper(); - public SchemaResourceProvider(final RestTemplate restTemplate, final SchemaResources schemaResources) { + public SchemaResourceProvider(final HttpClient httpClient, final SchemaResources schemaResources) { setSchemas = new HashMap<>(); metadataSchemas = new HashMap<>(); destinationSchemas = new HashMap<>(); submissionDataSchemas = new HashMap<>(); - this.restTemplate = restTemplate; + this.httpClient = httpClient; populateSetSchemas(schemaResources.getSetSchemaPaths()); populateMetadataSchemas(schemaResources.getMetadataSchemaPaths()); @@ -120,7 +120,7 @@ public class SchemaResourceProvider implements SchemaProvider { if (schemaUri.toString().matches("http.+")) { try { - return restTemplate.getForEntity(schemaUri, String.class).getBody(); + return this.httpClient.get(schemaUri.toString(), String.class).getBody(); } catch (Exception exception) { LOGGER.warn("Fetching schema from " + schemaUri + " failed, falling back to pre-stored version."); } diff --git a/core/src/main/java/dev/fitko/fitconnect/core/submission/SubmissionApiService.java b/core/src/main/java/dev/fitko/fitconnect/core/submission/SubmissionApiService.java index bbd10c6c9..debe3e74d 100644 --- a/core/src/main/java/dev/fitko/fitconnect/core/submission/SubmissionApiService.java +++ b/core/src/main/java/dev/fitko/fitconnect/core/submission/SubmissionApiService.java @@ -1,9 +1,6 @@ package dev.fitko.fitconnect.core.submission; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import dev.fitko.fitconnect.api.config.ApplicationConfig; -import dev.fitko.fitconnect.api.domain.auth.OAuthToken; import dev.fitko.fitconnect.api.domain.model.destination.Destination; import dev.fitko.fitconnect.api.domain.model.submission.CreateSubmission; import dev.fitko.fitconnect.api.domain.model.submission.Submission; @@ -13,214 +10,132 @@ import dev.fitko.fitconnect.api.domain.model.submission.SubmitSubmission; import dev.fitko.fitconnect.api.exceptions.RestApiException; import dev.fitko.fitconnect.api.services.auth.OAuthService; import dev.fitko.fitconnect.api.services.submission.SubmissionService; -import lombok.Builder; -import lombok.Getter; -import lombok.Setter; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.util.UriComponentsBuilder; +import dev.fitko.fitconnect.core.http.HttpClient; +import dev.fitko.fitconnect.core.http.HttpHeaders; +import dev.fitko.fitconnect.core.http.MimeTypes; +import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.UUID; -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; - public class SubmissionApiService implements SubmissionService { private final OAuthService authService; - private final RestTemplate restTemplate; + private final HttpClient httpClient; private final ApplicationConfig config; - public SubmissionApiService(final OAuthService authService, final RestTemplate restTemplate, final ApplicationConfig config) { + public SubmissionApiService(final OAuthService authService, final HttpClient httpClient, final ApplicationConfig config) { this.authService = authService; - this.restTemplate = restTemplate; + this.httpClient = httpClient; this.config = config; } @Override public Destination getDestination(final UUID destinationID) throws RestApiException { - final RequestSettings requestSettings = RequestSettings.builder() - .url(config.getDestinationsEndpoint()) - .method(HttpMethod.GET) - .responseType(Destination.class) - .entity(getHttpEntity(getHeaders())) - .params(Map.of("destinationId", destinationID)) - .errorMessage("Could not get destination " + destinationID) - .build(); - return performRequest(requestSettings); + + final String url = String.format(config.getDestinationsEndpoint(), destinationID); + + try { + return this.httpClient.get(url, getHeaders(), Destination.class).getBody(); + + } catch (IOException e) { + throw new RestApiException("Could not get destination " + destinationID, e); + } } @Override public SubmissionForPickup announceSubmission(final CreateSubmission submission) throws RestApiException { - final RequestSettings requestSettings = RequestSettings.builder() - .url(config.getSubmissionsEndpoint()) - .method(HttpMethod.POST) - .responseType(SubmissionForPickup.class) - .entity(getHttpEntity(submission, getHeaders())) - .params(Collections.emptyMap()) - .errorMessage("Could not announce submission for destination " + submission.getDestinationId()) - .build(); - return performRequest(requestSettings); + + try { + return this.httpClient.post(config.getSubmissionsEndpoint(), getHeaders(), submission, SubmissionForPickup.class).getBody(); + } catch (IOException e) { + throw new RestApiException("Could not announce submission for destination " + submission.getDestinationId(), e); + } } @Override public void uploadAttachment(final UUID submissionId, final UUID attachmentId, final String encryptedAttachment) throws RestApiException { - final Map<String, Object> params = new HashMap<>(); - params.put("submissionId", submissionId); - params.put("attachmentId", attachmentId); - final RequestSettings requestSettings = RequestSettings.builder() - .url(config.getAttachmentEndpoint()) - .method(HttpMethod.PUT) - .responseType(Void.class) - .entity(getHttpEntity(encryptedAttachment, getHeaders("application/jose"))) - .params(params) - .errorMessage("Could not upload attachment") - .build(); - performRequest(requestSettings); + + final String url = String.format(config.getAttachmentEndpoint(), submissionId, attachmentId); + + try { + this.httpClient.put(url, getHeaders("application/jose"), encryptedAttachment, Void.class); + } catch (IOException e) { + throw new RestApiException("Could not upload attachment", e); + } } @Override public String getAttachment(final UUID submissionId, final UUID attachmentId) throws RestApiException { - final Map<String, Object> params = new HashMap<>(); - params.put("submissionId", submissionId); - params.put("attachmentId", attachmentId); - final RequestSettings requestSettings = RequestSettings.builder() - .url(config.getAttachmentEndpoint()) - .method(HttpMethod.GET) - .responseType(String.class) - .entity(getHttpEntity(getHeaders("application/jose"))) - .params(params) - .errorMessage("Could not get attachment " + attachmentId) - .build(); - return performRequest(requestSettings); + + final String url = String.format(config.getAttachmentEndpoint(), submissionId, attachmentId); + + try { + return this.httpClient.get(url, getHeaders("application/jose"), String.class).getBody(); + } catch (IOException e) { + throw new RestApiException("Could not get attachment " + attachmentId, e); + } } @Override public Submission sendSubmission(final SubmitSubmission submission) throws RestApiException { - final Map<String, Object> params = Map.of("submissionId", submission.getSubmissionId()); - final RequestSettings requestSettings = RequestSettings.builder() - .url(config.getSubmissionEndpoint()) - .method(HttpMethod.PUT) - .responseType(Submission.class) - .entity(getHttpEntity(submission, getHeaders())) - .params(params) - .errorMessage("Could not send submission " + submission.getSubmissionId()) - .build(); - return performRequest(requestSettings); + + final String url = String.format(config.getSubmissionEndpoint(), submission); + + try { + return this.httpClient.put(url, getHeaders(), submission, Submission.class).getBody(); + } catch (IOException e) { + throw new RestApiException("Could not send submission " + submission.getSubmissionId(), e); + } } @Override public SubmissionsForPickup pollAvailableSubmissions(final int offset, final int limit) throws RestApiException { - final String urlWithQueryParams = UriComponentsBuilder.fromHttpUrl(config.getSubmissionsEndpoint()) - .queryParam("limit", limit) - .queryParam("offset", offset) - .encode() - .toUriString(); - final RequestSettings requestSettings = RequestSettings.builder() - .url(urlWithQueryParams) - .method(HttpMethod.GET) - .responseType(SubmissionsForPickup.class) - .entity(getHttpEntity(getHeaders())) - .errorMessage("Could not poll for available submissions") - .build(); - return performRequest(requestSettings); + + final String urlWithQueryParams = config.getSubmissionsEndpoint() + "?limit=" + limit + "&offset=" + offset; + + try { + return this.httpClient.get(urlWithQueryParams, getHeaders(), SubmissionsForPickup.class).getBody(); + } catch (IOException e) { + throw new RestApiException("Could not poll for available submissions", e); + } } @Override public SubmissionsForPickup pollAvailableSubmissionsForDestination(final UUID destinationId, final int offset, final int limit) { - final String urlWithQueryParams = UriComponentsBuilder.fromHttpUrl(config.getSubmissionsEndpoint()) - .queryParam("destinationId", destinationId) - .queryParam("limit", limit) - .queryParam("offset", offset) - .encode() - .toUriString(); - final RequestSettings requestSettings = RequestSettings.builder() - .url(urlWithQueryParams) - .method(HttpMethod.GET) - .responseType(SubmissionsForPickup.class) - .entity(getHttpEntity(getHeaders())) - .errorMessage("Could not poll for available submissions on destination " + destinationId) - .build(); - return performRequest(requestSettings); - } - @Override - public Submission getSubmission(final UUID submissionId) throws RestApiException { - final Map<String, Object> params = Map.of("submissionId", submissionId); - final RequestSettings requestSettings = RequestSettings.builder() - .url(config.getSubmissionEndpoint()) - .method(HttpMethod.GET) - .responseType(Submission.class) - .entity(getHttpEntity(getHeaders())) - .params(params) - .errorMessage("Submission with id " + submissionId + " does not exist") - .build(); - return performRequest(requestSettings); - } + final String urlWithQueryParams = config.getSubmissionsEndpoint() + "?destinationId=" + destinationId + + "&limit=" + limit + "&offset=" + offset; - private <T> T performRequest(final RequestSettings requestSettings) throws RestApiException { - final String url = requestSettings.url; - final HttpMethod method = requestSettings.method; - final HttpEntity entity = requestSettings.entity; - final Class<T> responseType = requestSettings.responseType; - final Map<String, ?> params = requestSettings.params; try { - return restTemplate.exchange(url, method, entity, responseType, params).getBody(); - } catch (final RestClientException e) { - throw new RestApiException(e.getMessage(), e); + return this.httpClient.get(urlWithQueryParams, getHeaders(), SubmissionsForPickup.class).getBody(); + } catch (IOException e) { + throw new RestApiException("Could not poll for available submissions on destination " + destinationId, e); } } - private HttpEntity<String> getHttpEntity(final HttpHeaders headers) { - return getHttpEntity(null, headers); - } + @Override + public Submission getSubmission(final UUID submissionId) throws RestApiException { - private HttpEntity<String> getHttpEntity(final Object body, final HttpHeaders headers) { - if (body == null) { - return new HttpEntity<>(headers); - } try { - return getHttpEntity(new ObjectMapper().writeValueAsString(body), headers); - } catch (final JsonProcessingException e) { - throw new RestApiException("Request body could not be processed", e); + return this.httpClient.get(String.format(config.getSubmissionEndpoint(), submissionId), getHeaders(), Submission.class).getBody(); + } catch (IOException e) { + throw new RestApiException("Submission with id " + submissionId + " does not exist", e); } } - private HttpEntity<String> getHttpEntity(final String body, final HttpHeaders headers) { - return body == null ? new HttpEntity<>(headers) : new HttpEntity<>(body, headers); - } - - private HttpHeaders getHeaders() { - return getHeaders(APPLICATION_JSON_VALUE); + private Map<String, String> getHeaders() { + return getHeaders(MimeTypes.APPLICATION_JSON); } - private HttpHeaders getHeaders(final String contentType) { - final OAuthToken token = authService.getCurrentToken(); - final var headers = new HttpHeaders(); - headers.setBearerAuth(token.getAccessToken()); - headers.setContentType(MediaType.parseMediaType(contentType)); - headers.setAcceptCharset(List.of(StandardCharsets.UTF_8)); - return headers; - } + private Map<String, String> getHeaders(final String contentType) { - @Getter - @Setter - @Builder - private static class RequestSettings { - private String url; - private HttpMethod method; - private HttpEntity entity; - private Class responseType; - private String errorMessage; - @Builder.Default - private Map<String, Object> params = new HashMap<>(); + return new HashMap<>(Map.of( + HttpHeaders.AUTHORIZATION, "Bearer: " + authService.getCurrentToken(), + HttpHeaders.CONTENT_TYPE, contentType, + HttpHeaders.ACCEPT_CHARSET, StandardCharsets.UTF_8.toString() + )); } } diff --git a/core/src/test/java/dev/fitko/fitconnect/core/auth/DefaultOAuthServiceTest.java b/core/src/test/java/dev/fitko/fitconnect/core/auth/DefaultOAuthServiceTest.java index 85189df78..dbddea4d7 100644 --- a/core/src/test/java/dev/fitko/fitconnect/core/auth/DefaultOAuthServiceTest.java +++ b/core/src/test/java/dev/fitko/fitconnect/core/auth/DefaultOAuthServiceTest.java @@ -5,10 +5,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import dev.fitko.fitconnect.api.domain.auth.OAuthToken; import dev.fitko.fitconnect.api.services.auth.OAuthService; import dev.fitko.fitconnect.core.RestEndpointBase; +import dev.fitko.fitconnect.core.http.HttpClient; +import dev.fitko.fitconnect.core.http.MimeTypes; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.http.MediaType; -import org.springframework.web.client.RestTemplate; import static com.github.tomakehurst.wiremock.client.WireMock.ok; import static com.github.tomakehurst.wiremock.client.WireMock.post; @@ -24,7 +24,7 @@ class DefaultOAuthServiceTest extends RestEndpointBase { public void setUp() { wireMockServer.resetMappings(); final var config = getTestConfig("http://localhost:" + wireMockServer.port()); - underTest = new DefaultOAuthService(new RestTemplate(), "id", "secret", config.getOAuthTokenEndpoint()); + underTest = new DefaultOAuthService(new HttpClient(true), "id", "secret", config.getOAuthTokenEndpoint()); } @Test @@ -74,7 +74,7 @@ class DefaultOAuthServiceTest extends RestEndpointBase { post(urlEqualTo("/token")) .willReturn(ok() .withBody(new ObjectMapper().writeValueAsString(token)) - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withHeader("Content-Type", MimeTypes.APPLICATION_JSON) .withStatus(200))); } } \ No newline at end of file diff --git a/core/src/test/java/dev/fitko/fitconnect/core/events/EventLogApiServiceTest.java b/core/src/test/java/dev/fitko/fitconnect/core/events/EventLogApiServiceTest.java index 787962c59..000635d95 100644 --- a/core/src/test/java/dev/fitko/fitconnect/core/events/EventLogApiServiceTest.java +++ b/core/src/test/java/dev/fitko/fitconnect/core/events/EventLogApiServiceTest.java @@ -6,8 +6,8 @@ import com.github.tomakehurst.wiremock.http.ResponseDefinition; import dev.fitko.fitconnect.api.domain.auth.OAuthToken; import dev.fitko.fitconnect.api.domain.model.event.EventLog; import dev.fitko.fitconnect.api.domain.model.event.EventLogEntry; -import dev.fitko.fitconnect.api.domain.model.event.SubmissionStatus; import dev.fitko.fitconnect.api.domain.model.event.SubmissionState; +import dev.fitko.fitconnect.api.domain.model.event.SubmissionStatus; import dev.fitko.fitconnect.api.domain.model.event.authtags.AuthenticationTags; import dev.fitko.fitconnect.api.domain.validation.ValidationResult; import dev.fitko.fitconnect.api.exceptions.EventLogException; @@ -15,11 +15,11 @@ import dev.fitko.fitconnect.api.services.auth.OAuthService; import dev.fitko.fitconnect.api.services.events.EventLogService; import dev.fitko.fitconnect.api.services.events.EventLogVerificationService; import dev.fitko.fitconnect.core.RestEndpointBase; +import dev.fitko.fitconnect.core.http.HttpClient; +import dev.fitko.fitconnect.core.http.MimeTypes; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentMatchers; -import org.springframework.http.MediaType; -import org.springframework.web.client.RestTemplate; import java.util.Collections; import java.util.List; @@ -57,7 +57,7 @@ class EventLogApiServiceTest extends RestEndpointBase { authServiceMock = mock(OAuthService.class); verifierMock = mock(EventLogVerificationService.class); final var config = getTestConfig("http://localhost:" + wireMockServer.port()); - underTest = new EventLogApiService(config, authServiceMock, new RestTemplate(), verifierMock); + underTest = new EventLogApiService(config, authServiceMock, new HttpClient(true), verifierMock); } @Test @@ -83,7 +83,7 @@ class EventLogApiServiceTest extends RestEndpointBase { get(urlEqualTo(urlPath)) .willReturn(ok() .withBody(new ObjectMapper().writeValueAsString(expectedLog)) - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withHeader("Content-Type", MimeTypes.APPLICATION_JSON) .withStatus(200))); // When @@ -119,7 +119,7 @@ class EventLogApiServiceTest extends RestEndpointBase { get(urlEqualTo(urlPath)) .willReturn(ok() .withBody(new ObjectMapper().writeValueAsString(expectedLog)) - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withHeader("Content-Type", MimeTypes.APPLICATION_JSON) .withStatus(200))); // When @@ -153,7 +153,7 @@ class EventLogApiServiceTest extends RestEndpointBase { get(urlEqualTo(urlPath)) .willReturn(ok() .withBody(new ObjectMapper().writeValueAsString(expectedLog)) - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withHeader("Content-Type", MimeTypes.APPLICATION_JSON) .withStatus(200))); // When @@ -187,7 +187,7 @@ class EventLogApiServiceTest extends RestEndpointBase { get(urlEqualTo(urlPath)) .willReturn(ok() .withBody(new ObjectMapper().writeValueAsString(expectedLog)) - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withHeader("Content-Type", MimeTypes.APPLICATION_JSON) .withStatus(200))); // When @@ -215,7 +215,7 @@ class EventLogApiServiceTest extends RestEndpointBase { post(urlEqualTo(urlPath)) .willReturn(ok() .withBody(serialisedSetEvent) - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withHeader("Content-Type", MimeTypes.APPLICATION_JSON) .withStatus(204))).getResponse(); // When diff --git a/core/src/test/java/dev/fitko/fitconnect/core/events/SecurityEventTokenServiceTest.java b/core/src/test/java/dev/fitko/fitconnect/core/events/SecurityEventTokenServiceTest.java index 4cd75dd84..c90c7c7e3 100644 --- a/core/src/test/java/dev/fitko/fitconnect/core/events/SecurityEventTokenServiceTest.java +++ b/core/src/test/java/dev/fitko/fitconnect/core/events/SecurityEventTokenServiceTest.java @@ -23,12 +23,12 @@ import dev.fitko.fitconnect.api.services.schema.SchemaProvider; import dev.fitko.fitconnect.api.services.validation.ValidationService; import dev.fitko.fitconnect.core.crypto.HashService; import dev.fitko.fitconnect.core.crypto.JWECryptoService; +import dev.fitko.fitconnect.core.http.HttpClient; import dev.fitko.fitconnect.core.schema.SchemaResourceProvider; import dev.fitko.fitconnect.core.util.CertificateLoader; import dev.fitko.fitconnect.core.validation.DefaultValidationService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.web.client.RestTemplate; import java.io.File; import java.io.IOException; @@ -68,7 +68,7 @@ class SecurityEventTokenServiceTest { final List<String> destinationSchemas = SchemaConfig.getDestinationSchemaPaths("/destination-schema"); final String submissionDataSchemaPath = "submission-data-test-schema"; final SchemaResources schemaResources = new SchemaResources(setSchemas, metadataSchemas, destinationSchemas, submissionDataSchemaPath); - final SchemaProvider schemaProvider = new SchemaResourceProvider(mock(RestTemplate.class), schemaResources); + final SchemaProvider schemaProvider = new SchemaResourceProvider(mock(HttpClient.class), schemaResources); validationService = new DefaultValidationService(config, new HashService(), schemaProvider, CertificateLoader.create().loadTrustedRootCertificates("trusted-test-root-certificates")); diff --git a/core/src/test/java/dev/fitko/fitconnect/core/http/ProxyRestTemplateTest.java b/core/src/test/java/dev/fitko/fitconnect/core/http/ProxyRestTemplateTest.java index 2a832c8e5..9c85e7460 100644 --- a/core/src/test/java/dev/fitko/fitconnect/core/http/ProxyRestTemplateTest.java +++ b/core/src/test/java/dev/fitko/fitconnect/core/http/ProxyRestTemplateTest.java @@ -6,8 +6,8 @@ import dev.fitko.fitconnect.api.config.BuildInfo; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.http.HttpMethod; -import org.springframework.web.client.RestTemplate; + +import java.io.IOException; import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; import static com.github.tomakehurst.wiremock.client.WireMock.get; @@ -32,7 +32,7 @@ public class ProxyRestTemplateTest { } @Test - void userAgentIsCorrect() { + void userAgentIsCorrect() throws IOException { WireMock.configureFor("localhost", 8080); wireMockServer.stubFor(get(urlEqualTo("/test")) @@ -44,9 +44,9 @@ public class ProxyRestTemplateTest { buildInfo.setProductName("productName"); buildInfo.setProductVersion("productVersion"); buildInfo.setCommit("commit"); - final RestTemplate restTemplate = new RestService(null, 0, buildInfo).getRestTemplate(); + final HttpClient httpClient = new RestService(null, 0, buildInfo).getHttpClient(); - restTemplate.exchange("http://localhost:8080/test", HttpMethod.GET, null, String.class); + httpClient.get("http://localhost:8080/test", String.class); verify(getRequestedFor(urlPathEqualTo("/test")) .withHeader("User-Agent", equalTo("productName/productVersion (commit:commit;os:" + System.getProperty("os.name") + ")"))); diff --git a/core/src/test/java/dev/fitko/fitconnect/core/http/RestServiceTest.java b/core/src/test/java/dev/fitko/fitconnect/core/http/RestServiceTest.java index 3b3830ec5..f3d61ae70 100644 --- a/core/src/test/java/dev/fitko/fitconnect/core/http/RestServiceTest.java +++ b/core/src/test/java/dev/fitko/fitconnect/core/http/RestServiceTest.java @@ -2,11 +2,7 @@ package dev.fitko.fitconnect.core.http; import dev.fitko.fitconnect.api.config.BuildInfo; import org.junit.jupiter.api.Test; -import org.springframework.http.client.InterceptingClientHttpRequestFactory; -import org.springframework.web.client.RestTemplate; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -23,12 +19,10 @@ class RestServiceTest { underTest = new RestService("http://testhost.de", 8080, new BuildInfo()); // When - final RestTemplate template = underTest.getRestTemplate(); + final HttpClient httpClient = underTest.getHttpClient(); // Then - assertNotNull(template); - assertThat(template.getRequestFactory().getClass(), equalTo(InterceptingClientHttpRequestFactory.class)); - + assertNotNull(httpClient); } @Test diff --git a/core/src/test/java/dev/fitko/fitconnect/core/http/RestTemplateTest.java b/core/src/test/java/dev/fitko/fitconnect/core/http/RestTemplateTest.java index 7a9c0bc41..3a4f59b3e 100644 --- a/core/src/test/java/dev/fitko/fitconnect/core/http/RestTemplateTest.java +++ b/core/src/test/java/dev/fitko/fitconnect/core/http/RestTemplateTest.java @@ -1,6 +1,5 @@ package dev.fitko.fitconnect.core.http; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import dev.fitko.fitconnect.api.config.BuildInfo; import dev.fitko.fitconnect.api.domain.model.metadata.Metadata; @@ -9,36 +8,28 @@ import dev.fitko.fitconnect.api.domain.model.metadata.data.MimeType; import dev.fitko.fitconnect.core.RestEndpointBase; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.http.MediaType; -import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.web.client.RestTemplate; +import java.io.IOException; import java.net.URI; import java.util.Collections; -import java.util.List; import java.util.Map; import static com.github.tomakehurst.wiremock.client.WireMock.get; import static com.github.tomakehurst.wiremock.client.WireMock.ok; import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertNotNull; public class RestTemplateTest extends RestEndpointBase { - private RestTemplate underTest; + private HttpClient underTest; @BeforeEach void setup() { - underTest = new RestService(null, 0, new BuildInfo()).getRestTemplate(); + underTest = new RestService(null, 0, new BuildInfo()).getHttpClient(); } @Test - void testRestCallForUnknownProperties() throws JsonProcessingException { + void testRestCallForUnknownProperties() throws IOException { // Given final var fakeBaseUrl = "http://localhost:" + wireMockServer.port(); @@ -49,39 +40,16 @@ public class RestTemplateTest extends RestEndpointBase { get(urlEqualTo("/test")) .willReturn(ok() .withBody(new ObjectMapper().writeValueAsString(metadataWithUnknownProperty)) - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withHeader("Content-Type", MimeTypes.APPLICATION_JSON) .withStatus(200))); // When - final Metadata response = underTest.getForObject(URI.create(fakeBaseUrl + "/test"), Metadata.class); + final Metadata response = underTest.get(URI.create(fakeBaseUrl + "/test").toString(), Metadata.class).getBody(); // Then assertNotNull(response); } - @Test - void testMessageConversionForUnknownProperties() throws JsonProcessingException { - - // Given - final List<HttpMessageConverter<?>> messageConverters = underTest.getMessageConverters(); - assertThat(messageConverters.size(), is(greaterThan(0))); - - // Get last set converter that's expected to be the jackson object mapper - final HttpMessageConverter<?> httpMessageConverter = messageConverters.get(messageConverters.size()-1); - assertThat(httpMessageConverter, instanceOf(MappingJackson2HttpMessageConverter.class)); - - final MappingJackson2HttpMessageConverter converter = (MappingJackson2HttpMessageConverter) httpMessageConverter; - - final ObjectMapper mapper = converter.getObjectMapper(); - - final Map<String, Map<String, Object>> metadataWithUnknownProperty = getMetadataWithUnknownSchemaProperty(); - - // Map object with an unknown property - final Metadata metadata = mapper.readValue(mapper.writeValueAsString(metadataWithUnknownProperty), Metadata.class); - - assertNotNull(metadata); - } - private static Map<String, Map<String, Object>> getMetadataWithUnknownSchemaProperty() { return Map.of( "$schemaFoo", Collections.emptyMap(), diff --git a/core/src/test/java/dev/fitko/fitconnect/core/keys/PublicKeyServiceTest.java b/core/src/test/java/dev/fitko/fitconnect/core/keys/PublicKeyServiceTest.java index 82e637c36..cc8bd1018 100644 --- a/core/src/test/java/dev/fitko/fitconnect/core/keys/PublicKeyServiceTest.java +++ b/core/src/test/java/dev/fitko/fitconnect/core/keys/PublicKeyServiceTest.java @@ -16,10 +16,10 @@ import dev.fitko.fitconnect.api.services.keys.KeyService; import dev.fitko.fitconnect.api.services.submission.SubmissionService; import dev.fitko.fitconnect.api.services.validation.ValidationService; import dev.fitko.fitconnect.core.RestEndpointBase; +import dev.fitko.fitconnect.core.http.HttpClient; +import dev.fitko.fitconnect.core.http.MimeTypes; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.http.MediaType; -import org.springframework.web.client.RestTemplate; import java.io.IOException; import java.text.ParseException; @@ -65,7 +65,7 @@ class PublicKeyServiceTest extends RestEndpointBase { config.setEnvironments(Map.of(envName, environment)); config.setActiveEnvironment(envName); - underTest = new PublicKeyService(config, new RestTemplate(), authServiceMock, submissionServiceMock, validationServiceMock); + underTest = new PublicKeyService(config, new HttpClient(true), authServiceMock, submissionServiceMock, validationServiceMock); } @Test @@ -86,7 +86,7 @@ class PublicKeyServiceTest extends RestEndpointBase { .withHeader("Authorization", containing("Bearer " + authToken.getAccessToken())) .willReturn(ok() .withBody(publicKeyJson) - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withHeader("Content-Type", MimeTypes.APPLICATION_JSON) .withStatus(200))); when(authServiceMock.getCurrentToken()).thenReturn(authToken); @@ -122,14 +122,14 @@ class PublicKeyServiceTest extends RestEndpointBase { config.setEnvironments(Map.of(envName, environment)); config.setActiveEnvironment(envName); - final PublicKeyService keyService = new PublicKeyService(config, new RestTemplate(), authServiceMock, submissionServiceMock, validationServiceMock); + final PublicKeyService keyService = new PublicKeyService(config, new HttpClient(true), authServiceMock, submissionServiceMock, validationServiceMock); wireMockServer.stubFor( get(urlEqualTo("/v1/destinations/" + destination.getDestinationId() + "/keys/123")) .withHeader("Authorization", containing("Bearer " + authToken.getAccessToken())) .willReturn(ok() .withBody(publicKeyJson) - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withHeader("Content-Type", MimeTypes.APPLICATION_JSON) .withStatus(200))); when(authServiceMock.getCurrentToken()).thenReturn(authToken); @@ -160,7 +160,7 @@ class PublicKeyServiceTest extends RestEndpointBase { get(urlEqualTo("/v1/destinations/" + destination.getDestinationId() + "/keys/123")) .willReturn(ok() .withBody(expectedSignatureKey) - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withHeader("Content-Type", MimeTypes.APPLICATION_JSON) .withStatus(200))); when(authServiceMock.getCurrentToken()).thenReturn(authToken); @@ -185,13 +185,13 @@ class PublicKeyServiceTest extends RestEndpointBase { final OAuthToken authToken = new OAuthToken(); authToken.setAccessToken("abc123"); - final JWKSet jwkSet = new JWKSet(JWK.parse( getResourceAsString("/public_signature_test_key.json"))); + final JWKSet jwkSet = new JWKSet(JWK.parse(getResourceAsString("/public_signature_test_key.json"))); wireMockServer.stubFor( get(urlEqualTo("/.well-known/jwks.json")) .willReturn(ok() .withBody(new ObjectMapper().writeValueAsString(jwkSet.toJSONObject())) - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withHeader("Content-Type", MimeTypes.APPLICATION_JSON) .withStatus(200))); when(authServiceMock.getCurrentToken()).thenReturn(authToken); @@ -215,13 +215,13 @@ class PublicKeyServiceTest extends RestEndpointBase { final OAuthToken authToken = new OAuthToken(); authToken.setAccessToken("abc123"); - final JWKSet jwkSet = new JWKSet(JWK.parse( getResourceAsString("/public_signature_test_key.json"))); + final JWKSet jwkSet = new JWKSet(JWK.parse(getResourceAsString("/public_signature_test_key.json"))); wireMockServer.stubFor( get(urlEqualTo("/.well-known/jwks.json")) .willReturn(ok() .withBody(new ObjectMapper().writeValueAsString(jwkSet.toJSONObject())) - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withHeader("Content-Type", MimeTypes.APPLICATION_JSON) .withStatus(200))); when(authServiceMock.getCurrentToken()).thenReturn(authToken); @@ -251,7 +251,7 @@ class PublicKeyServiceTest extends RestEndpointBase { get(urlEqualTo("/custom/path/.well-known/jwks.json")) .willReturn(ok() .withBody(new ObjectMapper().writeValueAsString(jwkSet.toJSONObject())) - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withHeader("Content-Type", MimeTypes.APPLICATION_JSON) .withStatus(200))); when(authServiceMock.getCurrentToken()).thenReturn(authToken); diff --git a/core/src/test/java/dev/fitko/fitconnect/core/routing/RoutingApiServiceTest.java b/core/src/test/java/dev/fitko/fitconnect/core/routing/RoutingApiServiceTest.java index 2c291cc79..2a7b4d20a 100644 --- a/core/src/test/java/dev/fitko/fitconnect/core/routing/RoutingApiServiceTest.java +++ b/core/src/test/java/dev/fitko/fitconnect/core/routing/RoutingApiServiceTest.java @@ -12,10 +12,10 @@ import dev.fitko.fitconnect.api.domain.model.route.RouteResult; import dev.fitko.fitconnect.api.exceptions.RestApiException; import dev.fitko.fitconnect.api.services.routing.RoutingService; import dev.fitko.fitconnect.core.RestEndpointBase; +import dev.fitko.fitconnect.core.http.HttpClient; +import dev.fitko.fitconnect.core.http.MimeTypes; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.http.MediaType; -import org.springframework.web.client.RestTemplate; import java.util.List; import java.util.Map; @@ -48,7 +48,7 @@ public class RoutingApiServiceTest extends RestEndpointBase { config.setEnvironments(Map.of(envName, environment)); config.setActiveEnvironment(envName); - underTest = new RoutingApiService(config, new RestTemplate()); + underTest = new RoutingApiService(config, new HttpClient(true)); } @Test @@ -99,7 +99,7 @@ public class RoutingApiServiceTest extends RestEndpointBase { get(urlEqualTo("/v1/routes?leikaKey=99123456760610&ars=064350014014&offset=0&limit=10")) .willReturn(ok() .withBody(new ObjectMapper().writeValueAsString(expectedResult)) - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withHeader("Content-Type", MimeTypes.APPLICATION_JSON) .withStatus(200))); // When diff --git a/core/src/test/java/dev/fitko/fitconnect/core/schema/SchemaResourceProviderTest.java b/core/src/test/java/dev/fitko/fitconnect/core/schema/SchemaResourceProviderTest.java index 17033c781..42a944043 100644 --- a/core/src/test/java/dev/fitko/fitconnect/core/schema/SchemaResourceProviderTest.java +++ b/core/src/test/java/dev/fitko/fitconnect/core/schema/SchemaResourceProviderTest.java @@ -6,18 +6,21 @@ import dev.fitko.fitconnect.api.config.SchemaConfig; import dev.fitko.fitconnect.api.domain.schema.SchemaResources; import dev.fitko.fitconnect.api.exceptions.SchemaNotFoundException; import dev.fitko.fitconnect.api.services.schema.SchemaProvider; +import dev.fitko.fitconnect.core.http.HttpClient; +import dev.fitko.fitconnect.core.http.HttpResponse; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.http.ResponseEntity; -import org.springframework.web.client.RestTemplate; +import java.io.IOException; import java.net.URI; import java.util.List; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; @@ -34,7 +37,7 @@ class SchemaResourceProviderTest { final List<String> destinationSchemas = SchemaConfig.getDestinationSchemaPaths("/destination-schema"); final String submissionDataPath = "submission-data-test-schema"; final SchemaResources schemaResources = new SchemaResources(setSchemas, metadataSchemas, destinationSchemas, submissionDataPath); - underTest = new SchemaResourceProvider(mock(RestTemplate.class), schemaResources); + underTest = new SchemaResourceProvider(mock(HttpClient.class), schemaResources); } @Test @@ -102,12 +105,12 @@ class SchemaResourceProviderTest { } @Test - void loadSubmissionDataSchemaFromRemote() { + void loadSubmissionDataSchemaFromRemote() throws IOException { - RestTemplate restTemplate = mock(RestTemplate.class); - when(restTemplate.getForEntity(eq(URI.create("https://test.json")), any())).thenReturn(ResponseEntity.ok("schema")); + HttpClient httpClient = mock(HttpClient.class); + when(httpClient.get(eq("https://test.json"), any())).thenReturn(new HttpResponse<>(200, "schema")); - SchemaResourceProvider schemaResourceProvider = new SchemaResourceProvider(restTemplate, + SchemaResourceProvider schemaResourceProvider = new SchemaResourceProvider(httpClient, new SchemaResources(List.of(), List.of(), List.of(), null)); String schema = schemaResourceProvider.loadSubmissionDataSchema(URI.create("https://test.json")); @@ -116,13 +119,13 @@ class SchemaResourceProviderTest { } @Test - void loadSubmissionDataSchemaFromRemoteFailedButFromMemoryWorks() { + void loadSubmissionDataSchemaFromRemoteFailedButFromMemoryWorks() throws IOException { - RestTemplate restTemplate = mock(RestTemplate.class); - when(restTemplate.getForEntity(eq(URI.create("https://schema.fitko.de/fim/s00000096_1.0.schema.json")), + HttpClient httpClient = mock(HttpClient.class); + when(httpClient.get(eq("https://schema.fitko.de/fim/s00000096_1.0.schema.json"), any())).thenThrow(new RuntimeException("Something went wrong!")); - SchemaResourceProvider schemaResourceProvider = new SchemaResourceProvider(restTemplate, + SchemaResourceProvider schemaResourceProvider = new SchemaResourceProvider(httpClient, new SchemaResources(List.of(), List.of(), List.of(), "submission-data-test-schema")); String schema = schemaResourceProvider.loadSubmissionDataSchema(URI.create("https://schema.fitko.de/fim/s00000096_1.0.schema.json")); @@ -131,13 +134,13 @@ class SchemaResourceProviderTest { } @Test - void loadSubmissionDataSchemaFromRemoteAndMemoryFailed() { + void loadSubmissionDataSchemaFromRemoteAndMemoryFailed() throws IOException { - RestTemplate restTemplate = mock(RestTemplate.class); - when(restTemplate.getForEntity(eq(URI.create("https://schema.fitko.de/fim/s00000096_1.0.schema.json")), + HttpClient httpClient = mock(HttpClient.class); + when(httpClient.get(eq("https://schema.fitko.de/fim/s00000096_1.0.schema.json"), any())).thenThrow(new RuntimeException("Something went wrong!")); - SchemaResourceProvider schemaResourceProvider = new SchemaResourceProvider(restTemplate, + SchemaResourceProvider schemaResourceProvider = new SchemaResourceProvider(httpClient, new SchemaResources(List.of(), List.of(), List.of(), null)); Exception exception = assertThrows(SchemaNotFoundException.class, @@ -149,7 +152,7 @@ class SchemaResourceProviderTest { @Test void loadSubmissionDataSchemaFromMemory() { - SchemaResourceProvider schemaResourceProvider = new SchemaResourceProvider(mock(RestTemplate.class), + SchemaResourceProvider schemaResourceProvider = new SchemaResourceProvider(mock(HttpClient.class), new SchemaResources(List.of(), List.of(), List.of(), "submission-data-test-schema")); String schema = schemaResourceProvider.loadSubmissionDataSchema(URI.create("urn:test:submission_data_schema.json")); @@ -160,7 +163,7 @@ class SchemaResourceProviderTest { @Test void loadSubmissionDataSchemaFromMemoryFailed() { - SchemaResourceProvider schemaResourceProvider = new SchemaResourceProvider(mock(RestTemplate.class), + SchemaResourceProvider schemaResourceProvider = new SchemaResourceProvider(mock(HttpClient.class), new SchemaResources(List.of(), List.of(), List.of(), null)); Exception exception = assertThrows(SchemaNotFoundException.class, diff --git a/core/src/test/java/dev/fitko/fitconnect/core/submission/SubmissionApiServiceTest.java b/core/src/test/java/dev/fitko/fitconnect/core/submission/SubmissionApiServiceTest.java index e257c31c9..b8aa4ce5b 100644 --- a/core/src/test/java/dev/fitko/fitconnect/core/submission/SubmissionApiServiceTest.java +++ b/core/src/test/java/dev/fitko/fitconnect/core/submission/SubmissionApiServiceTest.java @@ -15,12 +15,11 @@ import dev.fitko.fitconnect.api.domain.model.submission.SubmitSubmission; import dev.fitko.fitconnect.api.services.auth.OAuthService; import dev.fitko.fitconnect.api.services.submission.SubmissionService; import dev.fitko.fitconnect.core.RestEndpointBase; +import dev.fitko.fitconnect.core.http.HttpClient; +import dev.fitko.fitconnect.core.http.MimeTypes; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.web.client.RestTemplate; import java.util.HashSet; import java.util.List; @@ -46,7 +45,7 @@ import static org.mockito.Mockito.when; class SubmissionApiServiceTest extends RestEndpointBase { - private RestTemplate restTemplate; + private HttpClient httpClient; private OAuthService authServiceMock; private SubmissionService underTest; @@ -56,9 +55,9 @@ class SubmissionApiServiceTest extends RestEndpointBase { final var fakeBaseUrl = "http://localhost:" + wireMockServer.port(); final ApplicationConfig config = getTestConfig(fakeBaseUrl); - restTemplate = new RestTemplate(); + httpClient = new HttpClient(true); authServiceMock = Mockito.mock(OAuthService.class); - underTest = new SubmissionApiService(authServiceMock, restTemplate, config); + underTest = new SubmissionApiService(authServiceMock, httpClient, config); } @Test @@ -95,7 +94,7 @@ class SubmissionApiServiceTest extends RestEndpointBase { .withHeader("Authorization", containing("Bearer " + authToken.getAccessToken())) .willReturn(ok() .withBody(new ObjectMapper().writeValueAsString(expectedSubmission)) - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withHeader("Content-Type", MimeTypes.APPLICATION_JSON) .withStatus(200))); // When @@ -135,7 +134,7 @@ class SubmissionApiServiceTest extends RestEndpointBase { // Then verify(putRequestedFor(urlEqualTo(urlPath)).withHeader("Authorization", equalTo("Bearer abc"))); assertThat(response.getHeaders().getContentTypeHeader().mimeTypePart(), is("application/jose")); - assertEquals(response.getStatus(), HttpStatus.NO_CONTENT.value()); + assertEquals(response.getStatus(), MimeTypes.APPLICATION_JSON); } @Test @@ -168,7 +167,7 @@ class SubmissionApiServiceTest extends RestEndpointBase { assertThat(attachment, is(encryptedAttachment)); verify(getRequestedFor(urlEqualTo(urlPath)).withHeader("Authorization", equalTo("Bearer abc"))); assertThat(response.getHeaders().getContentTypeHeader().mimeTypePart(), is("application/jose")); - assertEquals(response.getStatus(), HttpStatus.OK.value()); + assertEquals(response.getStatus(), MimeTypes.APPLICATION_JSON); } @Test @@ -200,10 +199,9 @@ class SubmissionApiServiceTest extends RestEndpointBase { put(urlEqualTo(urlPath)) .willReturn(ok() .withBody(new ObjectMapper().writeValueAsString(expectedSubmission)) - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withHeader("Content-Type", MimeTypes.APPLICATION_JSON) .withStatus(200))).getResponse(); - // When final Submission submission = underTest.sendSubmission(submitSubmission); @@ -215,7 +213,7 @@ class SubmissionApiServiceTest extends RestEndpointBase { verify(putRequestedFor(urlEqualTo(urlPath)).withHeader("Authorization", equalTo("Bearer abc"))); assertThat(response.getHeaders().getContentTypeHeader().mimeTypePart(), is("application/json")); - assertEquals(response.getStatus(), HttpStatus.OK.value()); + assertEquals(response.getStatus(), 200); } @Test @@ -249,7 +247,7 @@ class SubmissionApiServiceTest extends RestEndpointBase { get(urlEqualTo(urlPath)) .willReturn(ok() .withBody(new ObjectMapper().writeValueAsString(expectedSubmissions)) - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withHeader("Content-Type", MimeTypes.APPLICATION_JSON) .withStatus(200))).getResponse(); // When @@ -281,7 +279,7 @@ class SubmissionApiServiceTest extends RestEndpointBase { get(urlEqualTo(urlPath)) .willReturn(ok() .withBody(new ObjectMapper().writeValueAsString(expectedSubmission)) - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withHeader("Content-Type", MimeTypes.APPLICATION_JSON) .withStatus(200))).getResponse(); // When @@ -309,7 +307,7 @@ class SubmissionApiServiceTest extends RestEndpointBase { get(urlEqualTo(urlPath)) .willReturn(ok() .withBody(new ObjectMapper().writeValueAsString(expectedDestination)) - .withHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE) + .withHeader("Content-Type", MimeTypes.APPLICATION_JSON) .withStatus(200))).getResponse(); // When final Destination destination = underTest.getDestination(expectedDestination.getDestinationId()); @@ -319,7 +317,7 @@ class SubmissionApiServiceTest extends RestEndpointBase { verify(getRequestedFor(urlEqualTo(urlPath)).withHeader("Authorization", equalTo("Bearer 123"))); } - private Set<SubmissionForPickup> generateSubmission(final UUID destinationId, final int count){ + private Set<SubmissionForPickup> generateSubmission(final UUID destinationId, final int count) { final Set<SubmissionForPickup> submissions = new HashSet<>(count); for (int i = 0; i < count; i++) { final SubmissionForPickup submission = new SubmissionForPickup(); diff --git a/core/src/test/java/dev/fitko/fitconnect/core/validation/DefaultValidationServiceTest.java b/core/src/test/java/dev/fitko/fitconnect/core/validation/DefaultValidationServiceTest.java index 42761009b..a25ada95b 100644 --- a/core/src/test/java/dev/fitko/fitconnect/core/validation/DefaultValidationServiceTest.java +++ b/core/src/test/java/dev/fitko/fitconnect/core/validation/DefaultValidationServiceTest.java @@ -50,6 +50,7 @@ import dev.fitko.fitconnect.api.domain.validation.ValidationResult; import dev.fitko.fitconnect.api.services.crypto.MessageDigestService; import dev.fitko.fitconnect.api.services.schema.SchemaProvider; import dev.fitko.fitconnect.core.crypto.HashService; +import dev.fitko.fitconnect.core.http.HttpClient; import dev.fitko.fitconnect.core.schema.SchemaResourceProvider; import dev.fitko.fitconnect.core.testutil.LogCaptor; import dev.fitko.fitconnect.core.util.CertificateLoader; @@ -57,7 +58,6 @@ import dev.fitko.fitconnect.jwkvalidator.exceptions.JWKValidationException; import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.web.client.RestTemplate; import java.io.IOException; import java.net.URI; @@ -92,7 +92,7 @@ class DefaultValidationServiceTest { private DefaultValidationService underTest; private MessageDigestService hashService; private static final LogCaptor logs = new LogCaptor(); - private final RestTemplate restTemplate = mock(RestTemplate.class); + private final HttpClient httpClient = mock(HttpClient.class); private SchemaProvider schemaProvider; @BeforeEach @@ -104,7 +104,7 @@ class DefaultValidationServiceTest { final List<String> destinationSchemas = SchemaConfig.getDestinationSchemaPaths("/destination-schema"); final String submissionDataSchemaPath = "submission-data-test-schema"; final SchemaResources schemaResources = new SchemaResources(setSchemas, metadataSchemas, destinationSchemas, submissionDataSchemaPath); - schemaProvider = new SchemaResourceProvider(restTemplate, schemaResources); + schemaProvider = new SchemaResourceProvider(httpClient, schemaResources); underTest = new DefaultValidationService(config, hashService, schemaProvider, CertificateLoader.create().loadTrustedRootCertificates("trusted-test-root-certificates")); } diff --git a/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/AuthenticationIT.java b/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/AuthenticationIT.java index 0da0e02ba..27432d7d1 100644 --- a/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/AuthenticationIT.java +++ b/integration-tests/src/test/java/dev/fitko/fitconnect/integrationtests/AuthenticationIT.java @@ -25,7 +25,7 @@ public class AuthenticationIT { final RestService restService = new RestService(new BuildInfo()); - final var authService = new DefaultOAuthService(restService.getRestTemplate(), clientId, secret, tokenUrl); + final var authService = new DefaultOAuthService(restService.getHttpClient(), clientId, secret, tokenUrl); // When final OAuthToken token = authService.getCurrentToken(); diff --git a/pom.xml b/pom.xml index 14e3ed226..1b55ce66c 100644 --- a/pom.xml +++ b/pom.xml @@ -68,7 +68,6 @@ <slf4j.version>2.0.7</slf4j.version> <jcommander.version>1.82</jcommander.version> <apache-tika.version>2.7.0</apache-tika.version> - <spring-web.version>5.3.26</spring-web.version> <snakeyaml.version>2.0</snakeyaml.version> <open-csv.version>5.7.1</open-csv.version> <json-schema-validator.version>1.0.79</json-schema-validator.version> @@ -159,11 +158,6 @@ <artifactId>nimbus-jose-jwt</artifactId> <version>${nimbus.version}</version> </dependency> - <dependency> - <groupId>org.springframework</groupId> - <artifactId>spring-web</artifactId> - <version>${spring-web.version}</version> - </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> -- GitLab