From 8f3b805a558c4ed454db2b691032cea800d7b6dd Mon Sep 17 00:00:00 2001 From: Christof Rabensteiner Date: Tue, 16 Jul 2019 14:33:26 +0200 Subject: Implement ForwardResponseToService Sink And All Its Implications MZS Schema Change: - Add configuration for ForwardResponseToServiceSink (add parameters in mzs:DeliveryRequest/Config) - Add sink configuration in application.yaml, convert from Spring Environment to ConfigType, and merge ConfigTypes. - Validate sink configuration completeness. Contract added: - Add contract mzs2app.wsdl: This contract specifies how mzs:DeliveryRequestStatus' and mzs:DeliveryNotifications are forwarded to the sender application. - Implement "ForwardResponseToService" Sink. - Add and implement MsgResponse.sendToMzsClient() : This is a somewhat unfortunate solution because, intuitively, sending should be done by it's caller, the "ForwardResponseToService"-sink. However, this solution prevents differences between msg:DeliveryRequestStatus and msg:DeliveryNotification (and code that needs to handle differences, i.e. sending) from sprawling outside of the respective MsgResponse derivatives. We move the entire "send" process into MsgResponse to prevent a hard-to-maintain "if type == notification then do x else to y" construct in ForwardResponseToServiceSink. Otherwise, introducing the MsgResponse wrapper was pointless. --- .../backend/ForwardResponseToServiceSink.java | 33 ++++++++++++++ .../gv/egiz/moazs/backend/MsgResponseBackend.java | 20 ++++++--- .../java/at/gv/egiz/moazs/client/MzsClient.java | 13 ------ .../at/gv/egiz/moazs/preprocess/ConfigUtil.java | 52 +++++++++++++++++++--- .../preprocess/MzsDeliveryRequestValidator.java | 42 +++++++++++------ .../at/gv/egiz/moazs/scheme/Msg2MzsConverter.java | 11 +++-- .../java/at/gv/egiz/moazs/scheme/MsgResponse.java | 4 ++ .../gv/egiz/moazs/scheme/NotificationResponse.java | 24 +++++++--- .../egiz/moazs/scheme/RequestStatusResponse.java | 9 ++++ .../java/at/gv/egiz/moazs/service/MzsService.java | 8 ++-- 10 files changed, 163 insertions(+), 53 deletions(-) create mode 100644 src/main/java/at/gv/egiz/moazs/backend/ForwardResponseToServiceSink.java delete mode 100644 src/main/java/at/gv/egiz/moazs/client/MzsClient.java (limited to 'src/main/java') diff --git a/src/main/java/at/gv/egiz/moazs/backend/ForwardResponseToServiceSink.java b/src/main/java/at/gv/egiz/moazs/backend/ForwardResponseToServiceSink.java new file mode 100644 index 0000000..4b3c085 --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/backend/ForwardResponseToServiceSink.java @@ -0,0 +1,33 @@ +package at.gv.egiz.moazs.backend; + +import at.gv.egiz.moazs.client.ClientFactory; +import at.gv.egiz.moazs.repository.DeliveryRepository; +import at.gv.egiz.moazs.scheme.Msg2MzsConverter; +import at.gv.egiz.moazs.scheme.MsgResponse; +import at.gv.zustellung.app2mzs.xsd.ClientType; +import at.gv.zustellung.app2mzs.xsd.Mzs2AppPortType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.concurrent.CompletableFuture; + +@Component +public class ForwardResponseToServiceSink { + + private final ClientFactory factory; + private final DeliveryRepository repository; + private final Msg2MzsConverter converter; + + @Autowired + public ForwardResponseToServiceSink(ClientFactory factory, DeliveryRepository repository, Msg2MzsConverter converter) { + this.factory = factory; + this.repository = repository; + this.converter = converter; + } + + public CompletableFuture send(MsgResponse msgResponse, ClientType params) { + var binaryResponse = repository.retrieveBinaryResponse(msgResponse.getResponseID()); + Mzs2AppPortType client = factory.create(params, Mzs2AppPortType.class); + return msgResponse.sendToMzsClient(converter, binaryResponse, client); + } +} diff --git a/src/main/java/at/gv/egiz/moazs/backend/MsgResponseBackend.java b/src/main/java/at/gv/egiz/moazs/backend/MsgResponseBackend.java index 59db396..9e3cd36 100644 --- a/src/main/java/at/gv/egiz/moazs/backend/MsgResponseBackend.java +++ b/src/main/java/at/gv/egiz/moazs/backend/MsgResponseBackend.java @@ -26,18 +26,22 @@ public class MsgResponseBackend implements Consumer { private final DeliveryRepository repository; private final Consumer signatureVerifier; - private final SaveResponseToFileSink saveResponseToFileSink; + private final SaveResponseToFileSink saveResponseSink; private final LogResponseSink logResponseSink; + private final ForwardResponseToServiceSink forwardResponseSink; @Autowired public MsgResponseBackend(DeliveryRepository repository, Consumer signatureVerifier, SaveResponseToFileSink saveResponseToFileSink, - LogResponseSink logResponseSink) { + LogResponseSink logResponseSink, + ForwardResponseToServiceSink forwardResponseSink) { this.repository = repository; this.signatureVerifier = signatureVerifier; - this.saveResponseToFileSink = saveResponseToFileSink; + this.saveResponseSink = saveResponseToFileSink; this.logResponseSink = logResponseSink; + this.forwardResponseSink = forwardResponseSink; + } /** @@ -84,13 +88,19 @@ public class MsgResponseBackend implements Consumer { var sinkParams = getSinkParams(msgResponse); - if (sinkParams.getSafeResponseToFile().isActive()) { - supplyAsync(() -> saveResponseToFileSink.save(msgResponse, sinkParams.getSafeResponseToFile().getPath())); + if (sinkParams.getSaveResponseToFile().isActive()) { + supplyAsync(() -> saveResponseSink.save(msgResponse, sinkParams.getSaveResponseToFile().getPath())); } if (sinkParams.isLogResponse()) { supplyAsync(() -> logResponseSink.log(msgResponse)); } + + if (sinkParams.getForwardResponseToService().isActive()) { + supplyAsync(() -> forwardResponseSink.send( + msgResponse, sinkParams.getForwardResponseToService().getMzsClient())); + } + } private MsgResponseSinksType getSinkParams(MsgResponse msgResponse) { diff --git a/src/main/java/at/gv/egiz/moazs/client/MzsClient.java b/src/main/java/at/gv/egiz/moazs/client/MzsClient.java deleted file mode 100644 index a8f1d27..0000000 --- a/src/main/java/at/gv/egiz/moazs/client/MzsClient.java +++ /dev/null @@ -1,13 +0,0 @@ -package at.gv.egiz.moazs.client; - -import at.gv.zustellung.app2mzs.xsd.DeliveryResponseType; -import org.springframework.stereotype.Component; - -@Component -public class MzsClient { - - public void sendNotification(DeliveryResponseType responseType) { - throw new UnsupportedOperationException("Not implemented."); - } - -} diff --git a/src/main/java/at/gv/egiz/moazs/preprocess/ConfigUtil.java b/src/main/java/at/gv/egiz/moazs/preprocess/ConfigUtil.java index b69b828..a3329cd 100644 --- a/src/main/java/at/gv/egiz/moazs/preprocess/ConfigUtil.java +++ b/src/main/java/at/gv/egiz/moazs/preprocess/ConfigUtil.java @@ -9,6 +9,7 @@ import java.util.Map; import static at.gv.zustellung.app2mzs.xsd.ClientType.clientTypeBuilder; import static at.gv.zustellung.app2mzs.xsd.ConfigType.configTypeBuilder; +import static at.gv.zustellung.app2mzs.xsd.ForwardResponseToServiceType.forwardResponseToServiceTypeBuilder; import static at.gv.zustellung.app2mzs.xsd.KeyStoreType.keyStoreTypeBuilder; import static at.gv.zustellung.app2mzs.xsd.MsgResponseSinksType.msgResponseSinksTypeBuilder; import static at.gv.zustellung.app2mzs.xsd.SSLType.SSLTypeBuilder; @@ -35,8 +36,10 @@ public class ConfigUtil { public static final String MSG_RESPONSE_SINKS_KEY = "msg-response-sinks"; public static final String LOG_RESPONSE_KEY = "log-response"; public static final String SAVE_RESPONSE_TO_FILE_KEY = "save-response-to-file"; - public static final String SAVE_RESPONSE_TO_FILE_ACTIVE_KEY = "active"; + public static final String ACTIVE_KEY = "active"; public static final String SAVE_RESPONSE_TO_FILE_PATH_KEY = "path"; + public static final String FORWARD_RESPONSE_TO_SERVICE_KEY = "forward-response-to-service"; + public static final String MZS_CLIENT_KEY = "mzs-client"; /** @@ -136,18 +139,20 @@ public class ConfigUtil { var logResponse = booleanOrNull(params.get(LOG_RESPONSE_KEY)); - var saveResponseParams = filterMapByPrefix(params, SAVE_RESPONSE_TO_FILE_KEY); - var saveResponse = buildSaveResponse(saveResponseParams); + var saveResponse = buildSaveResponse(filterMapByPrefix(params, SAVE_RESPONSE_TO_FILE_KEY)); + + var forwardResponse = buildForwardResponse(filterMapByPrefix(params, FORWARD_RESPONSE_TO_SERVICE_KEY)); return msgResponseSinksTypeBuilder() .withLogResponse(logResponse) .withSaveResponseToFile(saveResponse) + .withForwardResponseToService(forwardResponse) .build(); } private SaveResponseToFileType buildSaveResponse(Map params) { - var isActive = booleanOrNull(params.get(SAVE_RESPONSE_TO_FILE_ACTIVE_KEY)); + var isActive = booleanOrNull(params.get(ACTIVE_KEY)); var path = params.get(SAVE_RESPONSE_TO_FILE_PATH_KEY); return saveResponseToFileTypeBuilder() @@ -156,6 +161,20 @@ public class ConfigUtil { .build(); } + private ForwardResponseToServiceType buildForwardResponse(Map params) { + + var isActive = booleanOrNull(params.get(ACTIVE_KEY)); + var mzsClientParams = filterMapByPrefix(params, MZS_CLIENT_KEY); + ClientType mzsClient = mzsClientParams.isEmpty() + ? null : buildClient(mzsClientParams); + + return forwardResponseToServiceTypeBuilder() + .withActive(isActive) + .withMzsClient(mzsClient) + .build(); + } + + private Boolean booleanOrNull(String value) { return value == null ? null : Boolean.getBoolean(value); } @@ -261,14 +280,18 @@ public class ConfigUtil { var builder = msgResponseSinksTypeBuilder(fallback); - if (primary.isLogResponse() != null) { + if (primary.isLogResponse() != null) { builder.withLogResponse(primary.isLogResponse()); } - if (primary.getSaveResponseToFile() != null) { + if (primary.getSaveResponseToFile() != null) { builder.withSaveResponseToFile(merge(primary.getSaveResponseToFile(), fallback.getSaveResponseToFile())); } + if (primary.getForwardResponseToService() != null) { + builder.withForwardResponseToService(merge(primary.getForwardResponseToService(), fallback.getForwardResponseToService())); + } + return builder.build(); } @@ -286,6 +309,23 @@ public class ConfigUtil { builder.withPath(primary.getPath()); } + return builder.build(); + } + + private ForwardResponseToServiceType merge(ForwardResponseToServiceType primary, ForwardResponseToServiceType fallback) { + + if (fallback == null) return primary; + + var builder = forwardResponseToServiceTypeBuilder(fallback); + + if (primary.isActive() != null) { + builder.withActive(primary.isActive()); + } + + if (primary.getMzsClient() != null) { + builder.withMzsClient(merge(primary.getMzsClient(), fallback.getMzsClient())); + } + return builder.build(); } diff --git a/src/main/java/at/gv/egiz/moazs/preprocess/MzsDeliveryRequestValidator.java b/src/main/java/at/gv/egiz/moazs/preprocess/MzsDeliveryRequestValidator.java index 8f9cd27..2c2fc36 100644 --- a/src/main/java/at/gv/egiz/moazs/preprocess/MzsDeliveryRequestValidator.java +++ b/src/main/java/at/gv/egiz/moazs/preprocess/MzsDeliveryRequestValidator.java @@ -1,9 +1,6 @@ package at.gv.egiz.moazs.preprocess; -import at.gv.zustellung.app2mzs.xsd.ClientType; -import at.gv.zustellung.app2mzs.xsd.ConfigType; -import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType; -import at.gv.zustellung.app2mzs.xsd.KeyStoreType; +import at.gv.zustellung.app2mzs.xsd.*; import org.springframework.lang.Nullable; import org.springframework.stereotype.Component; @@ -19,8 +16,6 @@ public class MzsDeliveryRequestValidator { return !request.getConfig().isPerformQueryPersonRequest() || (request.getTnvzMetaData() != null && request.getSender().getCorporateBody() != null); - - } /** @@ -33,7 +28,8 @@ public class MzsDeliveryRequestValidator { return profile != null && profile.isPerformQueryPersonRequest() != null && isTVNZClientConfigured(profile.getTNVZClient(), profile.isPerformQueryPersonRequest()) - && isMSGClientConfigured(profile.getMSGClient()); + && isClientConfigured(profile.getMSGClient()) + && areSinksConfigured(profile.getMsgResponseSinks()); } private boolean isTVNZClientConfigured(ClientType tnvzClient, Boolean isPerformQueryPersonRequest) { @@ -44,12 +40,12 @@ public class MzsDeliveryRequestValidator { && isSSLConfigured(tnvzClient)); } - private boolean isMSGClientConfigured(ClientType msgClientParams) { - return msgClientParams != null - && msgClientParams.getURL() != null - && isSSLConfigured(msgClientParams) - && msgClientParams.getReceiveTimeout() != null - && msgClientParams.getConnectionTimeout() != null; + private boolean isClientConfigured(ClientType clientParams) { + return clientParams != null + && clientParams.getURL() != null + && isSSLConfigured(clientParams) + && clientParams.getReceiveTimeout() != null + && clientParams.getConnectionTimeout() != null; } private boolean isSSLConfigured(ClientType clientParams) { @@ -71,4 +67,24 @@ public class MzsDeliveryRequestValidator { && "JKS".equals(trustStore.getFileType()) && trustStore.getFileName() != null); } + + private boolean areSinksConfigured(MsgResponseSinksType sinks) { + return sinks != null + && sinks.isLogResponse() != null + && isSaveResponseToFileConfigured(sinks.getSaveResponseToFile()) + && isForwardResponseToServiceConfigured(sinks.getForwardResponseToService()); + } + + private boolean isSaveResponseToFileConfigured(SaveResponseToFileType fileSink) { + return fileSink != null + && (!fileSink.isActive() || fileSink.getPath() != null); + } + + private boolean isForwardResponseToServiceConfigured(ForwardResponseToServiceType forwardSink) { + return forwardSink != null + && (!forwardSink.isActive() || isClientConfigured(forwardSink.getMzsClient())); + } + + + } diff --git a/src/main/java/at/gv/egiz/moazs/scheme/Msg2MzsConverter.java b/src/main/java/at/gv/egiz/moazs/scheme/Msg2MzsConverter.java index 67f3d13..271cf67 100644 --- a/src/main/java/at/gv/egiz/moazs/scheme/Msg2MzsConverter.java +++ b/src/main/java/at/gv/egiz/moazs/scheme/Msg2MzsConverter.java @@ -1,9 +1,6 @@ package at.gv.egiz.moazs.scheme; -import at.gv.zustellung.app2mzs.xsd.DeliveryResponseType; -import at.gv.zustellung.app2mzs.xsd.ErrorType; -import at.gv.zustellung.app2mzs.xsd.PartialSuccessType; -import at.gv.zustellung.app2mzs.xsd.SuccessType; +import at.gv.zustellung.app2mzs.xsd.*; import at.gv.zustellung.msg.xsd.DeliveryAnswerType; import at.gv.zustellung.msg.xsd.DeliveryRequestStatusType; import org.springframework.stereotype.Component; @@ -34,6 +31,12 @@ public class Msg2MzsConverter { return responseBuilder.build(); } + public DeliveryNotificationType convert(at.gv.zustellung.msg.xsd.DeliveryNotificationType notificatione, Optional signedStatus) { + //TODO + return null; + } + + private SuccessType convert(DeliveryRequestStatusType.Success success, Optional signedStatus) { return successTypeBuilder() .withAppDeliveryID(success.getAppDeliveryID()) diff --git a/src/main/java/at/gv/egiz/moazs/scheme/MsgResponse.java b/src/main/java/at/gv/egiz/moazs/scheme/MsgResponse.java index 5370448..8bd88d9 100644 --- a/src/main/java/at/gv/egiz/moazs/scheme/MsgResponse.java +++ b/src/main/java/at/gv/egiz/moazs/scheme/MsgResponse.java @@ -1,9 +1,12 @@ package at.gv.egiz.moazs.scheme; import at.gv.egiz.moazs.MoaZSException; +import at.gv.zustellung.app2mzs.xsd.Mzs2AppPortType; import at.gv.zustellung.msg.xsd.DeliveryAnswerType; import javax.xml.bind.JAXBElement; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; /** * Represents responses to DeliveryRequests that were received from the msg service. @@ -31,5 +34,6 @@ public abstract class MsgResponse { public abstract String getZSDeliveryID(); public abstract DeliveryAnswerType getAnswer(); public abstract MsgResponse generateError(MoaZSException exception); + public abstract CompletableFuture sendToMzsClient(Msg2MzsConverter converter, Optional signedStatus, Mzs2AppPortType client); } diff --git a/src/main/java/at/gv/egiz/moazs/scheme/NotificationResponse.java b/src/main/java/at/gv/egiz/moazs/scheme/NotificationResponse.java index 784d000..21e00a1 100644 --- a/src/main/java/at/gv/egiz/moazs/scheme/NotificationResponse.java +++ b/src/main/java/at/gv/egiz/moazs/scheme/NotificationResponse.java @@ -1,12 +1,16 @@ package at.gv.egiz.moazs.scheme; import at.gv.egiz.moazs.MoaZSException; +import at.gv.zustellung.app2mzs.xsd.Mzs2AppPortType; import at.gv.zustellung.msg.xsd.DeliveryAnswerType; import at.gv.zustellung.msg.xsd.DeliveryNotificationType; import at.gv.zustellung.msg.xsd.ObjectFactory; import javax.xml.bind.JAXBElement; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + import static at.gv.zustellung.msg.xsd.DeliveryNotificationType.deliveryNotificationTypeBuilder; public class NotificationResponse extends MsgResponse { @@ -50,17 +54,23 @@ public class NotificationResponse extends MsgResponse } @Override - public MsgResponse generateError(MoaZSException exception) { + public NotificationResponse generateError(MoaZSException exception) { - //TODO: test this! + //TODO: use copy constructor? var notificationType = deliveryNotificationTypeBuilder() - .withAppDeliveryID(exception.getAppDeliveryID()) - .withDeliverySystem(exception.getDeliverySystem()) - .withGZ(exception.getGz()) - .withZSDeliveryID(exception.getZsDeliveryID()) - .build(); + .withAppDeliveryID(exception.getAppDeliveryID()) + .withDeliverySystem(exception.getDeliverySystem()) + .withGZ(exception.getGz()) + .withZSDeliveryID(exception.getZsDeliveryID()) + .build(); return new NotificationResponse(notificationType); + } + @Override + public CompletableFuture sendToMzsClient(Msg2MzsConverter converter, Optional signedNotification, Mzs2AppPortType client) { + var mzsNotification = converter.convert(notification, signedNotification); + client.forwardNotification(mzsNotification); + return CompletableFuture.completedFuture(null); } } diff --git a/src/main/java/at/gv/egiz/moazs/scheme/RequestStatusResponse.java b/src/main/java/at/gv/egiz/moazs/scheme/RequestStatusResponse.java index 3b4710b..14e22ad 100644 --- a/src/main/java/at/gv/egiz/moazs/scheme/RequestStatusResponse.java +++ b/src/main/java/at/gv/egiz/moazs/scheme/RequestStatusResponse.java @@ -1,12 +1,15 @@ package at.gv.egiz.moazs.scheme; import at.gv.egiz.moazs.MoaZSException; +import at.gv.zustellung.app2mzs.xsd.Mzs2AppPortType; import at.gv.zustellung.msg.xsd.DeliveryAnswerType; import at.gv.zustellung.msg.xsd.DeliveryRequestStatusType; import at.gv.zustellung.msg.xsd.ErrorInfoType; import at.gv.zustellung.msg.xsd.ObjectFactory; import javax.xml.bind.JAXBElement; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; import static at.gv.egiz.moazs.util.NullCoalesce.coalesce; import static at.gv.zustellung.msg.xsd.DeliveryRequestStatusType.Error.errorBuilder; @@ -82,7 +85,13 @@ public class RequestStatusResponse extends MsgResponse sendToMzsClient(Msg2MzsConverter converter, Optional signedStatus, Mzs2AppPortType client) { + var msgStatus = converter.convert(status, signedStatus); + client.forwardStatus(msgStatus); + return CompletableFuture.completedFuture(null); } } diff --git a/src/main/java/at/gv/egiz/moazs/service/MzsService.java b/src/main/java/at/gv/egiz/moazs/service/MzsService.java index c8c0878..cbc56e4 100644 --- a/src/main/java/at/gv/egiz/moazs/service/MzsService.java +++ b/src/main/java/at/gv/egiz/moazs/service/MzsService.java @@ -3,7 +3,6 @@ package at.gv.egiz.moazs.service; import at.gv.egiz.moazs.preprocess.DeliveryRequestAugmenter; import at.gv.egiz.moazs.repository.DeliveryRepository; import at.gv.egiz.moazs.scheme.Msg2MzsConverter; -import at.gv.egiz.moazs.client.MzsClient; import at.gv.egiz.moazs.scheme.RequestStatusResponse; import at.gv.zustellung.app2mzs.xsd.App2MzsPortType; import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType; @@ -37,16 +36,14 @@ public class MzsService implements App2MzsPortType { private final DeliveryRepository repository; private final Consumer backend; - private final MzsClient appClient; private final DeliveryRequestAugmenter augmenter; private final Msg2MzsConverter converter; @Autowired - public MzsService(DeliveryRepository repository, Consumer deliveryRequestBackend, MzsClient appClient, + public MzsService(DeliveryRepository repository, Consumer deliveryRequestBackend, DeliveryRequestAugmenter augmenter, Msg2MzsConverter converter) { this.repository = repository; this.backend = deliveryRequestBackend; - this.appClient = appClient; this.augmenter = augmenter; this.converter = converter; } @@ -69,7 +66,8 @@ public class MzsService implements App2MzsPortType { } catch (TimeoutException e) { logger.info("Answer Timed Out", e); - future.thenAccept(appClient::sendNotification); + //TODO: revise how notification should be sent + //future.thenAccept(appClient::sendNotification); return generatePartialSuccessResponse(appDeliveryID); } catch (Exception e) { -- cgit v1.2.3