package at.gv.egiz.moazs.client; 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.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:QueryResultList 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()); Receiver receiver = extractReceiver(mzsRequest.getReceiver()); var metadata = extractMetaData(mzsRequest); 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(DeliveryRequestType request) { var builder = metaDataBuilder(); var meta = request.getTnvzMetaData(); if (meta.getDeliveryQuality() != null) { builder.withDeliveryQuality(meta.getDeliveryQuality()); } else { builder.withPrivateMessageQuality(meta.getPrivateMessageQuality()); } return builder .withOrigin(meta.getOrigin()) .withPreAdviceNote(request.getReceiver().getPreAdviceNote()) .withIgnorePostRedirectionOrder(meta.getIgnorePostRedirectionOrder()) .build(); } private Sender extractSender(DeliveryRequestType.Sender sender) { var corporateBody = sender.getCorporateBody(); 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 .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()); } } else { builder.withIdentification(converter.convert(receiver.getIdentification())); } return builder.build(); } private @Nullable PostalAddressType findPostalAddress(List> addresses) { if (addresses == null) return null; 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.withPreAdviceNoteSent(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(); } }