From 030488bb7ff9572f35032d80d4101c06cfc98bf5 Mon Sep 17 00:00:00 2001 From: Christof Rabensteiner Date: Tue, 2 Jul 2019 14:19:41 +0200 Subject: Implement And Integrate tnvz:QueryPersonRequest. - Merge TnvzClient and TnvzResultVerifier to TnvzHelper; TnvzHelper now builds the QueryPersonRequest, sends it to the tnvz port and evaluates the result. - Publish some interfaces in Mzs2MsgConverter because they are needed by TnvzHelper. - Generalize MsgClientFactory to ClientFactory such that it can be used to generate arbitrary SOAP clients (e.g. also for tnvz!). Schema Changes to accomodate Tnvz's QueryPersonRequest: - Add optional tnvz:AustrianAddressesOnly and optional TnvzMetaData to mzs:mzs:DeliveryRequest. Removed Unit Tests: - Remove subset of SameThreadDeliveryPipeline testcases (mimetype related) because its logic moved to TnvzHelper. --- src/main/java/at/gv/egiz/moazs/MoaZSException.java | 10 + .../java/at/gv/egiz/moazs/msg/ClientFactory.java | 107 ++++++++++ .../at/gv/egiz/moazs/msg/MsgClientFactory.java | 108 ---------- .../moazs/pipeline/SameThreadDeliveryPipeline.java | 61 +++--- .../moazs/preprocess/DeliveryRequestAugmenter.java | 1 + .../at/gv/egiz/moazs/scheme/MoaZSPrefixMapper.java | 2 + .../at/gv/egiz/moazs/scheme/Mzs2MsgConverter.java | 12 +- .../java/at/gv/egiz/moazs/scheme/NameSpace.java | 5 +- .../java/at/gv/egiz/moazs/tnvz/TnvzClient.java | 19 -- .../java/at/gv/egiz/moazs/tnvz/TnvzHelper.java | 231 +++++++++++++++++++++ .../at/gv/egiz/moazs/tnvz/TnvzResultVerifier.java | 63 ------ 11 files changed, 386 insertions(+), 233 deletions(-) create mode 100644 src/main/java/at/gv/egiz/moazs/msg/ClientFactory.java delete mode 100644 src/main/java/at/gv/egiz/moazs/msg/MsgClientFactory.java delete mode 100644 src/main/java/at/gv/egiz/moazs/tnvz/TnvzClient.java create mode 100644 src/main/java/at/gv/egiz/moazs/tnvz/TnvzHelper.java delete mode 100644 src/main/java/at/gv/egiz/moazs/tnvz/TnvzResultVerifier.java (limited to 'src/main/java') diff --git a/src/main/java/at/gv/egiz/moazs/MoaZSException.java b/src/main/java/at/gv/egiz/moazs/MoaZSException.java index 847d9c1..322f06b 100644 --- a/src/main/java/at/gv/egiz/moazs/MoaZSException.java +++ b/src/main/java/at/gv/egiz/moazs/MoaZSException.java @@ -8,6 +8,7 @@ import org.springframework.lang.Nullable; public class MoaZSException extends RuntimeException { public static final String ERROR_MZS_MIMETYPE_MISSMATCH = "8001"; + public static final String ERROR_MZS_NO_TNVZ_PERSON_QUERY_RESULTS = "8002"; public static final String ERROR_MOASP_SIGNATURE_INVALID = "7001"; @Nullable @@ -52,6 +53,10 @@ public class MoaZSException extends RuntimeException { return new Builder().withMessage(message); } + public static Builder moaZSExceptionBuilder() { + return new Builder(); + } + @Nullable public String getErrorCode() { return errorCode; @@ -95,6 +100,11 @@ public class MoaZSException extends RuntimeException { return this; } + public Builder withMessage(String formatString, Object... objects ) { + this.message = String.format(formatString, objects); + return this; + } + public Builder withCause(Throwable cause) { this.cause = cause; return this; diff --git a/src/main/java/at/gv/egiz/moazs/msg/ClientFactory.java b/src/main/java/at/gv/egiz/moazs/msg/ClientFactory.java new file mode 100644 index 0000000..6729015 --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/msg/ClientFactory.java @@ -0,0 +1,107 @@ +package at.gv.egiz.moazs.msg; + +import at.gv.egiz.moazs.util.FileUtils; +import at.gv.egiz.moazs.util.SSLContextCreator; +import at.gv.zustellung.app2mzs.xsd.ClientType; +import at.gv.zustellung.app2mzs.xsd.KeyStoreType; +import at.gv.zustellung.app2mzs.xsd.SSLType; +import org.apache.cxf.configuration.jsse.TLSClientParameters; +import org.apache.cxf.endpoint.Client; +import org.apache.cxf.frontend.ClientProxy; +import org.apache.cxf.jaxws.JaxWsClientFactoryBean; +import org.apache.cxf.jaxws.JaxWsProxyFactoryBean; +import org.apache.cxf.transport.http.HTTPConduit; +import org.apache.cxf.transports.http.configuration.HTTPClientPolicy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.annotation.Nullable; +import javax.net.ssl.SSLContext; + +import static at.gv.zustellung.app2mzs.xsd.KeyStoreType.keyStoreTypeBuilder; + +@Component +public class ClientFactory { + + private static final Logger log = LoggerFactory.getLogger(ClientFactory.class); + + private final StoreSOAPBodyBinaryInRepositoryInterceptor storeResponseInterceptor; + private final SSLContextCreator sslContextCreator; + private final FileUtils fileUtils; + + @Autowired + public ClientFactory(StoreSOAPBodyBinaryInRepositoryInterceptor storeResponseInterceptor, + SSLContextCreator creator, + FileUtils fileUtils) { + this.storeResponseInterceptor = storeResponseInterceptor; + this.sslContextCreator = creator; + this.fileUtils = fileUtils; + } + + /** + * Creates a client that communicates with a soap service. + * + * @param params for the client, such as service url and ssl parameters. + * @return the client + */ + public T create(ClientType params, Class clazz) { + + var factory = new JaxWsClientFactoryBean(); + factory.setServiceClass(clazz); + factory.setAddress(params.getURL()); + factory.getInInterceptors().add(storeResponseInterceptor); + + var proxy = new JaxWsProxyFactoryBean(factory).create(); + Client client = ClientProxy.getClient(proxy); + HTTPConduit http = (HTTPConduit) client.getConduit(); + + var httpClientPolicy = new HTTPClientPolicy(); + httpClientPolicy.setConnectionTimeout(params.getConnectionTimeout().longValueExact()); + httpClientPolicy.setReceiveTimeout(params.getReceiveTimeout().longValueExact()); + http.setClient(httpClientPolicy); + + if (params.getURL().startsWith("https")) { + TLSClientParameters tlsParams = setupTLSParams(params.getSSL()); + http.setTlsClientParameters(tlsParams); + log.info("SSLContext initialized. "); + } + + return ((T)proxy); + } + + private TLSClientParameters setupTLSParams(SSLType ssl) { + + var tlsParams = new TLSClientParameters(); + var keystore = resolveKeyStorePath(ssl.getKeyStore()); + + SSLContext sslContext; + if (ssl.isTrustAll()) { + sslContext = sslContextCreator.createUnsafeSSLContext(keystore); + } else { + var truststore = resolveKeyStorePath(ssl.getTrustStore()); + sslContext = sslContextCreator.createSSLContext(keystore, truststore); + } + tlsParams.setSSLSocketFactory(sslContext.getSocketFactory()); + + if (ssl.isLaxHostNameVerification()) { + tlsParams.setDisableCNCheck(true); + } + + return tlsParams; + } + + private KeyStoreType resolveKeyStorePath(@Nullable KeyStoreType store) { + + if (store == null) return null; + + var resolvedURI = "file:" + fileUtils.determinePath(store.getFileName()); + log.trace("Resolved key store path from {} to {}.", store.getFileName(), resolvedURI); + + return keyStoreTypeBuilder(store) + .withFileName(resolvedURI) + .build(); + } + +} diff --git a/src/main/java/at/gv/egiz/moazs/msg/MsgClientFactory.java b/src/main/java/at/gv/egiz/moazs/msg/MsgClientFactory.java deleted file mode 100644 index e55debc..0000000 --- a/src/main/java/at/gv/egiz/moazs/msg/MsgClientFactory.java +++ /dev/null @@ -1,108 +0,0 @@ -package at.gv.egiz.moazs.msg; - -import at.gv.egiz.moazs.util.FileUtils; -import at.gv.egiz.moazs.util.SSLContextCreator; -import at.gv.zustellung.app2mzs.xsd.ClientType; -import at.gv.zustellung.app2mzs.xsd.KeyStoreType; -import at.gv.zustellung.app2mzs.xsd.SSLType; -import at.gv.zustellung.msg.xsd.App2ZusePort; -import org.apache.cxf.configuration.jsse.TLSClientParameters; -import org.apache.cxf.endpoint.Client; -import org.apache.cxf.frontend.ClientProxy; -import org.apache.cxf.jaxws.JaxWsClientFactoryBean; -import org.apache.cxf.jaxws.JaxWsProxyFactoryBean; -import org.apache.cxf.transport.http.HTTPConduit; -import org.apache.cxf.transports.http.configuration.HTTPClientPolicy; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import javax.annotation.Nullable; -import javax.net.ssl.SSLContext; - -import static at.gv.zustellung.app2mzs.xsd.KeyStoreType.keyStoreTypeBuilder; - -@Component -public class MsgClientFactory { - - private static final Logger log = LoggerFactory.getLogger(MsgClientFactory.class); - - private final StoreSOAPBodyBinaryInRepositoryInterceptor storeResponseInterceptor; - private final SSLContextCreator sslContextCreator; - private final FileUtils fileUtils; - - @Autowired - public MsgClientFactory(StoreSOAPBodyBinaryInRepositoryInterceptor storeResponseInterceptor, - SSLContextCreator creator, - FileUtils fileUtils) { - this.storeResponseInterceptor = storeResponseInterceptor; - this.sslContextCreator = creator; - this.fileUtils = fileUtils; - } - - /** - * Creates a client that communicates with a msg service. - * - * @param params for the client, such as service url and ssl parameters. - * @return the msg client - */ - public App2ZusePort create(ClientType params) { - - var factory = new JaxWsClientFactoryBean(); - factory.setServiceClass(App2ZusePort.class); - factory.setAddress(params.getURL()); - factory.getInInterceptors().add(storeResponseInterceptor); - - var proxy = new JaxWsProxyFactoryBean(factory).create(); - Client client = ClientProxy.getClient(proxy); - HTTPConduit http = (HTTPConduit) client.getConduit(); - - var httpClientPolicy = new HTTPClientPolicy(); - httpClientPolicy.setConnectionTimeout(params.getConnectionTimeout().longValueExact()); - httpClientPolicy.setReceiveTimeout(params.getReceiveTimeout().longValueExact()); - http.setClient(httpClientPolicy); - - if (params.getURL().startsWith("https")) { - TLSClientParameters tlsParams = setupTLSParams(params.getSSL()); - http.setTlsClientParameters(tlsParams); - log.info("SSLContext initialized. "); - } - - return ((App2ZusePort)proxy); - } - - private TLSClientParameters setupTLSParams(SSLType ssl) { - - var tlsParams = new TLSClientParameters(); - var keystore = resolveKeyStorePath(ssl.getKeyStore()); - - SSLContext sslContext; - if (ssl.isTrustAll()) { - sslContext = sslContextCreator.createUnsafeSSLContext(keystore); - } else { - var truststore = resolveKeyStorePath(ssl.getTrustStore()); - sslContext = sslContextCreator.createSSLContext(keystore, truststore); - } - tlsParams.setSSLSocketFactory(sslContext.getSocketFactory()); - - if (ssl.isLaxHostNameVerification()) { - tlsParams.setDisableCNCheck(true); - } - - return tlsParams; - } - - private KeyStoreType resolveKeyStorePath(@Nullable KeyStoreType store) { - - if (store == null) return null; - - var resolvedURI = "file:" + fileUtils.determinePath(store.getFileName()); - log.trace("Resolved key store path from {} to {}.", store.getFileName(), resolvedURI); - - return keyStoreTypeBuilder(store) - .withFileName(resolvedURI) - .build(); - } - -} diff --git a/src/main/java/at/gv/egiz/moazs/pipeline/SameThreadDeliveryPipeline.java b/src/main/java/at/gv/egiz/moazs/pipeline/SameThreadDeliveryPipeline.java index 2e0433f..ecf580d 100644 --- a/src/main/java/at/gv/egiz/moazs/pipeline/SameThreadDeliveryPipeline.java +++ b/src/main/java/at/gv/egiz/moazs/pipeline/SameThreadDeliveryPipeline.java @@ -2,17 +2,17 @@ package at.gv.egiz.moazs.pipeline; import at.gv.egiz.moazs.MoaZSException; -import at.gv.egiz.moazs.msg.MsgClientFactory; -import at.gv.egiz.moazs.verify.SignatureVerifier; +import at.gv.egiz.moazs.msg.ClientFactory; 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.tnvz.TnvzClient; -import at.gv.egiz.moazs.tnvz.TnvzResultVerifier; +import at.gv.egiz.moazs.tnvz.TnvzHelper; +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.PersonResultType; +import at.gv.zustellung.tnvz.xsd.TNVZServicePort; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; @@ -32,54 +32,43 @@ public class SameThreadDeliveryPipeline implements DeliveryPipeline { private static final Logger log = Logger.getLogger(SameThreadDeliveryPipeline.class); private final DeliveryRepository repository; - private final TnvzClient tnvzClient; - private final TnvzResultVerifier tnvzVerifier; + private final TnvzHelper tnvzHelper; private final Mzs2MsgConverter converter; - private final MsgClientFactory msgClientFactory; + private final ClientFactory clientFactory; private final SignatureVerifier verifier; @Autowired public SameThreadDeliveryPipeline(DeliveryRepository repository, - TnvzClient tnvzClient, - TnvzResultVerifier tnvzVerifier, + TnvzHelper tnvzHelper, Mzs2MsgConverter converter, - MsgClientFactory msgClientFactory, + ClientFactory clientFactory, SignatureVerifier verifier ) { this.repository = repository; - this.tnvzClient = tnvzClient; - this.tnvzVerifier = tnvzVerifier; + this.tnvzHelper = tnvzHelper; this.converter = converter; - this.msgClientFactory = msgClientFactory; + this.clientFactory = clientFactory; this.verifier = verifier; } @Override public void processRequest(String appDeliveryId) { - var exceptionBuilder = moaZSExceptionBuilder(""); + var exceptionBuilder = moaZSExceptionBuilder(); try { var mzsRequest = repository.getDeliveryRequest(appDeliveryId).orElseThrow(); exceptionBuilder.withMzsRequest(mzsRequest); - at.gv.zustellung.msg.xsd.DeliveryRequestType msgRequest; - - if (mzsRequest.getConfig().isPerformQueryPersonRequest()) { - var tnvzResult = performTnvzQuery(mzsRequest); - exceptionBuilder.withTnvzResult(tnvzResult); - - msgRequest = converter.convert(mzsRequest, tnvzResult.getSuccess().getIdentification()); - } else { - msgRequest = converter.convert(mzsRequest); - } + at.gv.zustellung.msg.xsd.DeliveryRequestType msgRequest = buildMsgRequest(mzsRequest, exceptionBuilder); exceptionBuilder.withMsgRequest(msgRequest); - var status = msgClientFactory.create(mzsRequest.getConfig().getMSGClient()).delivery(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); } catch (MoaZSException exception) { @@ -92,6 +81,18 @@ public class SameThreadDeliveryPipeline implements DeliveryPipeline { } } + 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); + } + } + private void verifySignedStatus(String appDeliveryId, MoaZSException.Builder exceptionBuilder) throws MoaZSException { try { @@ -106,12 +107,6 @@ public class SameThreadDeliveryPipeline implements DeliveryPipeline { } } - private PersonResultType performTnvzQuery(DeliveryRequestType request) { - var result = tnvzClient.query(request.getSender(), request.getReceiver()); - tnvzVerifier.verify(request, result); - return result; - } - private DeliveryRequestStatusType generateErrorStatus(MoaZSException exception, String appDeliveryId) { var infoBuilder = errorInfoTypeBuilder() 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 d3891e4..aea01bb 100644 --- a/src/main/java/at/gv/egiz/moazs/preprocess/DeliveryRequestAugmenter.java +++ b/src/main/java/at/gv/egiz/moazs/preprocess/DeliveryRequestAugmenter.java @@ -32,6 +32,7 @@ public class DeliveryRequestAugmenter { * Augments an incoming {@code request} by filling gaps with config- or default parameters. * * @param request + * @throws at.gv.egiz.moazs.MoaZSException * @return augmented request */ public DeliveryRequestType augment(DeliveryRequestType request) { diff --git a/src/main/java/at/gv/egiz/moazs/scheme/MoaZSPrefixMapper.java b/src/main/java/at/gv/egiz/moazs/scheme/MoaZSPrefixMapper.java index d725ce6..a7e0308 100644 --- a/src/main/java/at/gv/egiz/moazs/scheme/MoaZSPrefixMapper.java +++ b/src/main/java/at/gv/egiz/moazs/scheme/MoaZSPrefixMapper.java @@ -23,6 +23,8 @@ public class MoaZSPrefixMapper extends NamespacePrefixMapper { this(); map.put((isMzs) ? NameSpace.MZSP : NameSpace.MSGP, "p"); map.put((isMzs) ? NameSpace.MZS : NameSpace.MSG , ""); + + if (isMzs) map.put(NameSpace.TNVZ, "tnvz"); } @Override diff --git a/src/main/java/at/gv/egiz/moazs/scheme/Mzs2MsgConverter.java b/src/main/java/at/gv/egiz/moazs/scheme/Mzs2MsgConverter.java index 751f564..fdb2ab8 100644 --- a/src/main/java/at/gv/egiz/moazs/scheme/Mzs2MsgConverter.java +++ b/src/main/java/at/gv/egiz/moazs/scheme/Mzs2MsgConverter.java @@ -61,7 +61,7 @@ public class Mzs2MsgConverter { //------------- SENDER ------------------ - private Sender convert(at.gv.zustellung.app2mzs.xsd.DeliveryRequestType.Sender sender) { + public Sender convert(at.gv.zustellung.app2mzs.xsd.DeliveryRequestType.Sender sender) { return senderBuilder() .withSenderPerson(extractSenderPerson(sender)) .withLogo(sender.getLogo()) @@ -119,7 +119,7 @@ public class Mzs2MsgConverter { //------------- RECEIVER ------------------ - private at.gv.zustellung.msg.xsd.Receiver convert(at.gv.zustellung.app2mzs.xsd.DeliveryRequestType.Receiver receiver) { + public at.gv.zustellung.msg.xsd.Receiver convert(at.gv.zustellung.app2mzs.xsd.DeliveryRequestType.Receiver receiver) { return setupReceiverBuilder(receiver).build(); } @@ -170,7 +170,7 @@ public class Mzs2MsgConverter { .build(); } - private PostalAddressType convert(at.gv.zustellung.app2mzs.xsd.persondata.PostalAddressType address) { + public PostalAddressType convert(at.gv.zustellung.app2mzs.xsd.persondata.PostalAddressType address) { return postalAddressTypeBuilder() .withCountryCode(address.getCountryCode()) .withDeliveryAddress(convert(address.getDeliveryAddress())) @@ -227,7 +227,7 @@ public class Mzs2MsgConverter { //------------- IDENTIFICATION TYPE ------------- - private IdentificationType convert(at.gv.zustellung.app2mzs.xsd.persondata.IdentificationType identification) { + public IdentificationType convert(at.gv.zustellung.app2mzs.xsd.persondata.IdentificationType identification) { return identificationTypeBuilder() .withId(identification.getId()) .withType(identification.getType()) @@ -244,7 +244,7 @@ public class Mzs2MsgConverter { //------------ PERSONS -------------------- - private JAXBElement convert( + public JAXBElement convert( JAXBElement jaxbPerson) { var mzsPerson = jaxbPerson.getValue(); @@ -268,7 +268,7 @@ public class Mzs2MsgConverter { return person instanceof at.gv.zustellung.app2mzs.xsd.persondata.CorporateBodyType; } - private CorporateBodyType convert(at.gv.zustellung.app2mzs.xsd.persondata.CorporateBodyType corporateBody) { + public CorporateBodyType convert(at.gv.zustellung.app2mzs.xsd.persondata.CorporateBodyType corporateBody) { return corporateBodyTypeBuilder() .withFullName(corporateBody.getFullName()) .withId(corporateBody.getId()) 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 fc479eb..7c52af1 100644 --- a/src/main/java/at/gv/egiz/moazs/scheme/NameSpace.java +++ b/src/main/java/at/gv/egiz/moazs/scheme/NameSpace.java @@ -6,13 +6,10 @@ public class NameSpace { public static final String MSG = new at.gv.zustellung.msg.xsd.ObjectFactory().createDeliveryRequest(null).getName().getNamespaceURI(); public static final String MSG_VERSION = "2.2.0"; - 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 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(); } diff --git a/src/main/java/at/gv/egiz/moazs/tnvz/TnvzClient.java b/src/main/java/at/gv/egiz/moazs/tnvz/TnvzClient.java deleted file mode 100644 index 3efb564..0000000 --- a/src/main/java/at/gv/egiz/moazs/tnvz/TnvzClient.java +++ /dev/null @@ -1,19 +0,0 @@ -package at.gv.egiz.moazs.tnvz; - -import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType.Receiver; -import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType.Sender; -import at.gv.zustellung.tnvz.xsd.PersonResultSuccessType; -import at.gv.zustellung.tnvz.xsd.PersonResultType; -import at.gv.zustellung.tnvz.xsd.PersonResultType.PersonResultTypeBuilder; -import org.springframework.stereotype.Component; - -@Component -public class TnvzClient { - - public PersonResultType query(Sender sender, Receiver receiver) { - //TODO: Replace this stub with actual request. - PersonResultSuccessType success = new PersonResultSuccessType.PersonResultSuccessTypeBuilder().build(); - return new PersonResultTypeBuilder().withSuccess(success).build(); - } - -} diff --git a/src/main/java/at/gv/egiz/moazs/tnvz/TnvzHelper.java b/src/main/java/at/gv/egiz/moazs/tnvz/TnvzHelper.java new file mode 100644 index 0000000..a14df9d --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/tnvz/TnvzHelper.java @@ -0,0 +1,231 @@ +package at.gv.egiz.moazs.tnvz; + +import at.gv.egiz.moazs.MoaZSException; +import at.gv.egiz.moazs.scheme.Mzs2MsgConverter; +import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType; +import at.gv.zustellung.app2mzs.xsd.TnvzMetaDataType; +import at.gv.zustellung.app2mzs.xsd.persondata.AbstractAddressType; +import at.gv.zustellung.msg.xsd.persondata.IdentificationType; +import at.gv.zustellung.msg.xsd.persondata.ObjectFactory; +import at.gv.zustellung.msg.xsd.persondata.PostalAddressType; +import at.gv.zustellung.tnvz.xsd.*; +import at.gv.zustellung.tnvz.xsd.QueryPersonRequest.QueryEntryList; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.annotation.Nullable; +import javax.xml.bind.JAXBElement; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static at.gv.zustellung.tnvz.xsd.PersonQueryType.MetaData.metaDataBuilder; +import static at.gv.zustellung.tnvz.xsd.PersonQueryType.personQueryTypeBuilder; +import static at.gv.zustellung.tnvz.xsd.QueryPersonRequest.QueryEntryList.queryEntryListBuilder; +import static at.gv.zustellung.tnvz.xsd.QueryPersonRequest.queryPersonRequestBuilder; +import static at.gv.zustellung.tnvz.xsd.Receiver.receiverBuilder; +import static at.gv.zustellung.tnvz.xsd.Sender.senderBuilder; +import static java.lang.String.join; +import static java.util.stream.Collectors.toSet; + +@Component +public class TnvzHelper { + + private final Mzs2MsgConverter converter; + + private static final ObjectFactory FACTORY = new at.gv.zustellung.msg.xsd.persondata.ObjectFactory(); + private static final String ENTRY_ID = "entry-id"; + private static final String RECEIVER_NOT_ADRESSABLE_ERROR_MSG = "Receiver is not addressable. Reason: %s"; + private static final String MIMETYPE_MISSMATCH_ERROR_MSG = "Request contains attachment of type(s) %s, but " + + "receiver only accepts attachments of type(s) %s."; + private static final String MZS_NO_TNVZ_PERSON_QUERY_RESULTS_ERROR_MSG = "tnvz:PersonQueryResult's list was empty."; + + + @Autowired + public TnvzHelper(Mzs2MsgConverter converter) { + this.converter = converter; + } + + /** + * Performs all tasks related to making a request to the tnvz service: + * Derives a tnvz:QueryPersonRequest from the {@code mzsRequest}, sends the QueryPersonRequest to + * {@code tvnzPort}, validates the tnvz's response and extracts the {@code Identification} Element. + * @param mzsRequest Data source for the QueryPersonRequest + * @param tvnzPort Client for communicating with the tnvz service + * @param exceptionBuilder Utility to collect information and build a meaningful exception in case of errors. + * @throws MoaZSException in case of an error. + * @return + */ + public IdentificationType performQueryPersonRequest(DeliveryRequestType mzsRequest, + TNVZServicePort tvnzPort, + MoaZSException.Builder exceptionBuilder) { + + var tvnzQuery = buildQuery(mzsRequest); + var tvnzResponse = tvnzPort.queryPerson(tvnzQuery); + verifyResponse(tvnzResponse, exceptionBuilder); + + var tvnzResult = getResult(tvnzResponse); + var typesInRequest = extractListOfMimemtypesIn(mzsRequest); + checkMimetypes(tvnzResult, typesInRequest, exceptionBuilder); + + return tvnzResult.getSuccess().getIdentification(); + } + + private QueryPersonRequest buildQuery(DeliveryRequestType mzsRequest) { + + Sender sender = extractSender(mzsRequest.getSender().getCorporateBody()); + Receiver receiver = extractReceiver(mzsRequest.getReceiver()); + var metadata = extractMetaData(mzsRequest.getTnvzMetaData()); + + PersonQueryType personQuery = personQueryTypeBuilder() + .withEntryID(ENTRY_ID) + .withSender(sender) + .withReceiver(receiver) + .withMetaData(metadata) + .build(); + + QueryEntryList entryList = queryEntryListBuilder() + .withQueryEntry(List.of(personQuery)) + .build(); + + return queryPersonRequestBuilder() + .withQueryEntryList(entryList) + .build(); + } + + private PersonQueryType.MetaData extractMetaData(@Nullable TnvzMetaDataType meta) { + if (meta == null) { + return null; + } else { + var builder = metaDataBuilder(); + + if (meta.getDeliveryQuality() != null) { + builder.withDeliveryQuality(meta.getDeliveryQuality()); + } else { + builder.withPrivateMessageQuality(meta.getPrivateMessageQuality()); + } + + return builder + .withOrigin(meta.getOrigin()) + .withPreAdviceNote(meta.getPreAdviceNote()) + .withIgnorePostRedirectionOrder(meta.getIgnorePostRedirectionOrder()) + .build(); + } + } + + private Sender extractSender(at.gv.zustellung.app2mzs.xsd.persondata.CorporateBodyType corporateBody) { + + var mzsIdentification = corporateBody.getIdentification().get(0); + var msgIdentification = converter.convert(mzsIdentification); + + var msgPerson = FACTORY.createPerson(converter.convert(corporateBody)); + + return senderBuilder() + .withIdentification(msgIdentification) + .withPerson(msgPerson) + .build(); + } + + private Receiver extractReceiver(DeliveryRequestType.Receiver receiver) { + + var builder = receiverBuilder(); + + if (receiver.getIdentification() != null) { + builder.withIdentification(converter.convert(receiver.getIdentification())); + } else { + builder + .withPerson(converter.convert(receiver.getPerson())) + .withAustrianAddressesOnly(receiver.getAustrianAddressesOnly()); + + var postalAddress = findPostalAddress(receiver.getAddress()); + if (postalAddress != null) + builder.withPostalAddress(postalAddress); + + if (receiver.getPreAdviceNote() != null) { + builder.withNotificationAddressList(receiver.getPreAdviceNote().getNotificationAddressList()); + } + } + + return builder.build(); + } + + private @Nullable PostalAddressType findPostalAddress(List> addresses) { + + for (JAXBElement address : addresses) { + if(address.getValue() instanceof at.gv.zustellung.app2mzs.xsd.persondata.PostalAddressType) { + var mzsPostalAddress = (at.gv.zustellung.app2mzs.xsd.persondata.PostalAddressType) address.getValue(); + return converter.convert(mzsPostalAddress); + } + } + + return null; + + } + + private Set extractListOfMimemtypesIn(DeliveryRequestType mzsRequest) { + return mzsRequest.getPayload().stream() + .map(DeliveryRequestType.Payload::getMIMEType) + .collect(toSet()); + } + + private void verifyResponse(QueryPersonResponse tvnzResponse, MoaZSException.Builder mzsBuilder) { + + var error = tvnzResponse.getError(); + if (error != null) { + throw mzsBuilder.withErrorCode(error.getCode()) + .withMessage(error.getText()) + .build(); + } + + var results = tvnzResponse.getQueryResultList().getQueryResult(); + if (results.isEmpty()) { + throw mzsBuilder.withErrorCode(MoaZSException.ERROR_MZS_NO_TNVZ_PERSON_QUERY_RESULTS) + .withMessage(MZS_NO_TNVZ_PERSON_QUERY_RESULTS_ERROR_MSG) + .build(); + } + + var tnvzResult = results.get(0); + mzsBuilder.withTnvzResult(tnvzResult); + if (tnvzResult.getError() != null) { + var info = tnvzResult.getError().getErrorInfo(); + throw mzsBuilder.withErrorCode(info.getCode()) + .withMessage(RECEIVER_NOT_ADRESSABLE_ERROR_MSG, info.getText()) + .build(); + } + } + + private PersonResultType getResult(QueryPersonResponse tvnzResponse) { + return tvnzResponse.getQueryResultList().getQueryResult().get(0); + } + + private void checkMimetypes(PersonResultType tnvzResult, Set typesInRequest, MoaZSException.Builder mzsBuilder) { + var mismatchedTypes = findMimeTypeMismatches(tnvzResult, typesInRequest); + if (!mismatchedTypes.isEmpty()) { + var acceptedTypesString = join(",", getAcceptedTypes(tnvzResult)); + var mismatchedTypesString = join(",", mismatchedTypes); + throw mzsBuilder.withErrorCode(MoaZSException.ERROR_MZS_MIMETYPE_MISSMATCH) + .withMessage(MIMETYPE_MISSMATCH_ERROR_MSG, mismatchedTypesString, acceptedTypesString) + .build(); + } + } + + private Collection findMimeTypeMismatches(PersonResultType result, Set typesInRequest) { + var acceptedTypes = getAcceptedTypes(result); + + if (acceptedTypes.contains("*/*")) { + return List.of(); + } + + var typesInRequestCopy = new HashSet<>(typesInRequest); + typesInRequestCopy.removeAll(acceptedTypes); + + return typesInRequestCopy; + } + + private List getAcceptedTypes(PersonResultType result) { + return result.getSuccess().getMimeTypeList().getMimeType(); + } + + +} diff --git a/src/main/java/at/gv/egiz/moazs/tnvz/TnvzResultVerifier.java b/src/main/java/at/gv/egiz/moazs/tnvz/TnvzResultVerifier.java deleted file mode 100644 index 9992246..0000000 --- a/src/main/java/at/gv/egiz/moazs/tnvz/TnvzResultVerifier.java +++ /dev/null @@ -1,63 +0,0 @@ -package at.gv.egiz.moazs.tnvz; - -import at.gv.egiz.moazs.MoaZSException; -import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType; -import at.gv.zustellung.tnvz.xsd.PersonResultType; -import org.springframework.stereotype.Component; - -import java.util.Collection; -import java.util.List; - -import static at.gv.egiz.moazs.MoaZSException.moaZSExceptionBuilder; -import static java.lang.String.join; -import static java.util.stream.Collectors.toSet; - -@Component -public class TnvzResultVerifier { - - public void verify(DeliveryRequestType request, PersonResultType result) { - - if (result.getError() != null) { - var info = result.getError().getErrorInfo(); - throw moaZSExceptionBuilder("Receiver is not addressable. Reason: %s", info.getText()) - .withErrorCode(info.getCode()) - .withMzsRequest(request) - .withTnvzResult(result) - .build(); - } - - var mismatchedTypes = findMimeTypeMismatches(result, request); - - if (!mismatchedTypes.isEmpty()) { - var template = "Request contains attachment of type(s) %s, but receiver only accepts attachments" + - " of type(s) %s."; - var acceptedTypesString = join(",", getAcceptedTypes(result)); - var mismatchedTypesString = join(",", mismatchedTypes); - throw moaZSExceptionBuilder(template, mismatchedTypesString, acceptedTypesString) - .withErrorCode(MoaZSException.ERROR_MZS_MIMETYPE_MISSMATCH) - .withMzsRequest(request) - .withTnvzResult(result) - .build(); - } - } - - private Collection findMimeTypeMismatches(PersonResultType result, DeliveryRequestType request) { - var acceptedTypes = getAcceptedTypes(result); - - if (acceptedTypes.contains("*/*")) { - return List.of(); - } - - var typesInRequest = request.getPayload().stream() - .map(DeliveryRequestType.Payload::getMIMEType) - .collect(toSet()); - - typesInRequest.removeAll(acceptedTypes); - - return typesInRequest; - } - - private List getAcceptedTypes(PersonResultType result) { - return result.getSuccess().getMimeTypeList().getMimeType(); - } -} -- cgit v1.2.3