From 9a1b8d62b71fbf467e688ad1f0cd43512b2e4af0 Mon Sep 17 00:00:00 2001
From: Martin Vogel <martin.vogel@sinc.de>
Date: Wed, 22 Jun 2022 09:54:00 +0200
Subject: [PATCH] #414 Introduce client factory to be able to construct the
 client without guice

---
 .../submission/AvailableSubmissions.java      |  22 ++
 ...onResponse.java => CreatedSubmission.java} |   2 +-
 .../fitko/fitconnect/api/services/Sender.java |   7 +-
 .../java/de/fitko/fitconnect/TestRunner.java  |  40 ++--
 .../fitconnect/client/ClientFactory.java      |  80 +++++++
 .../fitconnect/client/FluentSenderClient.java | 218 ++++++++++++++++++
 .../fitko/fitconnect/client/SenderClient.java |  35 ++-
 .../dependency/ApplicationConfig.java         |   2 +-
 .../fitconnect/impl/SubmissionSender.java     |   6 +-
 .../impl/metadata/MetadataUploadService.java  |   2 +-
 10 files changed, 359 insertions(+), 55 deletions(-)
 create mode 100644 api/src/main/java/de/fitko/fitconnect/api/domain/model/submission/AvailableSubmissions.java
 rename api/src/main/java/de/fitko/fitconnect/api/domain/model/submission/{SubmissionResponse.java => CreatedSubmission.java} (91%)
 create mode 100644 client/src/main/java/de/fitko/fitconnect/client/ClientFactory.java
 create mode 100644 client/src/main/java/de/fitko/fitconnect/client/FluentSenderClient.java

diff --git a/api/src/main/java/de/fitko/fitconnect/api/domain/model/submission/AvailableSubmissions.java b/api/src/main/java/de/fitko/fitconnect/api/domain/model/submission/AvailableSubmissions.java
new file mode 100644
index 000000000..07dc7552d
--- /dev/null
+++ b/api/src/main/java/de/fitko/fitconnect/api/domain/model/submission/AvailableSubmissions.java
@@ -0,0 +1,22 @@
+package de.fitko.fitconnect.api.domain.model.submission;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Value;
+
+import java.util.List;
+
+@Value
+public class AvailableSubmissions {
+
+    @JsonProperty("count")
+    int count;
+
+    @JsonProperty("offset")
+    int offset;
+
+    @JsonProperty("totalCount")
+    int totalCount;
+
+    @JsonProperty("submissions")
+    List<CreatedSubmission> submissions;
+}
diff --git a/api/src/main/java/de/fitko/fitconnect/api/domain/model/submission/SubmissionResponse.java b/api/src/main/java/de/fitko/fitconnect/api/domain/model/submission/CreatedSubmission.java
similarity index 91%
rename from api/src/main/java/de/fitko/fitconnect/api/domain/model/submission/SubmissionResponse.java
rename to api/src/main/java/de/fitko/fitconnect/api/domain/model/submission/CreatedSubmission.java
index d15106e53..d07b2de50 100644
--- a/api/src/main/java/de/fitko/fitconnect/api/domain/model/submission/SubmissionResponse.java
+++ b/api/src/main/java/de/fitko/fitconnect/api/domain/model/submission/CreatedSubmission.java
@@ -6,7 +6,7 @@ import lombok.Value;
 import java.util.UUID;
 
 @Value
