diff options
Diffstat (limited to 'src/main')
32 files changed, 809 insertions, 212 deletions
diff --git a/src/main/java/at/gv/egiz/moazs/MoaZSException.java b/src/main/java/at/gv/egiz/moazs/MoaZSException.java index 322f06b..1e86c22 100644 --- a/src/main/java/at/gv/egiz/moazs/MoaZSException.java +++ b/src/main/java/at/gv/egiz/moazs/MoaZSException.java @@ -1,10 +1,13 @@ package at.gv.egiz.moazs; -import at.gv.zustellung.msg.xsd.DeliveryRequestStatusType; -import at.gv.zustellung.msg.xsd.DeliveryRequestType; +import at.gv.zustellung.msg.xsd.DeliveryAnswerType; +import at.gv.zustellung.msg.xsd.PreAdviceNoteSentType; import at.gv.zustellung.tnvz.xsd.PersonResultType; import org.springframework.lang.Nullable; +import java.util.concurrent.ExecutorService; + + public class MoaZSException extends RuntimeException { public static final String ERROR_MZS_MIMETYPE_MISSMATCH = "8001"; @@ -14,25 +17,29 @@ public class MoaZSException extends RuntimeException { @Nullable private final String errorCode; @Nullable - private final PersonResultType tnvzResult; + private final PreAdviceNoteSentType preAdviceNoteSent; + @Nullable + private final String deliverySystem; @Nullable - private final DeliveryRequestStatusType msgResult; + private final String gz; @Nullable - private final DeliveryRequestType msgRequest; + private final String zsDeliveryID; @Nullable - private final at.gv.zustellung.app2mzs.xsd.DeliveryRequestType mzsRequest; + private final String appDeliveryID; - private MoaZSException(String message, Throwable cause, String errorCode, PersonResultType tnvzResult, - DeliveryRequestStatusType msgResult, DeliveryRequestType msgRequest, - at.gv.zustellung.app2mzs.xsd.DeliveryRequestType mzsRequest) { + private MoaZSException(String message, @Nullable Throwable cause, @Nullable String errorCode, @Nullable PreAdviceNoteSentType preAdviceNoteSent, + @Nullable String deliverySystem, @Nullable String gz, @Nullable String zsDeliveryID, + @Nullable String appDeliveryID) { super(message, cause); this.errorCode = errorCode; - this.tnvzResult = tnvzResult; - this.msgResult = msgResult; - this.msgRequest = msgRequest; - this.mzsRequest = mzsRequest; + this.preAdviceNoteSent = preAdviceNoteSent; + this.deliverySystem = deliverySystem; + this.gz = gz; + this.zsDeliveryID = zsDeliveryID; + this.appDeliveryID = appDeliveryID; } + public static MoaZSException moaZSException(String message, Throwable cause) { return moaZSExceptionBuilder(message).withCause(cause).build(); } @@ -63,23 +70,28 @@ public class MoaZSException extends RuntimeException { } @Nullable - public PersonResultType getTnvzResult() { - return tnvzResult; + public PreAdviceNoteSentType getPreAdviceNoteSent() { + return preAdviceNoteSent; + } + + @Nullable + public String getDeliverySystem() { + return deliverySystem; } @Nullable - public DeliveryRequestStatusType getMsgResult() { - return msgResult; + public String getGz() { + return gz; } @Nullable - public at.gv.zustellung.app2mzs.xsd.DeliveryRequestType getMzsRequest() { - return mzsRequest; + public String getZsDeliveryID() { + return zsDeliveryID; } @Nullable - public DeliveryRequestType getMsgRequest() { - return msgRequest; + public String getAppDeliveryID() { + return appDeliveryID; } public static class Builder { @@ -87,14 +99,26 @@ public class MoaZSException extends RuntimeException { private String message; private Throwable cause; private String errorCode; - private PersonResultType tnvzResult; - private DeliveryRequestStatusType msgResult; - private DeliveryRequestType msgRequest; - private at.gv.zustellung.app2mzs.xsd.DeliveryRequestType mzsRequest; + private PreAdviceNoteSentType preAdviceNoteSent; + private String deliverySystem; + private String gz; + private String zsDeliveryID; + private String appDeliveryID; private Builder() { } + public Builder(MoaZSException exception){ + this.message = exception.getMessage(); + this.cause = exception.getCause(); + this.errorCode = exception.getErrorCode(); + this.preAdviceNoteSent = exception.getPreAdviceNoteSent(); + this.deliverySystem = exception.getDeliverySystem(); + this.gz = exception.getGz(); + this.zsDeliveryID = exception.getZsDeliveryID(); + this.appDeliveryID = exception.getAppDeliveryID(); + } + public Builder withMessage(String message) { this.message = message; return this; @@ -115,28 +139,35 @@ public class MoaZSException extends RuntimeException { return this; } - public Builder withTnvzResult(PersonResultType tnvzResult) { - this.tnvzResult = tnvzResult; + public Builder withPreAdviceNoteSent(PersonResultType personResult) { + if (personResult.getError() != null) { + this.preAdviceNoteSent = personResult.getError().getPreAdviceNoteSent(); + } return this; } - public Builder withMsgResult(DeliveryRequestStatusType msgResult) { - this.msgResult = msgResult; + public Builder withDeliverySystem(at.gv.zustellung.app2mzs.xsd.DeliveryRequestType mzsRequest) { + this.deliverySystem = mzsRequest.getConfig().getMSGClient().getURL(); return this; } - public Builder withMsgRequest(DeliveryRequestType msgRequest) { - this.msgRequest = msgRequest; + + public Builder withAllParametersInAnswer(DeliveryAnswerType answer) { + this.deliverySystem = answer.getDeliverySystem(); + this.gz = answer.getGZ(); + this.zsDeliveryID = answer.getZSDeliveryID(); + this.appDeliveryID = answer.getAppDeliveryID(); return this; } - public Builder withMzsRequest(at.gv.zustellung.app2mzs.xsd.DeliveryRequestType mzsRequest) { - this.mzsRequest = mzsRequest; + public Builder withAppDeliveryID(String appDeliveryID) { + this.appDeliveryID = appDeliveryID; return this; } public MoaZSException build() { - return new MoaZSException(message, cause, errorCode, tnvzResult, msgResult, msgRequest, mzsRequest); + return new MoaZSException(message, cause, errorCode, preAdviceNoteSent, deliverySystem, gz, + zsDeliveryID, appDeliveryID); } } diff --git a/src/main/java/at/gv/egiz/moazs/scheme/MzsClient.java b/src/main/java/at/gv/egiz/moazs/client/MzsClient.java index 98e0bc8..a8f1d27 100644 --- a/src/main/java/at/gv/egiz/moazs/scheme/MzsClient.java +++ b/src/main/java/at/gv/egiz/moazs/client/MzsClient.java @@ -1,4 +1,4 @@ -package at.gv.egiz.moazs.scheme; +package at.gv.egiz.moazs.client; import at.gv.zustellung.app2mzs.xsd.DeliveryResponseType; import org.springframework.stereotype.Component; diff --git a/src/main/java/at/gv/egiz/moazs/scheme/TnvzHelper.java b/src/main/java/at/gv/egiz/moazs/client/TnvzHelper.java index 70c20bb..884be3e 100644 --- a/src/main/java/at/gv/egiz/moazs/scheme/TnvzHelper.java +++ b/src/main/java/at/gv/egiz/moazs/client/TnvzHelper.java @@ -1,4 +1,4 @@ -package at.gv.egiz.moazs.scheme; +package at.gv.egiz.moazs.client; import at.gv.egiz.moazs.MoaZSException; import at.gv.egiz.moazs.scheme.Mzs2MsgConverter; @@ -187,7 +187,8 @@ public class TnvzHelper { } var tnvzResult = results.get(0); - mzsBuilder.withTnvzResult(tnvzResult); + mzsBuilder.withPreAdviceNoteSent(tnvzResult); + if (tnvzResult.getError() != null) { var info = tnvzResult.getError().getErrorInfo(); throw mzsBuilder.withErrorCode(info.getCode()) diff --git a/src/main/java/at/gv/egiz/moazs/config/MzsServiceConfig.java b/src/main/java/at/gv/egiz/moazs/config/MzsServiceConfig.java deleted file mode 100644 index 9fd14eb..0000000 --- a/src/main/java/at/gv/egiz/moazs/config/MzsServiceConfig.java +++ /dev/null @@ -1,30 +0,0 @@ -package at.gv.egiz.moazs.config; - -import at.gv.egiz.moazs.scheme.MzsService; -import at.gv.zustellung.app2mzs.xsd.App2Mzs; -import org.apache.cxf.Bus; -import org.apache.cxf.jaxws.EndpointImpl; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import javax.xml.ws.Endpoint; - -@Configuration -public class MzsServiceConfig { - - @Bean - @Autowired - public Endpoint endpoint(Bus bus, MzsService mzsService, App2Mzs app2mzs) { - EndpointImpl endpoint = new EndpointImpl(bus, mzsService); - endpoint.setAddress("/"); - endpoint.setServiceName(app2mzs.getServiceName()); - endpoint.setWsdlLocation(app2mzs.getWSDLDocumentLocation().toString()); - endpoint.publish(); - return endpoint; - } - - @Bean public App2Mzs app2mzs() { - return new App2Mzs(); - } -} diff --git a/src/main/java/at/gv/egiz/moazs/config/PreprocessConfig.java b/src/main/java/at/gv/egiz/moazs/config/PreprocessConfig.java index b24db28..76bfb30 100644 --- a/src/main/java/at/gv/egiz/moazs/config/PreprocessConfig.java +++ b/src/main/java/at/gv/egiz/moazs/config/PreprocessConfig.java @@ -1,6 +1,6 @@ package at.gv.egiz.moazs.config; -import at.gv.egiz.moazs.scheme.MzsDeliveryRequestValidator; +import at.gv.egiz.moazs.preprocess.MzsDeliveryRequestValidator; import at.gv.egiz.moazs.preprocess.*; import at.gv.zustellung.app2mzs.xsd.ConfigType; import org.springframework.beans.factory.annotation.Autowired; diff --git a/src/main/java/at/gv/egiz/moazs/config/RepositoryConfig.java b/src/main/java/at/gv/egiz/moazs/config/RepositoryConfig.java new file mode 100644 index 0000000..ee73b9e --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/config/RepositoryConfig.java @@ -0,0 +1,32 @@ +package at.gv.egiz.moazs.config; + +import at.gv.egiz.moazs.repository.BinaryRepository; +import at.gv.egiz.moazs.repository.InMemoryBinaryRepository; +import at.gv.egiz.moazs.scheme.NameSpace; +import at.gv.egiz.moazs.scheme.NotificationResponse; +import at.gv.egiz.moazs.scheme.RequestStatusResponse; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +import java.util.Map; + +@Configuration +@Profile("!cluster") +public class RepositoryConfig { + + @Value("${repository.expiresAfterWrite}") + private int expiresAfterWrite; + + @Bean + public BinaryRepository binaryRepository() { + return new InMemoryBinaryRepository(expiresAfterWrite); + } + + @Bean + public Map<String, String> idSuffixes() { + return Map.of(NameSpace.MSG_DELIVERY_REQUEST_STATUS, RequestStatusResponse.getIdSuffix(), + NameSpace.MSG_DELIVERY_NOTIFICATION, NotificationResponse.getIdSuffix()); + } +} diff --git a/src/main/java/at/gv/egiz/moazs/config/ServicesConfig.java b/src/main/java/at/gv/egiz/moazs/config/ServicesConfig.java new file mode 100644 index 0000000..8e354ab --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/config/ServicesConfig.java @@ -0,0 +1,46 @@ +package at.gv.egiz.moazs.config; + +import at.gv.egiz.moazs.service.MsgService; +import at.gv.egiz.moazs.service.MzsService; +import at.gv.egiz.moazs.util.EndpointFactory; +import at.gv.egiz.moazs.util.StoreSOAPBodyBinaryInRepositoryInterceptor; +import at.gv.zustellung.app2mzs.xsd.App2Mzs; +import at.gv.zustellung.msg.xsd.Zuse2AppPortService; +import org.apache.cxf.interceptor.Interceptor; +import org.apache.cxf.message.Message; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.xml.ws.Endpoint; + +@Configuration +public class ServicesConfig { + + @Autowired + private EndpointFactory endpointFactory; + + @Bean + @Autowired + public Endpoint msgEndpoint(MsgService msgService, + Zuse2AppPortService zuse2app, + Interceptor<Message> msgInterceptor) { + return endpointFactory.create(msgService, zuse2app, msgInterceptor); + } + + @Bean + @Autowired + public Endpoint mzsEndpoint(MzsService mzsService, App2Mzs app2mzs) { + return endpointFactory.create(mzsService, app2mzs); + } + + @Bean + public Zuse2AppPortService zuse2App() { + return new Zuse2AppPortService(); + } + + @Bean public App2Mzs app2mzs() { + return new App2Mzs(); + } + +} diff --git a/src/main/java/at/gv/egiz/moazs/pipeline/SingleThreadedDeliveryPipeline.java b/src/main/java/at/gv/egiz/moazs/pipeline/SingleThreadedDeliveryPipeline.java index 783df32..69065d7 100644 --- a/src/main/java/at/gv/egiz/moazs/pipeline/SingleThreadedDeliveryPipeline.java +++ b/src/main/java/at/gv/egiz/moazs/pipeline/SingleThreadedDeliveryPipeline.java @@ -1,17 +1,17 @@ -package at.gv.egiz.moazs.pipeline; +package at.gv.egiz.moazs.process; import at.gv.egiz.moazs.MoaZSException; -import at.gv.egiz.moazs.util.ClientFactory; +import at.gv.egiz.moazs.client.ClientFactory; +import at.gv.egiz.moazs.client.TnvzHelper; +import at.gv.egiz.moazs.repository.BinaryRepository; import at.gv.egiz.moazs.repository.DeliveryRepository; import at.gv.egiz.moazs.scheme.Mzs2MsgConverter; -import at.gv.egiz.moazs.scheme.NameSpace; -import at.gv.egiz.moazs.scheme.TnvzHelper; +import at.gv.egiz.moazs.scheme.RequestStatusResponse; +import at.gv.egiz.moazs.verify.MsgResponseVerifier; import at.gv.egiz.moazs.verify.SignatureVerifier; import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType; import at.gv.zustellung.msg.xsd.App2ZusePort; -import at.gv.zustellung.msg.xsd.DeliveryAnswerType; -import at.gv.zustellung.msg.xsd.DeliveryRequestStatusType; import at.gv.zustellung.tnvz.xsd.TNVZServicePort; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; @@ -19,10 +19,7 @@ import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component; import static at.gv.egiz.moazs.MoaZSException.moaZSExceptionBuilder; -import static at.gv.egiz.moazs.util.NullCoalesce.coalesce; -import static at.gv.zustellung.msg.xsd.DeliveryRequestStatusType.Error.errorBuilder; -import static at.gv.zustellung.msg.xsd.DeliveryRequestStatusType.deliveryRequestStatusTypeBuilder; -import static at.gv.zustellung.msg.xsd.ErrorInfoType.errorInfoTypeBuilder; +import static at.gv.egiz.moazs.scheme.RequestStatusResponse.generateErrorFromException; import static java.lang.String.format; @Component @@ -30,8 +27,11 @@ import static java.lang.String.format; public class SingleThreadedDeliveryPipeline implements DeliveryPipeline { private static final Logger log = Logger.getLogger(SingleThreadedDeliveryPipeline.class); + private static final String MZS_PIPELINE_ERROR_MSG = + "An error occured while processing the DeliveryRequest with AppDeliveryID=%s. "; private final DeliveryRepository repository; + private final BinaryRepository binaryRepository; private final TnvzHelper tnvzHelper; private final Mzs2MsgConverter converter; private final ClientFactory clientFactory; @@ -39,12 +39,13 @@ public class SingleThreadedDeliveryPipeline implements DeliveryPipeline { @Autowired public SingleThreadedDeliveryPipeline(DeliveryRepository repository, + BinaryRepository binaryStatusRepository, TnvzHelper tnvzHelper, Mzs2MsgConverter converter, ClientFactory clientFactory, - SignatureVerifier verifier - ) { + SignatureVerifier verifier) { this.repository = repository; + this.binaryRepository = binaryStatusRepository; this.tnvzHelper = tnvzHelper; this.converter = converter; this.clientFactory = clientFactory; @@ -58,89 +59,49 @@ public class SingleThreadedDeliveryPipeline implements DeliveryPipeline { try { var mzsRequest = repository.getDeliveryRequest(appDeliveryId).orElseThrow(); - exceptionBuilder.withMzsRequest(mzsRequest); + exceptionBuilder.withDeliverySystem(mzsRequest); at.gv.zustellung.msg.xsd.DeliveryRequestType msgRequest = buildMsgRequest(mzsRequest, exceptionBuilder); - exceptionBuilder.withMsgRequest(msgRequest); var msgClientParams = mzsRequest.getConfig().getMSGClient(); App2ZusePort client = clientFactory.create(msgClientParams, App2ZusePort.class); var status = client.delivery(msgRequest); - exceptionBuilder.withMsgResult(status); - verifySignedStatus(appDeliveryId, exceptionBuilder); - repository.add(status); + var response = new RequestStatusResponse(status); + exceptionBuilder.withAllParametersInAnswer(response.getAnswer()); - } catch (MoaZSException exception) { - - log.error(format("An error occured while processing the DeliveryRequest with AppDeliveryID=%s. ", - appDeliveryId), exception); - - var errorStatus = generateErrorStatus(exception, appDeliveryId); - repository.add(errorStatus); - } - } + verifySignedStatus(response.getResponseID(), exceptionBuilder); + repository.add(response); - private at.gv.zustellung.msg.xsd.DeliveryRequestType buildMsgRequest(DeliveryRequestType mzsRequest, - MoaZSException.Builder exceptionBuilder) { - if (mzsRequest.getConfig().isPerformQueryPersonRequest()) { - var tnvzClientParams = mzsRequest.getConfig().getTNVZClient(); - TNVZServicePort tvnzPort = clientFactory.create(tnvzClientParams, TNVZServicePort.class); - var identification = tnvzHelper.performQueryPersonRequest(mzsRequest, tvnzPort, exceptionBuilder); - return converter.convert(mzsRequest, identification); - } else { - return converter.convert(mzsRequest); + } catch (MoaZSException exception) { + log.error(format(MZS_PIPELINE_ERROR_MSG, appDeliveryId), exception); + var errorResponse = generateErrorFromException(exception); + repository.add(errorResponse); } } private void verifySignedStatus(String appDeliveryId, MoaZSException.Builder exceptionBuilder) throws MoaZSException { - try { - var signedStatus = repository.getSignedDeliveryRequestStatus(appDeliveryId).get(); + var signedStatus = binaryRepository.get(appDeliveryId).get(); verifier.verify(signedStatus); - } catch (Exception ex) { - throw exceptionBuilder.withMessage(format("Signature of DeliveryRequestStatus with AppDeliveryID=%s " + - " is not valid.", appDeliveryId)) + } catch (MoaZSException ex) { + throw exceptionBuilder.withMessage(format(MsgResponseVerifier.MOASP_SIGNATURE_INVALID_ERROR_MSG, appDeliveryId)) .withErrorCode(MoaZSException.ERROR_MOASP_SIGNATURE_INVALID) .withCause(ex) .build(); } } - private DeliveryRequestStatusType generateErrorStatus(MoaZSException exception, String appDeliveryId) { - - var infoBuilder = errorInfoTypeBuilder() - .withText(exception.getMessage()) - .withCode(exception.getErrorCode()); - - var errorBuilder = errorBuilder() - .withErrorInfo(infoBuilder.build()) - .withAppDeliveryID(appDeliveryId); - - if (exception.getMzsRequest() != null) { - errorBuilder.withDeliverySystem(exception.getMzsRequest().getConfig().getMSGClient().getURL()); - } - - if (exception.getTnvzResult() != null && exception.getTnvzResult().getError() != null) { - errorBuilder.withPreAdviceNoteSent(exception.getTnvzResult().getError().getPreAdviceNoteSent()); - } - - if (exception.getMsgResult() != null) { - var answer = getAnswerFromResult(exception.getMsgResult()); - errorBuilder.withGZ(answer.getGZ()); - errorBuilder.withZSDeliveryID(answer.getZSDeliveryID()); + private at.gv.zustellung.msg.xsd.DeliveryRequestType buildMsgRequest(DeliveryRequestType mzsRequest, + MoaZSException.Builder exceptionBuilder) throws MoaZSException { + if (mzsRequest.getConfig().isPerformQueryPersonRequest()) { + var tnvzClientParams = mzsRequest.getConfig().getTNVZClient(); + TNVZServicePort tvnzPort = clientFactory.create(tnvzClientParams, TNVZServicePort.class); + var identification = tnvzHelper.performQueryPersonRequest(mzsRequest, tvnzPort, exceptionBuilder); + return converter.convert(mzsRequest, identification); + } else { + return converter.convert(mzsRequest); } - - return deliveryRequestStatusTypeBuilder() - .withError(errorBuilder.build()) - .withVersion(NameSpace.MSG_VERSION) - .build(); - - } - - private DeliveryAnswerType getAnswerFromResult(DeliveryRequestStatusType msgResult) { - return coalesce(msgResult.getSuccess(), msgResult.getPartialSuccess(), msgResult.getError()).get(); } - } diff --git a/src/main/java/at/gv/egiz/moazs/preprocess/ConfigProfileGenerator.java b/src/main/java/at/gv/egiz/moazs/preprocess/ConfigProfileGenerator.java index d651570..5e81f0d 100644 --- a/src/main/java/at/gv/egiz/moazs/preprocess/ConfigProfileGenerator.java +++ b/src/main/java/at/gv/egiz/moazs/preprocess/ConfigProfileGenerator.java @@ -1,7 +1,6 @@ package at.gv.egiz.moazs.preprocess; import at.gv.egiz.moazs.MoaZSException; -import at.gv.egiz.moazs.scheme.MzsDeliveryRequestValidator; import at.gv.egiz.moazs.util.StringUtils; import at.gv.zustellung.app2mzs.xsd.ConfigType; import org.slf4j.Logger; diff --git a/src/main/java/at/gv/egiz/moazs/preprocess/DeliveryRequestAugmenter.java b/src/main/java/at/gv/egiz/moazs/preprocess/DeliveryRequestAugmenter.java index 783536c..eac7ea6 100644 --- a/src/main/java/at/gv/egiz/moazs/preprocess/DeliveryRequestAugmenter.java +++ b/src/main/java/at/gv/egiz/moazs/preprocess/DeliveryRequestAugmenter.java @@ -1,6 +1,5 @@ package at.gv.egiz.moazs.preprocess; -import at.gv.egiz.moazs.scheme.MzsDeliveryRequestValidator; import at.gv.zustellung.app2mzs.xsd.ConfigType; import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType; import org.springframework.beans.factory.annotation.Autowired; diff --git a/src/main/java/at/gv/egiz/moazs/scheme/MzsDeliveryRequestValidator.java b/src/main/java/at/gv/egiz/moazs/preprocess/MzsDeliveryRequestValidator.java index 03f2664..8f9cd27 100644 --- a/src/main/java/at/gv/egiz/moazs/scheme/MzsDeliveryRequestValidator.java +++ b/src/main/java/at/gv/egiz/moazs/preprocess/MzsDeliveryRequestValidator.java @@ -1,4 +1,4 @@ -package at.gv.egiz.moazs.scheme; +package at.gv.egiz.moazs.preprocess; import at.gv.zustellung.app2mzs.xsd.ClientType; import at.gv.zustellung.app2mzs.xsd.ConfigType; diff --git a/src/main/java/at/gv/egiz/moazs/pipeline/DeliveryPipeline.java b/src/main/java/at/gv/egiz/moazs/process/DeliveryPipeline.java index f32dfe2..506dd1f 100644 --- a/src/main/java/at/gv/egiz/moazs/pipeline/DeliveryPipeline.java +++ b/src/main/java/at/gv/egiz/moazs/process/DeliveryPipeline.java @@ -1,4 +1,4 @@ -package at.gv.egiz.moazs.pipeline; +package at.gv.egiz.moazs.process; public interface DeliveryPipeline { diff --git a/src/main/java/at/gv/egiz/moazs/process/MsgResponseHandler.java b/src/main/java/at/gv/egiz/moazs/process/MsgResponseHandler.java new file mode 100644 index 0000000..5a7d39b --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/process/MsgResponseHandler.java @@ -0,0 +1,7 @@ +package at.gv.egiz.moazs.process; + +public interface MsgResponseHandler { + + void handle(String id); + +} diff --git a/src/main/java/at/gv/egiz/moazs/process/MsgResponseSink.java b/src/main/java/at/gv/egiz/moazs/process/MsgResponseSink.java new file mode 100644 index 0000000..67348fc --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/process/MsgResponseSink.java @@ -0,0 +1,11 @@ +package at.gv.egiz.moazs.process; + +import at.gv.egiz.moazs.scheme.MsgResponse; + +import java.util.concurrent.CompletableFuture; + +public interface MsgResponseSink { + + CompletableFuture<Void> handle(MsgResponse response); + +} diff --git a/src/main/java/at/gv/egiz/moazs/process/SafeResponseToFileSink.java b/src/main/java/at/gv/egiz/moazs/process/SafeResponseToFileSink.java new file mode 100644 index 0000000..ee32768 --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/process/SafeResponseToFileSink.java @@ -0,0 +1,84 @@ +package at.gv.egiz.moazs.process; + +import at.gv.egiz.moazs.repository.BinaryRepository; +import at.gv.egiz.moazs.scheme.Marshaller; +import at.gv.egiz.moazs.scheme.MsgResponse; +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.concurrent.CompletableFuture; + +import static java.lang.String.format; +import static java.util.concurrent.CompletableFuture.allOf; +import static java.util.concurrent.CompletableFuture.supplyAsync; + +@Component +public class SafeResponseToFileSink implements MsgResponseSink { + + private static final Logger log = LoggerFactory.getLogger(SafeResponseToFileSink.class); + private static final String SAFING_FAILED_MSG = "Could not save response with AppDeliveryId=%s."; + private static final SimpleDateFormat ISO_FORMATTER = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); + + private final Marshaller msgMarshaller; + private final BinaryRepository binaryRepository; + private final String root; + + + @Autowired + public SafeResponseToFileSink(Marshaller msgMarshaller, BinaryRepository binaryRepository, String root) { + this.msgMarshaller = msgMarshaller; + this.binaryRepository = binaryRepository; + this.root = root; + } + + @Override + public CompletableFuture<Void> handle(MsgResponse response) { + + var responseId = response.getResponseID(); + + var responsePath = generatePath(responseId, "xml"); + var storeResponseToFileSystemFuture = supplyAsync(() -> msgMarshaller.marshallXml(response.getResponse())) + .thenApply(responseString -> responseString.getBytes(StandardCharsets.UTF_8)) + .thenAccept(responseByteArray -> storeToFile(responsePath, responseByteArray)) + .exceptionally((ex) -> logException(ex, responseId)); + + var binaryResponsePath = generatePath(responseId, "binary.xml"); + var storeBinaryResponseToFileSystemFuture = supplyAsync(() -> binaryRepository.get(responseId).get()) + .thenAccept(binaryResponseByteArray -> storeToFile(binaryResponsePath, binaryResponseByteArray)) + .exceptionally((ex) -> logException(ex, responseId)); + + return allOf(storeResponseToFileSystemFuture, storeBinaryResponseToFileSystemFuture); + + } + + private String generatePath(String id, String suffix) { + var folder = sanitizeFileString(id); + var iso8601_now = ISO_FORMATTER.format(new Date()); + return format("%s/%s/%s.%s", root, folder, iso8601_now, suffix); + } + + private String sanitizeFileString(String fileString) { + return fileString.replaceAll("[^a-zA-Z0-9\\._\\-]", ""); + } + + private Void logException(Throwable ex, String appDeliveryID) { + log.error(format(SAFING_FAILED_MSG, appDeliveryID), ex); + return null; + } + + private void storeToFile(String path, byte[] content) { + try { + FileUtils.writeByteArrayToFile(new File(path), content); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/at/gv/egiz/moazs/process/SingleNodeResponseHandler.java b/src/main/java/at/gv/egiz/moazs/process/SingleNodeResponseHandler.java new file mode 100644 index 0000000..ec609cb --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/process/SingleNodeResponseHandler.java @@ -0,0 +1,26 @@ +package at.gv.egiz.moazs.process; + +import at.gv.egiz.moazs.verify.MsgResponseVerifier; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import static java.util.concurrent.CompletableFuture.supplyAsync; + +@Component +public class SingleNodeResponseHandler implements MsgResponseHandler { + + private final MsgResponseVerifier verifier; + private final MsgResponseSink sink; + + @Autowired + public SingleNodeResponseHandler(MsgResponseVerifier verifier, MsgResponseSink sink) { + this.verifier = verifier; + this.sink = sink; + } + + @Override + public void handle(String id) { + supplyAsync(() -> verifier.verify(id)) + .thenAcceptAsync((response) -> sink.handle(response)); + } +} diff --git a/src/main/java/at/gv/egiz/moazs/repository/DeliveryRepository.java b/src/main/java/at/gv/egiz/moazs/repository/DeliveryRepository.java index be61d1e..d0a8148 100644 --- a/src/main/java/at/gv/egiz/moazs/repository/DeliveryRepository.java +++ b/src/main/java/at/gv/egiz/moazs/repository/DeliveryRepository.java @@ -1,6 +1,8 @@ package at.gv.egiz.moazs.repository; +import at.gv.egiz.moazs.scheme.MsgResponse; import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType; +import at.gv.zustellung.msg.xsd.DeliveryNotificationType; import at.gv.zustellung.msg.xsd.DeliveryRequestStatusType; import org.springframework.stereotype.Repository; @@ -13,13 +15,9 @@ public interface DeliveryRepository { Optional<DeliveryRequestType> getDeliveryRequest(String appDeliveryID); - void add(DeliveryRequestStatusType status); + void add(MsgResponse response); - Optional<DeliveryRequestStatusType> getDeliveryRequestStatus(String appDeliveryID); - - void addSignedDeliveryRequestStatus(byte[] bytes, String appDeliveryId); - - Optional<byte[]> getSignedDeliveryRequestStatus(String appDeliveryID); + Optional<MsgResponse> getResponse(String id); } diff --git a/src/main/java/at/gv/egiz/moazs/repository/InMemoryDeliveryRepository.java b/src/main/java/at/gv/egiz/moazs/repository/InMemoryDeliveryRepository.java index 58ec92c..d9abb7b 100644 --- a/src/main/java/at/gv/egiz/moazs/repository/InMemoryDeliveryRepository.java +++ b/src/main/java/at/gv/egiz/moazs/repository/InMemoryDeliveryRepository.java @@ -1,36 +1,27 @@ package at.gv.egiz.moazs.repository; +import at.gv.egiz.moazs.scheme.MsgResponse; import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType; -import at.gv.zustellung.msg.xsd.DeliveryRequestStatusType; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Repository; import java.util.Optional; import java.util.concurrent.TimeUnit; -import static at.gv.egiz.moazs.util.NullCoalesce.coalesce; import static java.util.Optional.ofNullable; @Repository @Profile("!cluster") public class InMemoryDeliveryRepository implements DeliveryRepository { - private static final Logger logger = LoggerFactory.getLogger(InMemoryDeliveryRepository.class); - - private static final Cache<String, DeliveryRequestType> requestRepository = CacheBuilder.newBuilder() + private final Cache<String, DeliveryRequestType> requestRepository = CacheBuilder.newBuilder() .expireAfterWrite(30, TimeUnit.MINUTES) .build(); - private static final Cache<String, DeliveryRequestStatusType> statusRepository = CacheBuilder.newBuilder() - .expireAfterWrite(30, TimeUnit.MINUTES) - .build(); - - private static final Cache<String, byte[]> signedStatusRepository = CacheBuilder.newBuilder() + private final Cache<String, MsgResponse> responseRepository = CacheBuilder.newBuilder() .expireAfterWrite(30, TimeUnit.MINUTES) .build(); @@ -46,24 +37,14 @@ public class InMemoryDeliveryRepository implements DeliveryRepository { } @Override - public void add(DeliveryRequestStatusType status) { - var key = coalesce(status.getSuccess(), status.getPartialSuccess(), status.getError()) - .get().getAppDeliveryID(); - statusRepository.put(key, status); - } - - @Override - public Optional<DeliveryRequestStatusType> getDeliveryRequestStatus(String appDeliveryID) { - return ofNullable(statusRepository.getIfPresent(appDeliveryID)); - } - - @Override - public void addSignedDeliveryRequestStatus(byte[] bytes, String appDeliveryId) { - signedStatusRepository.put(appDeliveryId, bytes); + public void add(MsgResponse response) { + String key = response.getResponseID(); + System.out.println("storing with response id " + key); + responseRepository.put(key, response); } @Override - public Optional<byte[]> getSignedDeliveryRequestStatus(String appDeliveryID) { - return ofNullable(signedStatusRepository.getIfPresent(appDeliveryID)); + public Optional<MsgResponse> getResponse(String id) { + return ofNullable(responseRepository.getIfPresent(id)); } } diff --git a/src/main/java/at/gv/egiz/moazs/repository/RedisDeliveryRepository.java b/src/main/java/at/gv/egiz/moazs/repository/RedisDeliveryRepository.java index 9b7aefd..7ccd236 100644 --- a/src/main/java/at/gv/egiz/moazs/repository/RedisDeliveryRepository.java +++ b/src/main/java/at/gv/egiz/moazs/repository/RedisDeliveryRepository.java @@ -1,7 +1,9 @@ package at.gv.egiz.moazs.repository; import at.gv.egiz.moazs.scheme.Marshaller; +import at.gv.egiz.moazs.scheme.MsgResponse; import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType; +import at.gv.zustellung.msg.xsd.DeliveryNotificationType; import at.gv.zustellung.msg.xsd.DeliveryRequestStatusType; import at.gv.zustellung.app2mzs.xsd.ObjectFactory; import org.apache.tools.ant.filters.StringInputStream; @@ -50,7 +52,7 @@ public class RedisDeliveryRepository implements DeliveryRepository { @Override public Optional<DeliveryRequestType> getDeliveryRequest(String appDeliveryID) { - var serializedRequest = hashOperations.get(KEY, appDeliveryID); + String serializedRequest = hashOperations.get(KEY, appDeliveryID); if (serializedRequest == null) { return Optional.empty(); @@ -62,22 +64,14 @@ public class RedisDeliveryRepository implements DeliveryRepository { } @Override - public void add(DeliveryRequestStatusType status) { + public void add(MsgResponse notification) { throw new UnsupportedOperationException(NOT_IMPLEMENTED_MESSAGE); - } - @Override - public Optional<DeliveryRequestStatusType> getDeliveryRequestStatus(String appDeliveryID) { - throw new UnsupportedOperationException(NOT_IMPLEMENTED_MESSAGE); } @Override - public void addSignedDeliveryRequestStatus(byte[] bytes, String appDeliveryId) { + public Optional<MsgResponse> getResponse(String id) { throw new UnsupportedOperationException(NOT_IMPLEMENTED_MESSAGE); } - @Override - public Optional<byte[]> getSignedDeliveryRequestStatus(String appDeliveryID) { - return Optional.empty(); - } } diff --git a/src/main/java/at/gv/egiz/moazs/scheme/MsgResponse.java b/src/main/java/at/gv/egiz/moazs/scheme/MsgResponse.java new file mode 100644 index 0000000..fe46451 --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/scheme/MsgResponse.java @@ -0,0 +1,15 @@ +package at.gv.egiz.moazs.scheme; + +import at.gv.egiz.moazs.MoaZSException; +import at.gv.zustellung.msg.xsd.DeliveryAnswerType; + +public interface MsgResponse <T> { + + String getResponseID(); + T getResponse(); + String getAppDeliveryID(); + String getZSDeliveryID(); + DeliveryAnswerType getAnswer(); + MsgResponse<T> generateError(MoaZSException exception); + +} diff --git a/src/main/java/at/gv/egiz/moazs/scheme/NameSpace.java b/src/main/java/at/gv/egiz/moazs/scheme/NameSpace.java index 7c52af1..bb7f621 100644 --- a/src/main/java/at/gv/egiz/moazs/scheme/NameSpace.java +++ b/src/main/java/at/gv/egiz/moazs/scheme/NameSpace.java @@ -4,12 +4,17 @@ public class NameSpace { private NameSpace() {} - public static final String MSG = new at.gv.zustellung.msg.xsd.ObjectFactory().createDeliveryRequest(null).getName().getNamespaceURI(); + private static final at.gv.zustellung.msg.xsd.ObjectFactory MSG_FACTORY = new at.gv.zustellung.msg.xsd.ObjectFactory(); + public static final String MSG_VERSION = "2.2.0"; + public static final String MSG = MSG_FACTORY.createDeliveryRequest(null).getName().getNamespaceURI(); public static final String MSGP = new at.gv.zustellung.msg.xsd.persondata.ObjectFactory().createPerson(null).getName().getNamespaceURI(); - public static final String MZS = new at.gv.zustellung.app2mzs.xsd.ObjectFactory().createDeliveryRequest(null).getName().getNamespaceURI(); + public static final String MZS = new at.gv.zustellung.app2mzs.xsd.ObjectFactory().createDeliveryRequest(null).getName().getNamespaceURI(); public static final String TNVZ = new at.gv.zustellung.tnvz.xsd.ObjectFactory().createAddressabilityQuery(null).getName().getNamespaceURI(); public static final String MZSP = new at.gv.zustellung.app2mzs.xsd.persondata.ObjectFactory().createAbstractPersonData(null).getName().getNamespaceURI(); public static final String DSIG = new org.w3._2000._09.xmldsig_.ObjectFactory().createCanonicalizationMethod(null).getName().getNamespaceURI(); + public static final String MSG_DELIVERY_REQUEST_STATUS = MSG_FACTORY.createDeliveryRequestStatus(null).getName().getLocalPart(); + public static final String MSG_DELIVERY_NOTIFICATION = MSG_FACTORY.createDeliveryNotification(null).getName().getLocalPart(); + } diff --git a/src/main/java/at/gv/egiz/moazs/scheme/NotificationResponse.java b/src/main/java/at/gv/egiz/moazs/scheme/NotificationResponse.java new file mode 100644 index 0000000..f465a28 --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/scheme/NotificationResponse.java @@ -0,0 +1,67 @@ +package at.gv.egiz.moazs.scheme; + +import at.gv.egiz.moazs.MoaZSException; +import at.gv.zustellung.msg.xsd.DeliveryAnswerType; +import at.gv.zustellung.msg.xsd.DeliveryNotificationType; + +import static at.gv.zustellung.msg.xsd.DeliveryNotificationType.deliveryNotificationTypeBuilder; + +public class NotificationResponse implements MsgResponse<DeliveryNotificationType> { + + private final DeliveryNotificationType notification; + private final String id; + private static final String ID_SUFFIX = ".NO"; + + public NotificationResponse(DeliveryNotificationType notification) { + this.notification = notification; + this.id = getId(notification.getAppDeliveryID()); + } + + @Override + public String getResponseID() { + return this.id; + } + + public static String getId(String appDeliveryID) { + return appDeliveryID + ID_SUFFIX; + } + + @Override + public DeliveryNotificationType getResponse() { + return notification; + } + + @Override + public String getAppDeliveryID() { + return notification.getAppDeliveryID(); + } + + @Override + public String getZSDeliveryID() { + return notification.getZSDeliveryID(); + } + + @Override + public DeliveryAnswerType getAnswer() { + return notification; + } + + @Override + public MsgResponse<DeliveryNotificationType> generateError(MoaZSException exception) { + + //TODO: test this! + var notification = deliveryNotificationTypeBuilder() + .withAppDeliveryID(exception.getAppDeliveryID()) + .withDeliverySystem(exception.getDeliverySystem()) + .withGZ(exception.getGz()) + .withZSDeliveryID(exception.getZsDeliveryID()) + .build(); + + return new NotificationResponse(notification); + + } + + public static String getIdSuffix() { + return ID_SUFFIX; + } +} diff --git a/src/main/java/at/gv/egiz/moazs/scheme/RequestStatusResponse.java b/src/main/java/at/gv/egiz/moazs/scheme/RequestStatusResponse.java new file mode 100644 index 0000000..89c8be3 --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/scheme/RequestStatusResponse.java @@ -0,0 +1,87 @@ +package at.gv.egiz.moazs.scheme; + +import at.gv.egiz.moazs.MoaZSException; +import at.gv.zustellung.msg.xsd.DeliveryAnswerType; +import at.gv.zustellung.msg.xsd.DeliveryRequestStatusType; +import at.gv.zustellung.msg.xsd.ErrorInfoType; + +import static at.gv.egiz.moazs.util.NullCoalesce.coalesce; +import static at.gv.zustellung.msg.xsd.DeliveryRequestStatusType.Error.errorBuilder; +import static at.gv.zustellung.msg.xsd.DeliveryRequestStatusType.deliveryRequestStatusTypeBuilder; +import static at.gv.zustellung.msg.xsd.ErrorInfoType.errorInfoTypeBuilder; + +public class RequestStatusResponse implements MsgResponse<DeliveryRequestStatusType> { + + private final DeliveryRequestStatusType status; + private final DeliveryAnswerType answer; + private final String responseID; + private static final String ID_SUFFIX = ".RS"; + + public RequestStatusResponse(DeliveryRequestStatusType status) { + this.status = status; + this.answer = coalesce(status.getSuccess(), status.getPartialSuccess(), status.getError()).get(); + this.responseID = getResponseID(answer.getAppDeliveryID()); + } + + public static String getResponseID(String appDeliveryID) { + return appDeliveryID + ID_SUFFIX; + } + + @Override + public String getResponseID() { + return this.responseID; + } + + @Override + public DeliveryRequestStatusType getResponse() { + return status; + } + + @Override + public String getAppDeliveryID() { + return answer.getAppDeliveryID(); + } + + @Override + public String getZSDeliveryID() { + return answer.getZSDeliveryID(); + } + + @Override + public DeliveryAnswerType getAnswer() { + return this.answer; + } + + @Override + public MsgResponse<DeliveryRequestStatusType> generateError(MoaZSException exception) { + return generateErrorFromException(exception); + } + + public static MsgResponse<DeliveryRequestStatusType> generateErrorFromException(MoaZSException exception) { + ErrorInfoType info = errorInfoTypeBuilder() + .withText(exception.getMessage()) + .withCode(exception.getErrorCode()) + .build(); + + DeliveryRequestStatusType.Error error = errorBuilder() + .withErrorInfo(info) + .withAppDeliveryID(exception.getAppDeliveryID()) + .withDeliverySystem(exception.getDeliverySystem()) + .withGZ(exception.getGz()) + .withPreAdviceNoteSent(exception.getPreAdviceNoteSent()) + .withZSDeliveryID(exception.getZsDeliveryID()) + .build(); + + var status = deliveryRequestStatusTypeBuilder() + .withError(error) + .withVersion(NameSpace.MSG_VERSION) + .build(); + + return new RequestStatusResponse(status); + + } + + public static String getIdSuffix() { + return ID_SUFFIX; + } +} diff --git a/src/main/java/at/gv/egiz/moazs/service/MsgService.java b/src/main/java/at/gv/egiz/moazs/service/MsgService.java new file mode 100644 index 0000000..93f1ed5 --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/service/MsgService.java @@ -0,0 +1,74 @@ +package at.gv.egiz.moazs.service; +import at.gv.egiz.moazs.process.MsgResponseHandler; +import at.gv.egiz.moazs.repository.DeliveryRepository; +import at.gv.egiz.moazs.scheme.MsgResponse; +import at.gv.egiz.moazs.scheme.NameSpace; +import at.gv.egiz.moazs.scheme.NotificationResponse; +import at.gv.egiz.moazs.scheme.RequestStatusResponse; +import at.gv.zustellung.msg.xsd.*; +import org.apache.cxf.annotations.SchemaValidation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import static at.gv.zustellung.msg.xsd.DeliveryNotificationACKType.deliveryNotificationACKTypeBuilder; +import static at.gv.zustellung.msg.xsd.DeliveryRequestStatusACKType.deliveryRequestStatusACKTypeBuilder; +import static at.gv.zustellung.msg.xsd.GetVersionResponse.getVersionResponseBuilder; +import static java.util.concurrent.CompletableFuture.runAsync; + +@Service +@SchemaValidation(type = SchemaValidation.SchemaValidationType.BOTH) +public class MsgService implements Zuse2AppPort { + + private final DeliveryRepository repository; + private final MsgResponseHandler handler; + + @Autowired + public MsgService(DeliveryRepository repository, MsgResponseHandler handler) { + this.repository = repository; + this.handler = handler; + } + + @Override + public GetVersionResponse getVersion(SimpleRequestType getVersionRequest) { + return getVersionResponseBuilder() + .withVersion(NameSpace.MSG_VERSION) + .build(); + } + + @Override + public DeliveryRequestStatusACKType status(DeliveryRequestStatusType status) { + var response = new RequestStatusResponse(status); + sendToWork(response); + return statusAck(response.getAppDeliveryID(), response.getZSDeliveryID()); + } + + private DeliveryRequestStatusACKType statusAck(String appDeliveryID, String zsDeliveryID) { + return deliveryRequestStatusACKTypeBuilder() + .withAppDeliveryID(appDeliveryID) + .withZSDeliveryID(zsDeliveryID) + .withVersion(NameSpace.MSG_VERSION) + .build(); + } + + @Override + public DeliveryNotificationACKType notification(DeliveryNotificationType notification) { + var response = new NotificationResponse(notification); + sendToWork(response); + return notificationAck(response.getAppDeliveryID(), response.getZSDeliveryID()); + } + + private void sendToWork(MsgResponse response) { + runAsync(() -> repository.add(response)) + .thenRunAsync(() -> handler.handle(response.getResponseID())); + } + + private DeliveryNotificationACKType notificationAck(String appDeliveryID, String zsDeliveryID) { + return deliveryNotificationACKTypeBuilder() + .withAppDeliveryID(appDeliveryID) + .withZSDeliveryID(zsDeliveryID) + .withVersion(NameSpace.MSG_VERSION) + .build(); + } + + +} diff --git a/src/main/java/at/gv/egiz/moazs/scheme/MzsService.java b/src/main/java/at/gv/egiz/moazs/service/MzsService.java index f245b93..c41740f 100644 --- a/src/main/java/at/gv/egiz/moazs/scheme/MzsService.java +++ b/src/main/java/at/gv/egiz/moazs/service/MzsService.java @@ -1,8 +1,12 @@ -package at.gv.egiz.moazs.scheme; +package at.gv.egiz.moazs.service; -import at.gv.egiz.moazs.pipeline.DeliveryPipeline; import at.gv.egiz.moazs.preprocess.DeliveryRequestAugmenter; +import at.gv.egiz.moazs.process.DeliveryPipeline; +import at.gv.egiz.moazs.repository.BinaryRepository; 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; import at.gv.zustellung.app2mzs.xsd.DeliveryResponseType; @@ -37,15 +41,17 @@ public class MzsService implements App2MzsPortType { private final MzsClient appClient; private final DeliveryRequestAugmenter augmenter; private final Msg2MzsConverter converter; + private final BinaryRepository binaryStatusRepository; @Autowired public MzsService(DeliveryRepository repository, DeliveryPipeline pipeline, MzsClient appClient, - DeliveryRequestAugmenter augmenter, Msg2MzsConverter converter) { + DeliveryRequestAugmenter augmenter, Msg2MzsConverter converter, BinaryRepository binaryStatusRepository) { this.repository = repository; this.pipeline = pipeline; this.appClient = appClient; this.augmenter = augmenter; this.converter = converter; + this.binaryStatusRepository = binaryStatusRepository; } @Override @@ -55,10 +61,11 @@ public class MzsService implements App2MzsPortType { DeliveryRequestType deliveryRequest) { var appDeliveryID = deliveryRequest.getMetaData().getAppDeliveryID(); + var responseID = RequestStatusResponse.getResponseID(appDeliveryID); var future = supplyAsync(() -> augmenter.augment(deliveryRequest)) .thenApply(this::process) - .thenApply(status -> converter.convert(status, repository.getSignedDeliveryRequestStatus(appDeliveryID))); + .thenApply(status -> converter.convert(status, binaryStatusRepository.get(responseID))); try { return future.get(TIMEOUT_FOR_ANWSER, TimeUnit.SECONDS); @@ -85,9 +92,10 @@ public class MzsService implements App2MzsPortType { repository.add(deliveryRequest); pipeline.processRequest(appDeliveryID); - return repository.getDeliveryRequestStatus(appDeliveryID) + var statusId = RequestStatusResponse.getResponseID(appDeliveryID); + var response = repository.getResponse(statusId) .orElseThrow(() -> moaZSException("Could not get a response for AppDeliveryID=%s.", appDeliveryID)); - + return (DeliveryRequestStatusType) response.getResponse(); } private DeliveryResponseType generatePartialSuccessResponse(String appDeliveryId) { diff --git a/src/main/java/at/gv/egiz/moazs/util/ClientFactory.java b/src/main/java/at/gv/egiz/moazs/util/ClientFactory.java index e7761fe..d0a445b 100644 --- a/src/main/java/at/gv/egiz/moazs/util/ClientFactory.java +++ b/src/main/java/at/gv/egiz/moazs/util/ClientFactory.java @@ -1,5 +1,7 @@ -package at.gv.egiz.moazs.util; +package at.gv.egiz.moazs.client; +import at.gv.egiz.moazs.util.FileUtils; +import at.gv.egiz.moazs.util.StoreSOAPBodyBinaryInRepositoryInterceptor; import at.gv.zustellung.app2mzs.xsd.ClientType; import at.gv.zustellung.app2mzs.xsd.KeyStoreType; import at.gv.zustellung.app2mzs.xsd.SSLType; diff --git a/src/main/java/at/gv/egiz/moazs/util/EndpointFactory.java b/src/main/java/at/gv/egiz/moazs/util/EndpointFactory.java new file mode 100644 index 0000000..24321e1 --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/util/EndpointFactory.java @@ -0,0 +1,41 @@ +package at.gv.egiz.moazs.util; + +import org.apache.cxf.Bus; +import org.apache.cxf.interceptor.Interceptor; +import org.apache.cxf.jaxws.EndpointImpl; +import org.apache.cxf.message.Message; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import javax.xml.ws.Endpoint; + +import javax.xml.ws.Service; + +@Component +public class EndpointFactory { + + private final Bus bus; + + @Autowired + public EndpointFactory(Bus bus) { + this.bus = bus; + } + + public Endpoint create(Object implementor, Service service) { + return create(implementor, service, null); + } + + public Endpoint create(Object implementor, Service service, Interceptor<Message> interceptor) { + EndpointImpl endpoint = new EndpointImpl(bus, implementor); + endpoint.setAddress("/"); + endpoint.setServiceName(service.getServiceName()); + endpoint.setWsdlLocation(service.getWSDLDocumentLocation().toString()); + endpoint.publish(); + + if (interceptor != null) { + endpoint.getInInterceptors().add(interceptor); + } + + return endpoint; + } + +} diff --git a/src/main/java/at/gv/egiz/moazs/util/SSLContextCreator.java b/src/main/java/at/gv/egiz/moazs/util/SSLContextCreator.java index 302bbf0..8fb5d80 100644 --- a/src/main/java/at/gv/egiz/moazs/util/SSLContextCreator.java +++ b/src/main/java/at/gv/egiz/moazs/util/SSLContextCreator.java @@ -1,4 +1,4 @@ -package at.gv.egiz.moazs.util; +package at.gv.egiz.moazs.client; import at.gv.egiz.eaaf.core.impl.utils.KeyStoreUtils; import at.gv.zustellung.app2mzs.xsd.KeyStoreType; diff --git a/src/main/java/at/gv/egiz/moazs/util/StoreSOAPBodyBinaryInRepositoryInterceptor.java b/src/main/java/at/gv/egiz/moazs/util/StoreSOAPBodyBinaryInRepositoryInterceptor.java index 2db81ab..d70c8bd 100644 --- a/src/main/java/at/gv/egiz/moazs/util/StoreSOAPBodyBinaryInRepositoryInterceptor.java +++ b/src/main/java/at/gv/egiz/moazs/util/StoreSOAPBodyBinaryInRepositoryInterceptor.java @@ -1,6 +1,6 @@ package at.gv.egiz.moazs.util; -import at.gv.egiz.moazs.repository.DeliveryRepository; +import at.gv.egiz.moazs.repository.BinaryRepository; import at.gv.egiz.moazs.scheme.SOAPUtils; import org.apache.cxf.message.Message; import org.apache.cxf.phase.AbstractPhaseInterceptor; @@ -15,6 +15,7 @@ import org.xml.sax.SAXException; import javax.xml.parsers.ParserConfigurationException; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.Map; import static at.gv.egiz.moazs.MoaZSException.moaZSException; @@ -25,14 +26,16 @@ public class StoreSOAPBodyBinaryInRepositoryInterceptor extends AbstractPhaseInt private final CXFMessageUtils messageUtils; private final SOAPUtils soapUtils; - private final DeliveryRepository repository; + private final Map<String, String> idSuffixes; + private final BinaryRepository repository; @Autowired public StoreSOAPBodyBinaryInRepositoryInterceptor(CXFMessageUtils extractor, SOAPUtils soapUtils, - DeliveryRepository repository) { + Map<String, String> idSuffixes, BinaryRepository repository) { super(Phase.RECEIVE); this.messageUtils = extractor; this.soapUtils = soapUtils; + this.idSuffixes = idSuffixes; this.repository = repository; } @@ -45,17 +48,28 @@ public class StoreSOAPBodyBinaryInRepositoryInterceptor extends AbstractPhaseInt log.trace("Interceptor received this SOAP message: {}. ", new String(content, StandardCharsets.UTF_8)); } - if(content.length > 0) { - Element document = soapUtils.toDOM(content); - byte[] status = soapUtils.unwrapSoapEnvelope(document); - String appDeliveryID = soapUtils.getAppDeliveryIDFrom(document); - repository.addSignedDeliveryRequestStatus(status, appDeliveryID); + if (content.length <= 0) { + return; + } + + Element document = soapUtils.toDOM(content); + byte[] response = soapUtils.unwrapSoapEnvelope(document); + String appDeliveryID = soapUtils.getAppDeliveryIDFrom(document); + String rootTag = document.getTagName(); - if(log.isTraceEnabled()) { - log.trace("DeliveryRequestStatus with AppDeliveryID={} unwrapped and stored: {}. ", - appDeliveryID, new String(status, StandardCharsets.UTF_8)); - } + if (!idSuffixes.containsKey(rootTag)) { + log.trace("Will not add message of type {}. ", rootTag); + return; } + + var id = appDeliveryID + idSuffixes.get(rootTag); + repository.add(id, response); + + if(log.isTraceEnabled()) { + log.trace("Msg Response with AppDeliveryID={} unwrapped and stored: {}. ", + appDeliveryID, new String(response, StandardCharsets.UTF_8)); + } + } catch (ParserConfigurationException | SAXException | IOException | NullPointerException e) { throw moaZSException("Could not extract signed data from message.", e); } diff --git a/src/main/java/at/gv/egiz/moazs/verify/MsgResponseVerifier.java b/src/main/java/at/gv/egiz/moazs/verify/MsgResponseVerifier.java new file mode 100644 index 0000000..c5e04d9 --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/verify/MsgResponseVerifier.java @@ -0,0 +1,59 @@ +package at.gv.egiz.moazs.verify; + +import at.gv.egiz.moazs.MoaZSException; +import at.gv.egiz.moazs.repository.BinaryRepository; +import at.gv.egiz.moazs.repository.DeliveryRepository; +import at.gv.egiz.moazs.scheme.MsgResponse; +import at.gv.egiz.moazs.service.MsgService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import static at.gv.egiz.moazs.MoaZSException.moaZSExceptionBuilder; +import static java.lang.String.format; + +@Component +public class MsgResponseVerifier { + + private static final Logger log = LoggerFactory.getLogger(MsgService.class); + public static final String MOASP_SIGNATURE_INVALID_ERROR_MSG = "Signature of Msg Response " + + "with AppDeliveryID=%s is not valid."; + + private final DeliveryRepository repo; + private final BinaryRepository binaryRepo; + private final SignatureVerifier verifier; + + @Autowired + public MsgResponseVerifier(DeliveryRepository repo, + BinaryRepository binaryStatusRepository, + SignatureVerifier verifier) { + this.repo = repo; + this.binaryRepo = binaryStatusRepository; + this.verifier = verifier; + } + + public MsgResponse verify(String id) { + + var response = repo.getResponse(id).get(); + var builder = moaZSExceptionBuilder().withAllParametersInAnswer(response.getAnswer()); + + var binaryResponse = binaryRepo.get(id).get(); + + try { + verifier.verify(binaryResponse); + return response; + } catch (MoaZSException ex) { + log.error(ex.getMessage(), ex); + var wrappingEx = builder + .withMessage(format(MOASP_SIGNATURE_INVALID_ERROR_MSG, response.getAppDeliveryID())) + .withErrorCode(MoaZSException.ERROR_MOASP_SIGNATURE_INVALID) + .withCause(ex) + .build(); + + return response.generateError(wrappingEx); + } + + } + +} diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 1903067..ca8221c 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -72,3 +72,7 @@ moa.spss: # - relative path (otherwise, relative to application's class path) configuration: moa-spss/MOASPSSConfiguration.xml default-trustprofile: test-trustprofile + +repository: + # duration in minutes before repository records are evicted. + expiresAfterWrite: 30
\ No newline at end of file diff --git a/src/main/resources/zusemsg/zuse2app_p2.wsdl b/src/main/resources/zusemsg/zuse2app_p2.wsdl new file mode 100644 index 0000000..d50c3cc --- /dev/null +++ b/src/main/resources/zusemsg/zuse2app_p2.wsdl @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:msg="http://reference.e-government.gv.at/namespace/zustellung/msg/phase2/20181206#" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:service="http://reference.e-government.gv.at/namespace/zustellung/app2zuse/phase2/20181206#" targetNamespace="http://reference.e-government.gv.at/namespace/zustellung/app2zuse/phase2/20181206#"> + <wsdl:types> + <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" elementFormDefault="qualified" attributeFormDefault="unqualified" vc:minVersion="1.1" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"> + <xs:import namespace="http://reference.e-government.gv.at/namespace/zustellung/msg/phase2/20181206#" schemaLocation="zuse_p2.xsd"/> + </xs:schema> + </wsdl:types> + <wsdl:message name="DeliveryNotification"> + <wsdl:part name="DeliveryNotification" element="msg:DeliveryNotification"> + </wsdl:part> + </wsdl:message> + <wsdl:message name="DeliveryNotificationACK"> + <wsdl:part name="DeliveryNotificationACK" element="msg:DeliveryNotificationACK"> + </wsdl:part> + </wsdl:message> + <wsdl:message name="DeliveryRequestStatus"> + <wsdl:part name="DeliveryRequestStatus" element="msg:DeliveryRequestStatus"> + </wsdl:part> + </wsdl:message> + <wsdl:message name="DeliveryRequestStatusACK"> + <wsdl:part name="DeliveryRequestStatusACK" element="msg:DeliveryRequestStatusACK"> + </wsdl:part> + </wsdl:message> + <wsdl:message name="GetVersionRequest"> + <wsdl:part name="GetVersionRequest" element="msg:GetVersionRequest"> + </wsdl:part> + </wsdl:message> + <wsdl:message name="GetVersionResponse"> + <wsdl:part name="GetVersionResponse" element="msg:GetVersionResponse"> + </wsdl:part> + </wsdl:message> + <wsdl:portType name="Zuse2AppPort"> + <wsdl:operation name="Notification"> + <wsdl:input name="DeliveryNotification" message="service:DeliveryNotification"/> + <wsdl:output name="DeliveryNotificationACK" message="service:DeliveryNotificationACK"/> + </wsdl:operation> + <wsdl:operation name="Status"> + <wsdl:input name="DeliveryRequestStatus" message="service:DeliveryRequestStatus"/> + <wsdl:output name="DeliveryRequestStatusACK" message="service:DeliveryRequestStatusACK"/> + </wsdl:operation> + <wsdl:operation name="GetVersion"> + <wsdl:input name="GetVersionRequest" message="service:GetVersionRequest"/> + <wsdl:output name="GetVersionResponse" message="service:GetVersionResponse"/> + </wsdl:operation> + </wsdl:portType> + <wsdl:binding name="Zuse2AppPortSoap12" type="service:Zuse2AppPort"> + <soap12:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> + <wsdl:operation name="Notification"> + <soap12:operation soapAction="Notification" soapActionRequired="false"/> + <wsdl:input name="DeliveryNotification"> + <soap12:body use="literal"/> + </wsdl:input> + <wsdl:output name="DeliveryNotificationACK"> + <soap12:body use="literal"/> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="Status"> + <soap12:operation soapAction="Status" soapActionRequired="false"/> + <wsdl:input name="DeliveryRequestStatus"> + <soap12:body use="literal"/> + </wsdl:input> + <wsdl:output name="DeliveryRequestStatusACK"> + <soap12:body use="literal"/> + </wsdl:output> + </wsdl:operation> + <wsdl:operation name="GetVersion"> + <soap12:operation soapAction="GetVersion" soapActionRequired="false"/> + <wsdl:input name="GetVersionRequest"> + <soap12:body use="literal"/> + </wsdl:input> + <wsdl:output name="GetVersionResponse"> + <soap12:body use="literal"/> + </wsdl:output> + </wsdl:operation> + </wsdl:binding> + <wsdl:service name="Zuse2AppPortService"> + <wsdl:port name="Zuse2AppPortSoap12" binding="service:Zuse2AppPortSoap12"> + <soap12:address location="/zuse"/> + </wsdl:port> + </wsdl:service> +</wsdl:definitions> |