correctableReportableSellerTypes,
final CorrectablePlatformOperatorType correctablePlatformOperatorType)
- throws HttpStatusCodeNotExceptedException
{
- try(final WebClient client = new WebClient(this.configuration))
- {
- return this.sendDipOnlyInternal(correctableReportableSellerTypes, correctablePlatformOperatorType, client);
- }
+ return this.sendDipOnlyInternal(correctableReportableSellerTypes, correctablePlatformOperatorType);
}
/**
* Sends the message and queries a result.
*
- * Querying the result might take a few seconds and is configured in
- * {@link BzstDipConfiguration#queryResultConfiguration}.
+ * Querying the result might take a few seconds and is configured in
+ * {@link BzstDipConfiguration#getQueryResultConfiguration()}.
*
*
- * In special cases {@link #sendDipOnly(BzstDipMessage)} can be used, if the result is not needed,
- * or the results should be queried in some other way.
+ * In special cases {@link #sendDipOnly(BzstDipMessage)} can be used, if the result is not needed, or the results
+ * should be queried in some other way.
*
+ *
* @param message with the data for the BZST DIP API.
* @return the result which contains the dataTransferNumber and all found responses in the API.
*/
public BzstDipCompleteResult sendDipAndQueryResult(final BzstDipMessage message)
- throws HttpStatusCodeNotExceptedException, InterruptedException, IOException
+ throws InterruptedException, IOException
{
return this.sendDipAndQueryResult(message.toXmlType(this.configuration));
}
public BzstDipCompleteResult sendDipAndQueryResult(final BzstCesopPaymentDataBody message)
- throws HttpStatusCodeNotExceptedException, InterruptedException, IOException, DatatypeConfigurationException
+ throws InterruptedException, IOException, DatatypeConfigurationException
{
return this.sendDipAndQueryResult(message.toXmlType());
}
@@ -149,18 +162,19 @@ public BzstDipCompleteResult sendDipAndQueryResult(final BzstCesopPaymentDataBod
/**
* Sends the message and queries a result.
*
- * Querying the result might take a few seconds and is configured in
- * {@link BzstDipConfiguration#queryResultConfiguration}.
+ * Querying the result might take a few seconds and is configured in
+ * {@link BzstDipConfiguration#getQueryResultConfiguration()}.
*
*
- * In special cases {@link #sendDipOnly(String)} can be used, if the result is not needed,
- * or the results should be queried in some other way.
+ * In special cases {@link #sendDipOnly(String)} can be used, if the result is not needed, or the results should be
+ * queried in some other way.
*
+ *
* @param csvData which will be parsed by the {@link ReportableSellerCsvFileParser}.
* @return the result which contains the dataTransferNumber and all found responses in the API.
*/
public BzstDipCompleteResult sendDipAndQueryResult(final String csvData)
- throws HttpStatusCodeNotExceptedException, InterruptedException, IOException
+ throws InterruptedException, IOException
{
return this.sendDipAndQueryResult(new ReportableSellerCsvFileParser(this.configuration).parseCsvData(csvData));
}
@@ -168,20 +182,21 @@ public BzstDipCompleteResult sendDipAndQueryResult(final String csvData)
/**
* Sends the message and queries a result.
*
- * Querying the result might take a few seconds and is configured in
- * {@link BzstDipConfiguration#queryResultConfiguration}.
+ * Querying the result might take a few seconds and is configured in
+ * {@link BzstDipConfiguration#getQueryResultConfiguration()}.
*
*
- * In special cases {@link #sendDipOnly(List)} can be used, if the result is not needed,
- * or the results should be queried in some other way.
+ * In special cases {@link #sendDipOnly(List)} can be used, if the result is not needed, or the results should be
+ * queried in some other way.
*
+ *
* @param correctableReportableSellerTypes with the data for the BZST DIP API.
* @return the result which contains the dataTransferNumber and all found responses in the API.
*/
public BzstDipCompleteResult sendDipAndQueryResult(
final List correctableReportableSellerTypes
)
- throws HttpStatusCodeNotExceptedException, InterruptedException, IOException
+ throws InterruptedException, IOException
{
return this.sendDipAndQueryResult(
correctableReportableSellerTypes,
@@ -192,74 +207,64 @@ public BzstDipCompleteResult sendDipAndQueryResult(
/**
* Sends the message and queries a result.
*
- * Querying the result might take a few seconds and is configured in
- * {@link BzstDipConfiguration#queryResultConfiguration}.
+ * Querying the result might take a few seconds and is configured in
+ * {@link BzstDipConfiguration#getQueryResultConfiguration()}.
*
*
- * In special cases {@link #sendDipOnly(List, CorrectablePlatformOperatorType)} can be used, if the result is
- * not needed,
- * or the results should be queried in some other way.
+ * In special cases {@link #sendDipOnly(List, CorrectablePlatformOperatorType)} can be used, if the result is not
+ * needed, or the results should be queried in some other way.
*
+ *
* @param correctableReportableSellerTypes with the data for the BZST DIP API.
- * @param correctablePlatformOperatorType with the information about the platform operator.
+ * @param correctablePlatformOperatorType with the information about the platform operator.
* @return the result which contains the dataTransferNumber and all found responses in the API.
*/
public BzstDipCompleteResult sendDipAndQueryResult(
final List correctableReportableSellerTypes,
final CorrectablePlatformOperatorType correctablePlatformOperatorType
)
- throws HttpStatusCodeNotExceptedException, InterruptedException, IOException
+ throws InterruptedException, IOException
{
- try(final WebClient client = new WebClient(this.configuration))
- {
- final BzstDipSendingResult sendingResult =
- this.sendDipOnlyInternal(correctableReportableSellerTypes, correctablePlatformOperatorType, client);
-
- Thread.sleep(this.configuration.getQueryResultConfiguration().delayBeforeCheckingResults().toMillis());
-
- final BzstDipRequestStatusResult requestStatusResult = this.queryDipResultWithRetry(client, sendingResult);
-
- return BzstDipCompleteResult.fromResult(sendingResult, requestStatusResult);
- }
+ final BzstDipSendingResult sendingResult =
+ this.sendDipOnlyInternal(correctableReportableSellerTypes, correctablePlatformOperatorType);
+
+ Thread.sleep(this.configuration.getQueryResultConfiguration().delayBeforeCheckingResults().toMillis());
+
+ final BzstDipRequestStatusResult requestStatusResult = this.queryDipResultWithRetry(sendingResult);
+
+ return BzstDipCompleteResult.fromResult(sendingResult, requestStatusResult);
}
public BzstDipCompleteResult sendDipAndQueryResult(
final PaymentDataBodyType paymentDataBodyType
)
- throws HttpStatusCodeNotExceptedException, InterruptedException, IOException
+ throws InterruptedException, IOException
{
- try(final WebClient client = new WebClient(this.configuration))
- {
- final BzstDipSendingResult sendingResult =
- this.sendDipOnlyInternal(paymentDataBodyType, client);
-
- Thread.sleep(this.configuration.getQueryResultConfiguration().delayBeforeCheckingResults().toMillis());
-
- final BzstDipRequestStatusResult requestStatusResult = this.queryDipResultWithRetry(client, sendingResult);
-
- return BzstDipCompleteResult.fromResult(sendingResult, requestStatusResult);
- }
+ final WebClient client = new WebClient(this.configuration);
+ final BzstDipSendingResult sendingResult = this.sendDipOnlyInternal(paymentDataBodyType, client);
+
+ Thread.sleep(this.configuration.getQueryResultConfiguration().delayBeforeCheckingResults().toMillis());
+
+ final BzstDipRequestStatusResult requestStatusResult = this.queryDipResultWithRetry(sendingResult);
+
+ return BzstDipCompleteResult.fromResult(sendingResult, requestStatusResult);
}
/**
- * Queries for a DIP result. We recommend using the
- * {@link #sendDipAndQueryResult(BzstDipMessage)} counterpart and
+ * Queries for a DIP result. We recommend using the {@link #sendDipAndQueryResult(BzstDipMessage)} counterpart and
* suggest only using this method, if specifically needed.
+ *
* @return all found {@link BzstDipSingleTransferResult}s
*/
- public BzstDipRequestStatusResult queryDipResult() throws HttpStatusCodeNotExceptedException, IOException
+ public BzstDipRequestStatusResult queryDipResult() throws IOException
{
- try(final WebClient client = new WebClient(this.configuration))
- {
- return client.readAndConfirmDataTransferNumbers();
- }
+ return this.webClient.readAndConfirmDataTransferNumbers();
}
private BzstDipSendingResult sendDipOnlyInternal(
final List correctableReportableSellerTypes,
- final CorrectablePlatformOperatorType correctablePlatformOperatorType,
- final WebClient client
- ) throws HttpStatusCodeNotExceptedException
+ final CorrectablePlatformOperatorType correctablePlatformOperatorType
+ )
{
final XMLDocumentCreator xmlDocumentCreator = new XMLDocumentCreator(this.configuration);
final String signedXML =
@@ -272,12 +277,12 @@ private BzstDipSendingResult sendDipOnlyInternal(
LOGGER.debug("Created following XML-Document:\n{}", signedXML);
LOGGER.debug("XML data will now be uploaded...");
- final String dataTransferNumber = client.getDataTransferNumber();
+ final String dataTransferNumber = this.webClient.getDataTransferNumber();
LOGGER.debug("Data transfer number: {}", dataTransferNumber);
- client.uploadMassData(dataTransferNumber, signedXML);
+ this.webClient.uploadMassData(dataTransferNumber, signedXML);
- client.closeSubmission(dataTransferNumber);
+ this.webClient.closeSubmission(dataTransferNumber);
return new BzstDipSendingResult(dataTransferNumber);
}
@@ -285,7 +290,7 @@ private BzstDipSendingResult sendDipOnlyInternal(
private BzstDipSendingResult sendDipOnlyInternal(
final PaymentDataBodyType paymentDataBodyType,
final WebClient client
- ) throws HttpStatusCodeNotExceptedException
+ )
{
final XMLDocumentCreator xmlDocumentCreator = new XMLDocumentCreator(this.configuration);
final String signedXML =
@@ -308,9 +313,8 @@ private BzstDipSendingResult sendDipOnlyInternal(
}
private BzstDipRequestStatusResult queryDipResultWithRetry(
- final WebClient webClient,
final BzstDipSendingResult sendingResult)
- throws HttpStatusCodeNotExceptedException, InterruptedException, IOException
+ throws InterruptedException, IOException
{
BzstDipRequestStatusResult requestStatusResult;
int retryCounter = 0;
@@ -323,7 +327,7 @@ private BzstDipRequestStatusResult queryDipResultWithRetry(
LOGGER.debug("Waiting {}ms for next query...", delayInMilliseconds);
Thread.sleep(delayInMilliseconds);
}
- requestStatusResult = webClient.readAndConfirmDataTransferNumbers();
+ requestStatusResult = this.webClient.readAndConfirmDataTransferNumbers();
retryCounter++;
}
while(
diff --git a/bzst-dip-java-client/src/main/java/software/xdev/bzst/dip/client/exception/EncryptionException.java b/bzst-dip-java-client/src/main/java/software/xdev/bzst/dip/client/exception/EncryptionException.java
index 1c403689..689275ce 100644
--- a/bzst-dip-java-client/src/main/java/software/xdev/bzst/dip/client/exception/EncryptionException.java
+++ b/bzst-dip-java-client/src/main/java/software/xdev/bzst/dip/client/exception/EncryptionException.java
@@ -15,12 +15,11 @@
*/
package software.xdev.bzst.dip.client.exception;
-import software.xdev.bzst.dip.client.model.configuration.BzstDipConfiguration;
+import software.xdev.bzst.dip.client.webclient.BearerTokenRequester;
/**
- * Is used for exception that occur during encryption in
- * {@link software.xdev.bzst.dip.client.util.WebClientUtil#createRequestToken(BzstDipConfiguration)}.
+ * Is used for exception that occur during encryption in {@link BearerTokenRequester#getAccessToken()}.
*/
public class EncryptionException extends RuntimeException
{
diff --git a/bzst-dip-java-client/src/main/java/software/xdev/bzst/dip/client/exception/HttpStatusCodeNotExceptedException.java b/bzst-dip-java-client/src/main/java/software/xdev/bzst/dip/client/exception/HttpStatusCodeNotExceptedException.java
deleted file mode 100644
index 84b21132..00000000
--- a/bzst-dip-java-client/src/main/java/software/xdev/bzst/dip/client/exception/HttpStatusCodeNotExceptedException.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright © 2024 XDEV Software (https://xdev.software)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package software.xdev.bzst.dip.client.exception;
-
-import java.net.http.HttpResponse;
-
-
-/**
- * Is used while communicating with HTTP and an unexpected status code is returned.
- */
-public class HttpStatusCodeNotExceptedException extends Exception
-{
- public HttpStatusCodeNotExceptedException(final HttpResponse httpResponse)
- {
- super("Status code from http response: " + httpResponse.statusCode() + " with body: " + httpResponse.body());
- }
-}
diff --git a/bzst-dip-java-client/src/main/java/software/xdev/bzst/dip/client/model/message/cesop/BzstCesopPaymentDataBody.java b/bzst-dip-java-client/src/main/java/software/xdev/bzst/dip/client/model/message/cesop/BzstCesopPaymentDataBody.java
index 995bc705..f830aa9e 100644
--- a/bzst-dip-java-client/src/main/java/software/xdev/bzst/dip/client/model/message/cesop/BzstCesopPaymentDataBody.java
+++ b/bzst-dip-java-client/src/main/java/software/xdev/bzst/dip/client/model/message/cesop/BzstCesopPaymentDataBody.java
@@ -53,7 +53,7 @@
/**
* @param reportingPSP The reportingPSP element clearly defines the payment service provider that reports the payment
* data to the national tax administration. {@link BzstCesopReportingPSP}
- * @param reportedPayee defines the payee to whom the data transmitted by the payment service provider
+ * @param reportedPayees defines the payees to whom the data transmitted by the payment service provider
*/
public record BzstCesopPaymentDataBody(BzstCesopReportingPSP reportingPSP, List reportedPayees)
{
diff --git a/bzst-dip-java-client/src/main/java/software/xdev/bzst/dip/client/model/message/cesop/BzstCesopTAXIdentification.java b/bzst-dip-java-client/src/main/java/software/xdev/bzst/dip/client/model/message/cesop/BzstCesopTAXIdentification.java
index b44b2be5..298ac4fd 100644
--- a/bzst-dip-java-client/src/main/java/software/xdev/bzst/dip/client/model/message/cesop/BzstCesopTAXIdentification.java
+++ b/bzst-dip-java-client/src/main/java/software/xdev/bzst/dip/client/model/message/cesop/BzstCesopTAXIdentification.java
@@ -17,7 +17,6 @@
/**
* @param vatId The VAT identification number of the payee confirmed by the EU identification number of the paye
- * @param value The Tax ID.
*/
public record BzstCesopTAXIdentification(BzstCesopVatId vatId)
{
diff --git a/bzst-dip-java-client/src/main/java/software/xdev/bzst/dip/client/util/WebClientUtil.java b/bzst-dip-java-client/src/main/java/software/xdev/bzst/dip/client/util/WebClientUtil.java
index 3c9a17e7..ac4e4136 100644
--- a/bzst-dip-java-client/src/main/java/software/xdev/bzst/dip/client/util/WebClientUtil.java
+++ b/bzst-dip-java-client/src/main/java/software/xdev/bzst/dip/client/util/WebClientUtil.java
@@ -16,15 +16,9 @@
package software.xdev.bzst.dip.client.util;
import java.io.IOException;
-import java.io.InputStream;
import java.io.StringReader;
-import java.security.KeyStore;
-import java.security.PrivateKey;
-import java.time.Duration;
import java.util.ArrayList;
-import java.util.Date;
import java.util.List;
-import java.util.UUID;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
@@ -39,10 +33,7 @@
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
-import io.jsonwebtoken.Jwts;
-import software.xdev.bzst.dip.client.exception.EncryptionException;
import software.xdev.bzst.dip.client.factory.DocumentBuilderFactoryNoExternalEntities;
-import software.xdev.bzst.dip.client.model.configuration.BzstDipConfiguration;
/**
@@ -51,48 +42,12 @@
public final class WebClientUtil
{
private static final Logger LOGGER = LoggerFactory.getLogger(WebClientUtil.class);
- public static final String MDS_POSTFIX = "/auth/realms/mds";
public static final String TAG_NAME_DATENTRANSFERNUMMER = "Datentransfernummer";
private WebClientUtil()
{
}
- public static String createRequestToken(final BzstDipConfiguration configuration)
- {
- LOGGER.debug("Creating jwt token...");
- try(final InputStream keystoreInputStream = configuration.getCertificateKeystoreInputStream().get())
- {
- final KeyStore.PrivateKeyEntry privateKeyEntry = SigningUtil.getPrivateKeyEntry(
- keystoreInputStream,
- configuration.getKeyStorePrivateKeyAlias(),
- configuration.getCertificateKeystorePassword(),
- SigningUtil.KEYSTORE_TYPE
- );
-
- final PrivateKey privateKey = privateKeyEntry.getPrivateKey();
- final String clientId = configuration.getClientId();
- LOGGER.debug("Using client id: {}", clientId);
-
- return Jwts.builder()
- .issuer(clientId)
- .subject(clientId)
- .audience().add(
- configuration.getRealmEnvironmentBaseUrl() + MDS_POSTFIX)
- .and()
- .issuedAt(new Date())
- .expiration(new Date(System.currentTimeMillis() + Duration.ofMinutes(5).toMillis()))
- .id(UUID.randomUUID().toString())
- .notBefore(new Date(System.currentTimeMillis() - Duration.ofMinutes(1).toMillis()))
- .signWith(privateKey, Jwts.SIG.RS256)
- .compact();
- }
- catch(final IOException ioException)
- {
- throw new EncryptionException("An error occurred while creating the request token.", ioException);
- }
- }
-
public static List extractTransferNumberFromXml(final String xmlString) throws IOException
{
try
diff --git a/bzst-dip-java-client/src/main/java/software/xdev/bzst/dip/client/webclient/BearerTokenRequester.java b/bzst-dip-java-client/src/main/java/software/xdev/bzst/dip/client/webclient/BearerTokenRequester.java
new file mode 100644
index 00000000..51b3d52d
--- /dev/null
+++ b/bzst-dip-java-client/src/main/java/software/xdev/bzst/dip/client/webclient/BearerTokenRequester.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright © 2024 XDEV Software (https://xdev.software)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package software.xdev.bzst.dip.client.webclient;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.time.Duration;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+
+import io.jsonwebtoken.Jwts;
+import software.xdev.bzst.dip.client.exception.EncryptionException;
+import software.xdev.bzst.dip.client.generated.api.MdEinreichenProviderApi;
+import software.xdev.bzst.dip.client.model.configuration.BzstDipConfiguration;
+import software.xdev.bzst.dip.client.util.SigningUtil;
+
+
+/**
+ * Helps to communicate with the BZST API.
+ */
+public class BearerTokenRequester
+{
+ private static final Logger LOGGER = LoggerFactory.getLogger(BearerTokenRequester.class);
+ private static final String BEARER_STRING = "Bearer ";
+ public static final String MDS_POSTFIX = "/auth/realms/mds";
+
+ private final MdEinreichenProviderApi client;
+ private final BzstDipConfiguration configuration;
+
+ public BearerTokenRequester(
+ final BzstDipConfiguration configuration,
+ final MdEinreichenProviderApi client
+ )
+ {
+ this.configuration = configuration;
+ this.client = client;
+ }
+
+ /**
+ * For every request an access token is required
+ *
+ * @return Access Token as string
+ */
+ public String getAccessToken()
+ {
+ LOGGER.debug("Getting access token...");
+ final String requestToken = this.createRequestToken();
+
+ final HashMap parameters = new HashMap<>();
+ parameters.put("grant_type", "client_credentials");
+ parameters.put("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer");
+ parameters.put("client_assertion", requestToken);
+
+ return this.client.getApiClient().invokeAPI(
+ "/auth/realms/mds/protocol/openid-connect/token",
+ "POST",
+ List.of(),
+ List.of(),
+ "",
+ null,
+ Map.of(),
+ Map.of(),
+ parameters,
+ "",
+ "application/x-www-form-urlencoded;charset=UTF8",
+ new String[]{},
+ new TypeReference()
+ {
+ }
+ ).getAccessToken();
+ }
+
+ public String getAccessTokenWithBearerPrefix()
+ {
+ return BEARER_STRING + this.getAccessToken();
+ }
+
+ private String createRequestToken()
+ {
+ LOGGER.debug("Creating jwt token...");
+ try(final InputStream keystoreInputStream = this.configuration.getCertificateKeystoreInputStream().get())
+ {
+ final KeyStore.PrivateKeyEntry privateKeyEntry = SigningUtil.getPrivateKeyEntry(
+ keystoreInputStream,
+ this.configuration.getKeyStorePrivateKeyAlias(),
+ this.configuration.getCertificateKeystorePassword(),
+ SigningUtil.KEYSTORE_TYPE
+ );
+
+ final PrivateKey privateKey = privateKeyEntry.getPrivateKey();
+ final String clientId = this.configuration.getClientId();
+ LOGGER.debug("Using client id: {}", clientId);
+
+ return Jwts.builder()
+ .issuer(clientId)
+ .subject(clientId)
+ .audience().add(
+ this.configuration.getRealmEnvironmentBaseUrl() + MDS_POSTFIX)
+ .and()
+ .issuedAt(new Date())
+ .expiration(new Date(System.currentTimeMillis() + Duration.ofMinutes(5).toMillis()))
+ .id(UUID.randomUUID().toString())
+ .notBefore(new Date(System.currentTimeMillis() - Duration.ofMinutes(1).toMillis()))
+ .signWith(privateKey, Jwts.SIG.RS256)
+ .compact();
+ }
+ catch(final IOException ioException)
+ {
+ throw new EncryptionException("An error occurred while creating the request token.", ioException);
+ }
+ }
+}
diff --git a/bzst-dip-java-client/src/main/java/software/xdev/bzst/dip/client/webclient/WebClient.java b/bzst-dip-java-client/src/main/java/software/xdev/bzst/dip/client/webclient/WebClient.java
index 0af473d8..8eb0f38b 100644
--- a/bzst-dip-java-client/src/main/java/software/xdev/bzst/dip/client/webclient/WebClient.java
+++ b/bzst-dip-java-client/src/main/java/software/xdev/bzst/dip/client/webclient/WebClient.java
@@ -15,24 +15,18 @@
*/
package software.xdev.bzst.dip.client.webclient;
+import java.io.ByteArrayInputStream;
import java.io.IOException;
-import java.net.URI;
-import java.net.URLEncoder;
-import java.net.http.HttpClient;
-import java.net.http.HttpRequest;
-import java.net.http.HttpResponse;
+import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
-import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import software.xdev.bzst.dip.client.exception.HttpStatusCodeNotExceptedException;
+import software.xdev.bzst.dip.client.generated.api.MdEinreichenProviderApi;
+import software.xdev.bzst.dip.client.generated.client.ApiClient;
import software.xdev.bzst.dip.client.model.configuration.BzstDipConfiguration;
import software.xdev.bzst.dip.client.model.message.dac7.BzstDipRequestStatusResult;
import software.xdev.bzst.dip.client.model.message.dac7.BzstDipSingleTransferResult;
@@ -42,162 +36,74 @@
/**
* Helps to communicate with the BZST API.
*/
-public class WebClient implements AutoCloseable
+public class WebClient
{
private static final Logger LOGGER = LoggerFactory.getLogger(WebClient.class);
- private static final String AUTHORIZATION_STRING = "Authorization";
- private static final String BEARER_STRING = "Bearer ";
- public static final String DIP_MD = "/dip/md/";
- public static final String PATCH = "PATCH";
public static final int OK_HTTP_STATUS_CODE = 200;
- private final HttpClient httpClient = HttpClient.newHttpClient();
- private final BzstDipConfiguration configuration;
+ private final MdEinreichenProviderApi client;
+ private final BearerTokenRequester bearerTokenRequester;
public WebClient(final BzstDipConfiguration configuration)
{
- this.configuration = configuration;
- }
-
- private HttpResponse executeRequest(final HttpRequest httpRequest, final int expectedHttpStatusCode)
- throws HttpStatusCodeNotExceptedException
- {
- final HttpResponse httpResponse = this.executeRequest(httpRequest);
- if(httpResponse.statusCode() != expectedHttpStatusCode)
- {
- throw new HttpStatusCodeNotExceptedException(httpResponse);
- }
- return httpResponse;
+ this(configuration, new MdEinreichenProviderApi());
+ this.client.getApiClient().setBasePath(configuration.getRealmEnvironmentBaseUrl());
}
- private HttpResponse executeRequest(final HttpRequest httpRequest)
+ public WebClient(final BzstDipConfiguration configuration, final ApiClient apiClient)
{
- try
- {
- return this.httpClient.send(
- httpRequest,
- HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
- }
- catch(final IOException | InterruptedException e)
- {
- throw new RuntimeException("An error occurred while getting the access token.", e);
- }
+ this(configuration, new MdEinreichenProviderApi(apiClient));
}
- private HttpRequest createGetAccessTokenRequest()
+ public WebClient(
+ final BzstDipConfiguration configuration,
+ final MdEinreichenProviderApi mdEinreichenProviderApi)
{
- final String requestToken = WebClientUtil.createRequestToken(this.configuration);
-
- final HashMap parameters = new HashMap<>();
- parameters.put("grant_type", "client_credentials");
- parameters.put("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer");
- parameters.put("client_assertion", requestToken);
-
- return HttpRequest.newBuilder()
- .POST(HttpRequest.BodyPublishers.ofString(createFormForParameters(parameters)))
- .uri(URI.create(
- this.configuration.getRealmEnvironmentBaseUrl() + "/auth/realms/mds/protocol/openid-connect/token"))
- .header("Content-Type", "application/x-www-form-urlencoded")
- .build();
- }
-
- /**
- * For every request an access token is required
- *
- * @return Access Token as string
- */
- public String getAccessToken() throws HttpStatusCodeNotExceptedException
- {
- LOGGER.debug("Getting access token...");
- try
- {
- final HttpRequest httpRequest = this.createGetAccessTokenRequest();
- final HttpResponse httpResponse = this.executeRequest(httpRequest, OK_HTTP_STATUS_CODE);
-
- final ObjectMapper objectMapper = new ObjectMapper();
- final AccessTokenHttpResponse accessTokenHttpResponse =
- objectMapper.readValue(httpResponse.body(), AccessTokenHttpResponse.class);
-
- return accessTokenHttpResponse.getAccessToken();
- }
- catch(final IOException e)
- {
- throw new RuntimeException("An error occurred while getting the access token.", e);
- }
- }
-
- private HttpRequest createGetDataTransferNumberRequest() throws HttpStatusCodeNotExceptedException
- {
- return HttpRequest.newBuilder()
- .POST(HttpRequest.BodyPublishers.noBody())
- .uri(URI.create(this.configuration.getRealmEnvironmentBaseUrl() + "/dip/start/DAC7"))
- .header(AUTHORIZATION_STRING, BEARER_STRING + this.getAccessToken())
- .build();
+ this.client = mdEinreichenProviderApi;
+ this.bearerTokenRequester = new BearerTokenRequester(configuration, this.client);
}
/**
* @return XML as string with data transfer numbers
*/
- public String getDataTransferNumber() throws HttpStatusCodeNotExceptedException
+ public String getDataTransferNumber()
{
- LOGGER.debug("Getting data transfer number...");
- final HttpResponse httpResponse = this.executeRequest(this.createGetDataTransferNumberRequest(), 201);
-
- return httpResponse.body();
+ return this.getDataTransferNumber("DAC7");
}
- private HttpRequest createUploadMassDataRequest(final String dataTransferNumber, final String xmlString)
- throws HttpStatusCodeNotExceptedException
+ public String getDataTransferNumber(final String fachverfahren)
{
- return HttpRequest.newBuilder()
- .PUT(HttpRequest.BodyPublishers.ofString(xmlString))
- .uri(URI.create(this.configuration.getRealmEnvironmentBaseUrl() + DIP_MD + dataTransferNumber + "/xml"))
- .header(AUTHORIZATION_STRING, BEARER_STRING + this.getAccessToken())
- .build();
+ LOGGER.debug("Getting data transfer number...");
+ return this.client.einreichungAnmelden(
+ fachverfahren,
+ this.bearerTokenRequester.getAccessTokenWithBearerPrefix()
+ );
}
- public String uploadMassData(final String dataTransferNumber, final String xmlString)
- throws HttpStatusCodeNotExceptedException
+ public void uploadMassData(final String dataTransferNumber, final String xmlString)
{
LOGGER.debug("Uploading the xml data...");
- final HttpResponse httpResponse = this.executeRequest(
- this.createUploadMassDataRequest(dataTransferNumber, xmlString), OK_HTTP_STATUS_CODE);
+ this.client.massendatenEinreichen(
+ dataTransferNumber,
+ this.bearerTokenRequester.getAccessTokenWithBearerPrefix(),
+ new ByteArrayInputStream(xmlString.getBytes())
+ );
LOGGER.debug("Uploaded data successfully!");
- return httpResponse.body();
- }
-
- private HttpRequest createCloseSubmissionRequest(final String dataTransferNumber)
- throws HttpStatusCodeNotExceptedException
- {
- return HttpRequest.newBuilder()
- .uri(URI.create(this.configuration.getRealmEnvironmentBaseUrl() + DIP_MD + dataTransferNumber + "/finish"))
- .method(PATCH, HttpRequest.BodyPublishers.noBody())
- .header(AUTHORIZATION_STRING, BEARER_STRING + this.getAccessToken())
- .build();
}
/**
* Requests the closing of the submission with the given dataTransferNumber.
*/
- public String closeSubmission(final String dataTransferNumber) throws HttpStatusCodeNotExceptedException
+ public void closeSubmission(final String dataTransferNumber)
{
LOGGER.debug("Closing submission...");
- final HttpResponse httpResponse = this.executeRequest(
- this.createCloseSubmissionRequest(dataTransferNumber), OK_HTTP_STATUS_CODE);
+ this.client.einreichungBeenden(
+ dataTransferNumber,
+ this.bearerTokenRequester.getAccessTokenWithBearerPrefix()
+ );
LOGGER.debug("Closed submission successfully!");
-
- return httpResponse.body();
- }
-
- private HttpRequest createGetResultLogsRequest() throws HttpStatusCodeNotExceptedException
- {
- return HttpRequest.newBuilder()
- .uri(URI.create(this.configuration.getRealmEnvironmentBaseUrl() + DIP_MD + "protocolnumbers"))
- .GET()
- .header(AUTHORIZATION_STRING, BEARER_STRING + this.getAccessToken())
- .build();
}
/**
@@ -205,24 +111,19 @@ private HttpRequest createGetResultLogsRequest() throws HttpStatusCodeNotExcepte
*
* @return String list with data transfer numbers
*/
- public List requestResultLogs() throws HttpStatusCodeNotExceptedException, IOException
- {
- final String responseBody = this.executeRequest(this.createGetResultLogsRequest(), OK_HTTP_STATUS_CODE).body();
- LOGGER.debug("ResponseBody from data transfer number request:\n{}", responseBody);
-
- return WebClientUtil.extractTransferNumberFromXml(responseBody);
- }
-
- public HttpRequest createGetResultProtocolRequest(final String dataTransferNumber)
- throws HttpStatusCodeNotExceptedException
+ public List requestResultLogs() throws IOException
{
- return HttpRequest.newBuilder()
- .uri(
- URI.create(this.configuration.getRealmEnvironmentBaseUrl() + DIP_MD + dataTransferNumber + "/protocol")
+ try(
+ final InputStream inputStream = this.client.alleProtokollnummern(
+ this.bearerTokenRequester.getAccessTokenWithBearerPrefix()
)
- .GET()
- .header(AUTHORIZATION_STRING, BEARER_STRING + this.getAccessToken())
- .build();
+ )
+ {
+ final String responseBody = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
+ LOGGER.debug("ResponseBody from data transfer number request:\n{}", responseBody);
+
+ return WebClientUtil.extractTransferNumberFromXml(responseBody);
+ }
}
/**
@@ -231,52 +132,44 @@ public HttpRequest createGetResultProtocolRequest(final String dataTransferNumbe
* @return Returns complete HttpResponse
*/
public BzstDipSingleTransferResult requestTransferResult(final String dataTransferNumber)
- throws HttpStatusCodeNotExceptedException
- {
- final HttpResponse httpResponse =
- this.executeRequest(this.createGetResultProtocolRequest(dataTransferNumber));
- return new BzstDipSingleTransferResult(dataTransferNumber, httpResponse.statusCode());
- }
-
- private HttpRequest createConfirmResultProtocolRequest(final String transferNumber)
- throws HttpStatusCodeNotExceptedException
+ throws IOException
{
- return HttpRequest.newBuilder()
- .uri(URI.create(this.configuration.getRealmEnvironmentBaseUrl() + DIP_MD + transferNumber + "/protocol"))
- .method(PATCH, HttpRequest.BodyPublishers.noBody())
- .header(AUTHORIZATION_STRING, BEARER_STRING + this.getAccessToken())
- .build();
+ try(
+ final InputStream inputStream = this.client.protokollAbrufen(
+ dataTransferNumber,
+ this.bearerTokenRequester.getAccessTokenWithBearerPrefix()
+ )
+ )
+ {
+ final String text = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
+
+ // TODO: Check text
+ return new BzstDipSingleTransferResult(dataTransferNumber, 2);
+
+ // return new BzstDipSingleTransferResult(dataTransferNumber, httpResponse.statusCode());
+ }
}
/**
* Confirm the result protocol
*/
- public BzstDipSingleTransferResult confirmTransfer(final String transferNumber)
- throws HttpStatusCodeNotExceptedException
- {
- final HttpResponse httpResponse =
- this.executeRequest(this.createConfirmResultProtocolRequest(transferNumber), OK_HTTP_STATUS_CODE);
- return new BzstDipSingleTransferResult(transferNumber, httpResponse.statusCode());
- }
-
- public HttpRequest createAbortSubmissionRequest(final String dataTransferNumber)
- throws HttpStatusCodeNotExceptedException
+ public BzstDipSingleTransferResult confirmTransfer(final String dataTransferNumber)
{
- return HttpRequest.newBuilder()
- .uri(URI.create(this.configuration.getRealmEnvironmentBaseUrl() + DIP_MD + dataTransferNumber + "/abort"))
- .method(PATCH, HttpRequest.BodyPublishers.noBody())
- .header(AUTHORIZATION_STRING, BEARER_STRING + this.getAccessToken())
- .build();
+ this.client.protokollErhalten(
+ dataTransferNumber,
+ this.bearerTokenRequester.getAccessTokenWithBearerPrefix()
+ );
+ return new BzstDipSingleTransferResult(dataTransferNumber, OK_HTTP_STATUS_CODE);
}
- public String abortSubmission(final String dataTransferNumber) throws HttpStatusCodeNotExceptedException
+ public void abortSubmission(final String dataTransferNumber)
{
LOGGER.error("Aborting submission...");
- final HttpResponse httpResponse = this.executeRequest(
- this.createAbortSubmissionRequest(dataTransferNumber), OK_HTTP_STATUS_CODE);
+ this.client.einreichungAbbrechen(
+ dataTransferNumber,
+ this.bearerTokenRequester.getAccessTokenWithBearerPrefix()
+ );
LOGGER.debug("Aborted successfully.");
-
- return httpResponse.body();
}
/**
@@ -285,7 +178,7 @@ public String abortSubmission(final String dataTransferNumber) throws HttpStatus
* @return returns true if the method should be called later again because the result is not yet available
*/
public BzstDipRequestStatusResult readAndConfirmDataTransferNumbers()
- throws HttpStatusCodeNotExceptedException, IOException
+ throws IOException
{
final List dataTransferNumbers = this.requestResultLogs();
LOGGER.debug("DataTransferNumbers {}", dataTransferNumbers);
@@ -301,7 +194,7 @@ public BzstDipRequestStatusResult readAndConfirmDataTransferNumbers()
}
private BzstDipSingleTransferResult requestSingleTransferAndConfirm(final String transferNumber)
- throws HttpStatusCodeNotExceptedException
+ throws IOException
{
final BzstDipSingleTransferResult singleTransferResult = this.requestTransferResult(transferNumber);
LOGGER.debug(
@@ -316,19 +209,4 @@ private BzstDipSingleTransferResult requestSingleTransferAndConfirm(final String
}
return singleTransferResult;
}
-
- private static String createFormForParameters(final HashMap parameters)
- {
- // Creating form with all parameters
- return parameters.keySet().stream()
- .map(key -> key + "=" + URLEncoder.encode(parameters.get(key), StandardCharsets.UTF_8))
- .collect(Collectors.joining("&"));
- }
-
- @Override
- public void close()
- {
- // For Java 21
- // this.httpClient.close();
- }
}
diff --git a/openapi/INFO.md b/openapi/INFO.md
new file mode 100644
index 00000000..8a9c7278
--- /dev/null
+++ b/openapi/INFO.md
@@ -0,0 +1,8 @@
+This ``openapi.yml`` is based on the [official available one](https://www.bzst.de/SharedDocs/Downloads/DE/EOP_BOP/dip_open_api.yaml) with minor modifications.
+
+The Java API Client can be generated using ``mvn clean compile -P openapi-generator`` inside [``bzst-dip-java-client``](../bzst-dip-java-client/).
+
+Helpful links:
+* https://jsonformatter.org/json-to-jsonschema
+* https://swagger.io/specification/
+* https://editor.swagger.io/
\ No newline at end of file
diff --git a/openapi/openapi.yml b/openapi/openapi.yml
new file mode 100644
index 00000000..8f30794a
--- /dev/null
+++ b/openapi/openapi.yml
@@ -0,0 +1,271 @@
+openapi: 3.0.1
+info:
+ title: dip-mds
+ description: DIP-Massendatenschnittstelle
+ version: DIP-MDS 1.3
+tags:
+ - name: MdEinreichenProvider
+ description: Einreichen von Massendatenlieferungen
+paths:
+ /dip/start/{fachverfahren}:
+ post:
+ tags:
+ - MdEinreichenProvider
+ summary: Anfordern einer Datentransfernummer und Einleiten einer Massendatenlieferung
+ description: >-
+ Anfordern einer Datentransfernummer zur Identifikation der Lieferung und Einleiten einer Massendatenlieferung
+ operationId: einreichungAnmelden
+ parameters:
+ - name: fachverfahren
+ in: path
+ description: 'Das Ziel-Fachverfahren'
+ required: true
+ schema:
+ type: string
+ - name: Authorization
+ schema:
+ type: string
+ in: header
+ responses:
+ '201':
+ description: Datentransfer erfolgreich initiiert
+ content:
+ text/plain:
+ schema:
+ type: string
+ '401':
+ description: Ungültiger Authorization Header
+ '404':
+ description: Zielfachverfahren nicht gefunden
+ '429':
+ description: Der Client hat zu viele Anfragen in einem bestimmten Zeitraum gesendet
+ '500':
+ description: Interner Fehler
+ /dip/md/{datentransfernummer}/xml:
+ put:
+ tags:
+ - MdEinreichenProvider
+ summary: Einreichung des XML
+ description: >-
+ Einreichung der Daten-XML unter Angabe einer Datentransfernummer
+ operationId: massendatenEinreichen
+ parameters:
+ - name: datentransfernummer
+ in: path
+ description: 'Die Datentransfernummer, die die Transaktion identifiziert'
+ required: true
+ schema:
+ type: string
+ - name: Authorization
+ schema:
+ type: string
+ in: header
+ requestBody:
+ description: >-
+ Einreichung der Daten-XML unter Angabe einer Datentransfernummer
+ content:
+ application/octet-stream:
+ schema:
+ type: InputStream
+ responses:
+ '200':
+ description: Einreichung erfolgreich
+ '400':
+ description: Ungültige Datentransfernummer
+ '401':
+ description: Ungültiger Authorization Header
+ '410':
+ description: Datentransfer wurde bereits beendet
+ '424':
+ description: Der Datenübermittler ist dem Vorgang nicht zugeordnet
+ '500':
+ description: Interner Fehler
+ /dip/md/{datentransfernummer}/attachment:
+ put:
+ tags:
+ - MdEinreichenProvider
+ summary: Einreichung zusätzlicher Anhänge
+ description: >-
+ Einreichung zusätzlicher Anhänge unter Angabe einer Datentransfernummer
+ operationId: anhangEinreichen
+ parameters:
+ - name: datentransfernummer
+ in: path
+ description: 'Die Datentransfernummer, die die Transaktion identifiziert'
+ required: true
+ schema:
+ type: string
+ - name: Authorization
+ schema:
+ type: string
+ in: header
+ requestBody:
+ description: >-
+ Einreichung zusätzlicher Anhänge unter Angabe einer Datentransfernummer
+ content:
+ application/octet-stream:
+ schema:
+ type: InputStream
+ responses:
+ '200':
+ description: Einreichung erfolgreich
+ '400':
+ description: Ungültige Datentransfernummer
+ '401':
+ description: Ungültiger Authorization Header
+ '424':
+ description: Der Datenübermittler ist dem Vorgang nicht zugeordnet
+ '500':
+ description: Interner Fehler
+ /dip/md/{datentransfernummer}/finish:
+ patch:
+ tags:
+ - MdEinreichenProvider
+ summary: Erklärung, dass die Massendatenlieferung abgeschlossen ist
+ description: >-
+ Erklärung der Fertigstellung der Massendatenlieferung
+ operationId: einreichungBeenden
+ parameters:
+ - name: datentransfernummer
+ in: path
+ description: 'Die Datentransfernummer, die die Transaktion identifiziert'
+ required: true
+ schema:
+ type: string
+ - name: Authorization
+ schema:
+ type: string
+ in: header
+ responses:
+ '200':
+ description: Anfrage erfolgreich
+ '400':
+ description: Ungültige Datentransfernummer
+ '401':
+ description: Ungültiger Authorization Header
+ '410':
+ description: Datentransfer wurde bereits beendet
+ '424':
+ description: Der Datenübermittler ist dem Vorgang nicht zugeordnet
+ '500':
+ description: Interner Fehler
+ /dip/md/{datentransfernummer}/abort:
+ patch:
+ tags:
+ - MdEinreichenProvider
+ summary: Abbruch der laufenden Übertragung und Verwerfen der bisher übertragenen Dateien
+ description: >-
+ Verkünden der Absicht, die laufende Massendatenlieferung abzubrechen und die übertragenen Dateien zu verwerfen
+ operationId: einreichungAbbrechen
+ parameters:
+ - name: datentransfernummer
+ in: path
+ description: 'Die Datentransfernummer, die die Transaktion identifiziert'
+ required: true
+ schema:
+ type: string
+ - name: Authorization
+ schema:
+ type: string
+ in: header
+ responses:
+ '200':
+ description: Anfrage erfolgreich
+ '400':
+ description: Ungültige Datentransfernummer
+ '401':
+ description: Ungültiger Authorization Header
+ '410':
+ description: Datentransfer wurde bereits beendet
+ '424':
+ description: Der Datenübermittler ist dem Vorgang nicht zugeordnet
+ '500':
+ description: Interner Fehler
+ /dip/md/{datentransfernummer}/protocol:
+ get:
+ tags:
+ - MdEinreichenProvider
+ summary: Abruf des Ergebnisprotokolls
+ description: Abruf des Ergebnisprotokolls
+ operationId: protokollAbrufen
+ parameters:
+ - name: datentransfernummer
+ in: path
+ description: 'Die Datentransfernummer, die die Transaktion identifiziert'
+ required: true
+ schema:
+ type: string
+ - name: Authorization
+ schema:
+ type: string
+ in: header
+ responses:
+ '200':
+ description: Anfrage erfolgreich
+ content:
+ application/octet-stream:
+ schema:
+ type: InputStream
+ '400':
+ description: Ungültige Datentransfernummer
+ '401':
+ description: Ungültiger Authorization Header
+ '404':
+ description: Protokoll liegt nicht vor
+ '424':
+ description: Der Datenübermittler ist dem Vorgang nicht zugeordnet
+ '500':
+ description: Interner Fehler
+ patch:
+ tags:
+ - MdEinreichenProvider
+ summary: Erhalt des Protokolls bestätigen
+ description: Erhalt des Protokolls bestätigen
+ operationId: protokollErhalten
+ parameters:
+ - name: datentransfernummer
+ in: path
+ description: 'Die Datentransfernummer, die die Transaktion identifiziert'
+ required: true
+ schema:
+ type: string
+ - name: Authorization
+ schema:
+ type: string
+ in: header
+ responses:
+ '200':
+ description: Anfrage erfolgreich
+ '400':
+ description: Ungültige Datentransfernummer
+ '401':
+ description: Ungültiger Authorization Header
+ '404':
+ description: Protokoll liegt nicht vor
+ '424':
+ description: Der Datenübermittler ist dem Vorgang nicht zugeordnet
+ '500':
+ description: Interner Fehler
+ /dip/md/protocolnumbers:
+ get:
+ tags:
+ - MdEinreichenProvider
+ summary: Abruf einer Liste aller Datentransfernummern mit verfügbarem Protokoll
+ description: Abruf einer Liste aller Datentransfernummern mit verfügbarem Protokoll
+ operationId: alleProtokollnummern
+ parameters:
+ - name: Authorization
+ schema:
+ type: string
+ in: header
+ responses:
+ '200':
+ description: Anfrage erfolgreich
+ content:
+ application/octet-stream:
+ schema:
+ type: InputStream
+ '401':
+ description: Ungültiger Authorization Header
+ '500':
+ description: Interner Fehler