-public class SubmissionResponse {
+public class CreatedSubmission {
 
     @JsonProperty("destinationId")
     private final UUID destinationId;
diff --git a/api/src/main/java/de/fitko/fitconnect/api/services/Sender.java b/api/src/main/java/de/fitko/fitconnect/api/services/Sender.java
index f6db1e331..e54db66b7 100644
--- a/api/src/main/java/de/fitko/fitconnect/api/services/Sender.java
+++ b/api/src/main/java/de/fitko/fitconnect/api/services/Sender.java
@@ -6,7 +6,7 @@ import de.fitko.fitconnect.api.domain.model.metadata.Metadata;
 import de.fitko.fitconnect.api.domain.model.metadata.attachment.Attachment;
 import de.fitko.fitconnect.api.domain.model.metadata.data.Data;
 import de.fitko.fitconnect.api.domain.model.submission.SubmissionRequest;
-import de.fitko.fitconnect.api.domain.model.submission.SubmissionResponse;
+import de.fitko.fitconnect.api.domain.model.submission.CreatedSubmission;
 import de.fitko.fitconnect.api.domain.validation.ValidationResult;
 
 import java.io.File;
@@ -85,8 +85,7 @@ public interface Sender {
      * @param submission with a destinationId, a list of attachmentIds and a serviceType
      * @return the created submission
      */
-    Optional<SubmissionResponse> createSubmission(SubmissionRequest submission);
-
+    Optional<CreatedSubmission> createSubmission(SubmissionRequest submission);
 
     /**
      * Posts the announced {@link SubmissionRequest}
@@ -96,7 +95,7 @@ public interface Sender {
      *
      * @return the submission
      */
-    Optional<SubmissionResponse> sendSubmission(UUID submissionId, Metadata encryptedMetadata);
+    Optional<CreatedSubmission> sendSubmission(UUID submissionId, Metadata encryptedMetadata);
 
 
     void uploadAttachments(UUID submissionId, List<Attachment> encryptedAttachments);
diff --git a/client/src/main/java/de/fitko/fitconnect/TestRunner.java b/client/src/main/java/de/fitko/fitconnect/TestRunner.java
index 420774113..fee75c2bd 100644
--- a/client/src/main/java/de/fitko/fitconnect/TestRunner.java
+++ b/client/src/main/java/de/fitko/fitconnect/TestRunner.java
@@ -1,8 +1,7 @@
 package de.fitko.fitconnect;
 
-import de.fitko.fitconnect.api.domain.model.submission.SubmissionRequest;
-import de.fitko.fitconnect.client.SenderClient;
-import de.fitko.fitconnect.client.SubscriberClient;
+import de.fitko.fitconnect.api.domain.model.submission.CreatedSubmission;
+import de.fitko.fitconnect.client.*;
 
 import java.util.Collections;
 import java.util.List;
@@ -16,18 +15,21 @@ public class TestRunner {
 
     private static void senderSample() {
 
-        // straight call in one go
-        SenderClient.build().send(UUID.randomUUID(), Collections.emptyList());
-        SenderClient.build().send(UUID.randomUUID(), Collections.emptyList(), "some json or xml");
+        // No DI
+        ClientFactory.senderClient().send(UUID.randomUUID(), Collections.emptyList());
+
+        // With Guice DI straight call in one go
+        FluentSenderClient.build().send(UUID.randomUUID(), Collections.emptyList());
+        FluentSenderClient.build().send(UUID.randomUUID(), Collections.emptyList(), "some json or xml");
 
         // Without data
-        SenderClient.build()
+        FluentSenderClient.build()
                 .withDestination(UUID.randomUUID())
                 .withAttachments(Collections.emptyList())
                 .submit();
 
         // With data
-        SenderClient.build()
+        FluentSenderClient.build()
                 .withDestination(UUID.randomUUID())
                 .withAttachments(Collections.emptyList())
                 .withData("some json or xml")
@@ -36,26 +38,12 @@ public class TestRunner {
 
     private static void subscriberSample() {
 
-        var clientId = "781f6213-0f0f-4a79-9372-e7187ffda98b";
-        var secret = "PnzR8Vbmhpv_VwTkT34wponqXWK8WBm-LADlryYdV4o";
-
-
-        // #1 authenticate
-        var authenticatedClient = SubscriberClient.builder().authenticate(clientId, secret);
-
-        // #2 poll for available submissions
-        List<SubmissionRequest> availableSubmissions = authenticatedClient.getAvailableSubmissions("someDestinationId");
+        var client = ClientFactory.subscriberClient();
 
-        // #3 get a submission and its data
-        var confirmedSubmission = authenticatedClient
-                .requestSubmission(SubmissionRequest.builder().build())
-                .requestMetadata()
-                .requestAttachments()
-                .confirmSubmission();
+        List<CreatedSubmission> submissions = client.getAvailableSubmissions(UUID.randomUUID(), 0, 100);
 
-        // access request submission data
-        var attachments = confirmedSubmission.getAttachments();
-        var metadata = confirmedSubmission.getMetadata();
+        // filter submissions for requested one
+        CreatedSubmission submission = client.requestSubmission(UUID.fromString("123"));
 
     }
 
diff --git a/client/src/main/java/de/fitko/fitconnect/client/ClientFactory.java b/client/src/main/java/de/fitko/fitconnect/client/ClientFactory.java
new file mode 100644
index 000000000..e94bbd75d
--- /dev/null
+++ b/client/src/main/java/de/fitko/fitconnect/client/ClientFactory.java
@@ -0,0 +1,80 @@
+package de.fitko.fitconnect.client;
+
+import com.typesafe.config.Config;
+import com.typesafe.config.ConfigBeanFactory;
+import com.typesafe.config.ConfigFactory;
+import de.fitko.fitconnect.api.services.Sender;
+import de.fitko.fitconnect.api.services.Subscriber;
+import de.fitko.fitconnect.api.services.auth.OAuthService;
+import de.fitko.fitconnect.api.services.crypto.CryptoService;
+import de.fitko.fitconnect.api.services.metadata.MetadataService;
+import de.fitko.fitconnect.api.services.validation.CertificateValidator;
+import de.fitko.fitconnect.api.services.validation.MetadataValidator;
+import de.fitko.fitconnect.dependency.ApplicationConfig;
+import de.fitko.fitconnect.impl.SubmissionSender;
+import de.fitko.fitconnect.impl.SubmissionSubscriber;
+import de.fitko.fitconnect.impl.auth.DefaultOAuthService;
+import de.fitko.fitconnect.impl.crypto.JWECryptoService;
+import de.fitko.fitconnect.impl.http.ProxyConfig;
+import de.fitko.fitconnect.impl.metadata.MetadataUploadService;
+import de.fitko.fitconnect.impl.validation.KeyValidator;
+import de.fitko.fitconnect.impl.validation.MetadataSubmissionValidator;
+import org.springframework.web.client.RestTemplate;
+
+import java.io.File;
+
+public class ClientFactory {
+
+    public static final String CONFIG_FILENAME = "sdk.conf";
+    public static final String CONFIG_CONTEXT = "sdk";
+
+    private ClientFactory() {}
+
+    public static SenderClient.WithDestination senderClient() {
+        final ApplicationConfig config = loadConfig();
+        final RestTemplate restTemplate = getRestTemplate(config);
+        final Sender sender = getSender(config, restTemplate);
+        return SenderClient.build(sender, config.getClientId(), config.getClientSecret());
+    }
+
+    public static SubscriberClient.RequestSubmission subscriberClient() {
+        final ApplicationConfig config = loadConfig();
+        final RestTemplate restTemplate = getRestTemplate(config);
+        final Subscriber subscriber = getSubscriber(config, restTemplate);
+        return SubscriberClient.builder(subscriber);
+    }
+
+    private static Subscriber getSubscriber(ApplicationConfig config, RestTemplate restTemplate) {
+        final OAuthService oAuthService = getOAuthService(config, restTemplate);
+        final CryptoService cryptoService = getCryptoService();
+        final MetadataValidator validator = new MetadataSubmissionValidator();
+        return new SubmissionSubscriber(oAuthService,cryptoService, validator);
+    }
+
+    private static Sender getSender(ApplicationConfig config, RestTemplate restTemplate) {
+        final OAuthService authService = getOAuthService(config, restTemplate);
+        final CryptoService cryptoService = getCryptoService();
+        final CertificateValidator validator = new KeyValidator();
+        final MetadataService metadataService = new MetadataUploadService(restTemplate);
+        return new SubmissionSender(authService, cryptoService, validator, metadataService);
+    }
+
+    private static CryptoService getCryptoService() {
+        return new JWECryptoService();
+    }
+
+    private static OAuthService getOAuthService(ApplicationConfig config, RestTemplate restTemplate) {
+        return new DefaultOAuthService(restTemplate, config.getAuthTokenUrl());
+    }
+
+    private static RestTemplate getRestTemplate(ApplicationConfig config) {
+        final ProxyConfig proxyConfig = new ProxyConfig(config.getHttpProxyHost(), config.getHttpProxyPort());
+        return proxyConfig.proxyRestTemplate();
+    }
+
+    private static ApplicationConfig loadConfig() {
+        final Config configFile = ConfigFactory.parseFile(new File(CONFIG_FILENAME));
+        final Config sdkConfig = ConfigFactory.load(configFile).getConfig(CONFIG_CONTEXT);
+        return ConfigBeanFactory.create(sdkConfig, ApplicationConfig.class);
+    }
+}
diff --git a/client/src/main/java/de/fitko/fitconnect/client/FluentSenderClient.java b/client/src/main/java/de/fitko/fitconnect/client/FluentSenderClient.java
new file mode 100644
index 000000000..b035f9b9d
--- /dev/null
+++ b/client/src/main/java/de/fitko/fitconnect/client/FluentSenderClient.java
@@ -0,0 +1,218 @@
+package de.fitko.fitconnect.client;
+
+import com.nimbusds.jose.jwk.RSAKey;
+import de.fitko.fitconnect.api.domain.auth.OAuthToken;
+import de.fitko.fitconnect.api.domain.model.metadata.Metadata;
+import de.fitko.fitconnect.api.domain.model.metadata.attachment.Attachment;
+import de.fitko.fitconnect.api.domain.model.metadata.data.Data;
+import de.fitko.fitconnect.api.domain.model.submission.SubmissionRequest;
+import de.fitko.fitconnect.api.domain.model.submission.CreatedSubmission;
+import de.fitko.fitconnect.api.domain.validation.ValidationResult;
+import de.fitko.fitconnect.api.exceptions.client.ClientNotAuthenticated;
+import de.fitko.fitconnect.api.services.Sender;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+/**
+ * A fluent client for announcing and handing in a {@link SubmissionRequest}
+ */
+public class FluentSenderClient extends Client {
+
+    private FluentSenderClient() {}
+
+    public static WithDestination build() {
+        final Sender sender = getService(Sender.class);
+         final String clientId = getProperty("clientId");
+         final String secret = getProperty("clientSecret");
+        return new ClientBuilder(sender, clientId, secret);
+    }
+
+    public interface WithDestination {
+
+        /**
+         * Configures the client for the given destination and load the public key
+         *
+         * @param destinationId the clients destination
+         * @return the upload step for attachments
+         */
+        WithAttachments withDestination(UUID destinationId);
+
+        CreatedSubmission send(UUID destinationId, List<File> attachments, String data);
+
+        CreatedSubmission send(UUID destinationId, List<File> attachments, byte[] data);
+
+        CreatedSubmission send(UUID destinationId, List<File> attachments);
+    }
+
+    public interface WithAttachments {
+
+        /**
+         * Sends the submission with a list of attachments
+         *
+         * @param attachments that are sent with the submission
+         * @return the step where additional data can be added to the submission
+         */
+        WithData withAttachments(List<File> attachments);
+    }
+
+    public interface WithData {
+
+        Submit withData(String data);
+
+        Submit withData(byte[] data);
+
+        CreatedSubmission submit();
+    }
+
+    public interface Submit {
+        CreatedSubmission submit();
+    }
+
+    public static class ClientBuilder implements WithDestination, WithAttachments, WithData, Submit {
+
+        private Sender sender;
+        private final String clientId;
+        private final String secret;
+
+        private UUID destinationId;
+        private Data data;
+        private List<Attachment> attachments;
+        private RSAKey encryptionKey;
+        private UUID submissionId;
+
+        public ClientBuilder(Sender sender, String clientId, String secret) {
+            this.sender = sender;
+            this.clientId = clientId;
+            this.secret = secret;
+            authenticate();
+        }
+
+        @Override
+        public WithAttachments withDestination(UUID destinationId) {
+            final RSAKey encryptionKey = sender.getEncryptionKeyForDestination(destinationId);
+            final ValidationResult validationResult = sender.validatePublicKey(encryptionKey);
+            if(validationResult.hasErrors()){
+                throw new RuntimeException("Public encryption key is not valid");
+            }
+            this.encryptionKey = encryptionKey;
+            return this;
+        }
+
+        @Override
+        public CreatedSubmission send(UUID destinationId, List<File> attachments, String data) {
+            return this.withDestination(destinationId)
+                    .withAttachments(attachments)
+                    .withData(data)
+                    .submit();
+        }
+
+        @Override
+        public CreatedSubmission send(UUID destinationId, List<File> attachments, byte[] data) {
+            return this.withDestination(destinationId)
+                    .withAttachments(attachments)
+                    .withData(data)
+                    .submit();
+        }
+
+        @Override
+        public CreatedSubmission send(UUID destinationId, List<File> attachments) {
+            return this.withDestination(destinationId)
+                    .withAttachments(attachments)
+                    .submit();
+        }
+
+        @Override
+        public Submit withData(String data) {
+            return withData(data.getBytes(StandardCharsets.UTF_8));
+        }
+
+        @Override
+        public Submit withData(byte[] data) {
+            var unencryptedData = Data.builder().build();
+            final Optional<Data> encryptedData = sender.encryptSubmissionData(encryptionKey, unencryptedData);
+            if(encryptedData.isEmpty()){
+                throw new RuntimeException("Data could not be encrypted");
+            }
+            this.data = encryptedData.get();
+            return this;
+        }
+
+        @Override
+        public WithData withAttachments(List<File> attachmentFiles) {
+            final List<Attachment> attachments = readFilesToAttachments(attachmentFiles);
+            final CreatedSubmission submission = createSubmission(destinationId, attachments);
+            this.submissionId = submission.getSubmissionId();
+            final List<Attachment> encryptedAttachments = encryptAttachments(encryptionKey, attachments);
+            sender.uploadAttachments(submissionId, encryptedAttachments);
+            return this;
+        }
+
+        @Override
+        public CreatedSubmission submit() {
+            final Optional<Metadata> metadata = getMetadata();
+            if(metadata.isEmpty()){
+                throw new RuntimeException("Metadata could not be created");
+            }
+            return sender.sendSubmission(submissionId, metadata.get()).orElseThrow();
+        }
+
+        private Optional<Metadata> getMetadata() {
+            return this.data == null ? sender.createMetadata(attachments) : sender.createMetadata(data, attachments);
+        }
+
+        private List<Attachment> encryptAttachments(RSAKey encryptionKey, List<Attachment> attachments) {
+            return attachments.stream().map(attachment -> encryptAttachment(encryptionKey, attachment)).collect(Collectors.toList());
+        }
+
+        private Attachment encryptAttachment(RSAKey encryptionKey, Attachment attachment) {
+            final Optional<Attachment> encryptedAttachment = sender.encryptAttachment(encryptionKey, attachment);
+            if (encryptedAttachment.isEmpty()) {
+                throw new RuntimeException("Attachment could not be encrypted");
+            }
+            return encryptedAttachment.get();
+        }
+
+        private CreatedSubmission createSubmission(UUID destinationId, List<Attachment> attachments) {
+            final SubmissionRequest request = SubmissionRequest.builder()
+                    .destinationId(destinationId)
+                    .announcedAttachments(asListOfAttachmentsIds(attachments))
+                    .build();
+
+            final Optional<CreatedSubmission> response = sender.createSubmission(request);
+            if (response.isEmpty()) {
+                throw new RuntimeException("Could not create submission");
+            }
+            return response.get();
+        }
+
+        private List<UUID> asListOfAttachmentsIds(List<Attachment> attachments) {
+            return attachments.stream().map(attachment -> attachment.getAttachmentId()).collect(Collectors.toList());
+        }
+
+        private void authenticate() {
+            final Optional<OAuthToken> oAuthToken = sender.retrieveOAuthToken(clientId, secret);
+            if (oAuthToken.isEmpty()) {
+                throw new ClientNotAuthenticated("Client is not authenticated, please authenticate first");
+            }
+        }
+
+        private List<Attachment> readFilesToAttachments(List<File> attachmentFiles) {
+            return attachmentFiles.stream()
+                    .map(this::readFileToAttachment)
+                    .collect(Collectors.toList());
+        }
+
+        private Attachment readFileToAttachment(File file) {
+            final Optional<Attachment> attachment = sender.createAttachment(file);
+            if(attachment.isEmpty()){
+                throw new RuntimeException("Attachment could not be created");
+            }
+            return attachment.get();
+        }
+    }
+}
\ No newline at end of file
diff --git a/client/src/main/java/de/fitko/fitconnect/client/SenderClient.java b/client/src/main/java/de/fitko/fitconnect/client/SenderClient.java
index 6b0677fcf..418842be8 100644
--- a/client/src/main/java/de/fitko/fitconnect/client/SenderClient.java
+++ b/client/src/main/java/de/fitko/fitconnect/client/SenderClient.java
@@ -6,7 +6,7 @@ import de.fitko.fitconnect.api.domain.model.metadata.Metadata;
 import de.fitko.fitconnect.api.domain.model.metadata.attachment.Attachment;
 import de.fitko.fitconnect.api.domain.model.metadata.data.Data;
 import de.fitko.fitconnect.api.domain.model.submission.SubmissionRequest;
-import de.fitko.fitconnect.api.domain.model.submission.SubmissionResponse;
+import de.fitko.fitconnect.api.domain.model.submission.CreatedSubmission;
 import de.fitko.fitconnect.api.domain.validation.ValidationResult;
 import de.fitko.fitconnect.api.exceptions.client.ClientNotAuthenticated;
 import de.fitko.fitconnect.api.services.Sender;
@@ -21,15 +21,12 @@ import java.util.stream.Collectors;
 /**
  * A fluent client for announcing and handing in a {@link SubmissionRequest}
  */
-public class SenderClient extends Client {
+public class SenderClient {
 
     private SenderClient() {
     }
 
-    public static WithDestination build() {
-        final Sender sender = getService(Sender.class);
-        final String clientId = getProperty("clientId");
-        final String secret = getProperty("clientSecret");
+    public static WithDestination build(Sender sender,String clientId, String secret ) {
         return new ClientBuilder(sender, clientId, secret);
     }
 
@@ -43,11 +40,11 @@ public class SenderClient extends Client {
          */
         WithAttachments withDestination(UUID destinationId);
 
-        SubmissionResponse send(UUID destinationId, List<File> attachments, String data);
+        CreatedSubmission send(UUID destinationId, List<File> attachments, String data);
 
-        SubmissionResponse send(UUID destinationId, List<File> attachments, byte[] data);
+        CreatedSubmission send(UUID destinationId, List<File> attachments, byte[] data);
 
-        SubmissionResponse send(UUID destinationId, List<File> attachments);
+        CreatedSubmission send(UUID destinationId, List<File> attachments);
     }
 
     public interface WithAttachments {
@@ -67,11 +64,11 @@ public class SenderClient extends Client {
 
         Submit withData(byte[] data);
 
-        SubmissionResponse submit();
+        CreatedSubmission submit();
     }
 
     public interface Submit {
-        SubmissionResponse submit();
+        CreatedSubmission submit();
     }
 
     public static class ClientBuilder implements WithDestination, WithAttachments, WithData, Submit {
@@ -105,7 +102,7 @@ public class SenderClient extends Client {
         }
 
         @Override
-        public SubmissionResponse send(UUID destinationId, List<File> attachments, String data) {
+        public CreatedSubmission send(UUID destinationId, List<File> attachments, String data) {
             return this.withDestination(destinationId)
                     .withAttachments(attachments)
                     .withData(data)
@@ -113,7 +110,7 @@ public class SenderClient extends Client {
         }
 
         @Override
-        public SubmissionResponse send(UUID destinationId, List<File> attachments, byte[] data) {
+        public CreatedSubmission send(UUID destinationId, List<File> attachments, byte[] data) {
             return this.withDestination(destinationId)
                     .withAttachments(attachments)
                     .withData(data)
@@ -121,7 +118,7 @@ public class SenderClient extends Client {
         }
 
         @Override
-        public SubmissionResponse send(UUID destinationId, List<File> attachments) {
+        public CreatedSubmission send(UUID destinationId, List<File> attachments) {
             return this.withDestination(destinationId)
                     .withAttachments(attachments)
                     .submit();
@@ -146,15 +143,15 @@ public class SenderClient extends Client {
         @Override
         public WithData withAttachments(List<File> attachmentFiles) {
             final List<Attachment> attachments = readFilesToAttachments(attachmentFiles);
-            final SubmissionResponse createdSubmission = createSubmission(destinationId, attachments);
-            this.submissionId = createdSubmission.getSubmissionId();
+            final CreatedSubmission submission = createSubmission(destinationId, attachments);
+            this.submissionId = submission.getSubmissionId();
             final List<Attachment> encryptedAttachments = encryptAttachments(encryptionKey, attachments);
             sender.uploadAttachments(submissionId, encryptedAttachments);
             return this;
         }
 
         @Override
-        public SubmissionResponse submit() {
+        public CreatedSubmission submit() {
             final Optional<Metadata> metadata = getMetadata();
             if(metadata.isEmpty()){
                 throw new RuntimeException("Metadata could not be created");
@@ -178,13 +175,13 @@ public class SenderClient extends Client {
             return encryptedAttachment.get();
         }
 
-        private SubmissionResponse createSubmission(UUID destinationId, List<Attachment> attachments) {
+        private CreatedSubmission createSubmission(UUID destinationId, List<Attachment> attachments) {
             final SubmissionRequest request = SubmissionRequest.builder()
                     .destinationId(destinationId)
                     .announcedAttachments(asListOfAttachmentsIds(attachments))
                     .build();
 
-            final Optional<SubmissionResponse> response = sender.createSubmission(request);
+            final Optional<CreatedSubmission> response = sender.createSubmission(request);
             if (response.isEmpty()) {
                 throw new RuntimeException("Could not create submission");
             }
diff --git a/dependency/src/main/java/de/fitko/fitconnect/dependency/ApplicationConfig.java b/dependency/src/main/java/de/fitko/fitconnect/dependency/ApplicationConfig.java
index e459216d0..5904e9537 100644
--- a/dependency/src/main/java/de/fitko/fitconnect/dependency/ApplicationConfig.java
+++ b/dependency/src/main/java/de/fitko/fitconnect/dependency/ApplicationConfig.java
@@ -13,7 +13,7 @@ import java.util.Properties;
 public class ApplicationConfig {
 
     private String httpProxyHost;
-    private String httpProxyPort;
+    private Integer httpProxyPort;
 
     private String authTokenUrl;
     private List<String> apiUrls;
diff --git a/impl/src/main/java/de/fitko/fitconnect/impl/SubmissionSender.java b/impl/src/main/java/de/fitko/fitconnect/impl/SubmissionSender.java
index 13ca5ab24..3145725cd 100644
--- a/impl/src/main/java/de/fitko/fitconnect/impl/SubmissionSender.java
+++ b/impl/src/main/java/de/fitko/fitconnect/impl/SubmissionSender.java
@@ -9,7 +9,7 @@ import de.fitko.fitconnect.api.domain.model.metadata.attachment.signature.Hash__
 import de.fitko.fitconnect.api.domain.model.metadata.attachment.signature.Type;
 import de.fitko.fitconnect.api.domain.model.metadata.data.Data;
 import de.fitko.fitconnect.api.domain.model.submission.SubmissionRequest;
-import de.fitko.fitconnect.api.domain.model.submission.SubmissionResponse;
+import de.fitko.fitconnect.api.domain.model.submission.CreatedSubmission;
 import de.fitko.fitconnect.api.domain.validation.ValidationResult;
 import de.fitko.fitconnect.api.exceptions.internal.AuthenticationException;
 import de.fitko.fitconnect.api.services.Sender;
@@ -88,12 +88,12 @@ public class SubmissionSender implements Sender {
     }
 
     @Override
-    public Optional<SubmissionResponse> createSubmission(SubmissionRequest submission) {
+    public Optional<CreatedSubmission> createSubmission(SubmissionRequest submission) {
         throw new UnsupportedOperationException("not yet implemented");
     }
 
     @Override
-    public Optional<SubmissionResponse> sendSubmission(UUID submissionId, Metadata encryptedMetadata) {
+    public Optional<CreatedSubmission> sendSubmission(UUID submissionId, Metadata encryptedMetadata) {
         throw new UnsupportedOperationException("not yet implemented");
     }
 
diff --git a/impl/src/main/java/de/fitko/fitconnect/impl/metadata/MetadataUploadService.java b/impl/src/main/java/de/fitko/fitconnect/impl/metadata/MetadataUploadService.java
index 3c1318f91..44070f7b7 100644
--- a/impl/src/main/java/de/fitko/fitconnect/impl/metadata/MetadataUploadService.java
+++ b/impl/src/main/java/de/fitko/fitconnect/impl/metadata/MetadataUploadService.java
@@ -14,7 +14,7 @@ public class MetadataUploadService implements MetadataService {
     private final RestTemplate restTemplate;
 
     @Inject
-    MetadataUploadService(final RestTemplate restTemplate){
+    public MetadataUploadService(final RestTemplate restTemplate){
         this.restTemplate = restTemplate;
     }
 
-- 
GitLab