/******************************************************************************* * Copyright 2020 Graz University of Technology * MOA ZS has been developed in a cooperation between EGIZ * and Graz University of Technology. * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and * limitations under the Licence. * * This product combines work with different licenses. See the "NOTICE" text * file for details on the various modules and licenses. * The "NOTICE" text file is part of the distribution. Any derivative works * that you distribute must include a readable copy of the "NOTICE" text file. *******************************************************************************/ 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.slf4j.Logger; import org.slf4j.LoggerFactory; 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.egiz.moazs.MoaZSException.moaZSException; 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; /** * @author Christof Rabensteiner * */ @Component public class TnvzHelper { private static final Logger log = LoggerFactory.getLogger(TnvzHelper.class); 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."; private final Mzs2MsgConverter converter; @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 tnvzPort}, validates the tnvz's response and extracts the {@code Identification} Element. * @param mzsRequest Data source for the QueryPersonRequest * @param tnvzPort Client for communicating with the tnvz service * @throws MoaZSException in case of an error. * @return */ public IdentificationType performQueryPersonRequest(DeliveryRequestType mzsRequest, TNVZServicePort tnvzPort) { log.info("Perform Query Person Request for mzs:DeliveryRequest with AppDeliveryID={}", mzsRequest.getMetaData().getAppDeliveryID()); var tnvzQuery = buildQuery(mzsRequest); var tnvzResponse = tnvzPort.queryPerson(tnvzQuery); verifyResponse(tnvzResponse); var tnvzResult = getFirstResult(tnvzResponse); var typesInRequest = extractListOfMimemtypesIn(mzsRequest); checkMimetypes(tnvzResponse, typesInRequest); return tnvzResult.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.getMetaData(); if (meta.getDeliveryQuality() != null) { builder.withDeliveryQuality(meta.getDeliveryQuality()); } else { builder.withPrivateMessageQuality(meta.getPrivateMessageQuality()); } return builder.withOrigin(meta.getOrigin()) .withIgnorePostRedirectionOrder(meta.getIgnorePostRedirectionOrder()) .withPreAdviceNote(request.getReceiver().getPreAdviceNote()) .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.createCorporateBody(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.convertReceiverPerson(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 tnvzResponse) { var error = tnvzResponse.getError(); if (error != null) { throw MoaZSException.moaZSException(error.getText(), error.getCode()); } var results = tnvzResponse.getQueryResultList().getQueryResult(); if (results.isEmpty()) { throw MoaZSException.moaZSException(MZS_NO_TNVZ_PERSON_QUERY_RESULTS_ERROR_MSG, MoaZSException.ERROR_MZS_NO_TNVZ_PERSON_QUERY_RESULTS); } var tnvzResult = results.get(0); if (tnvzResult.getError() != null) { var info = tnvzResult.getError().getErrorInfo(); var message = String.format(RECEIVER_NOT_ADRESSABLE_ERROR_MSG, info.getText()); var code = info.getCode(); throw moaZSException(message, code, tnvzResult.getError().getPreAdviceNoteSent()); } } private PersonResultType getFirstResult(QueryPersonResponse tnvzResponse) { return tnvzResponse.getQueryResultList().getQueryResult().get(0); } private void checkMimetypes(QueryPersonResponse tnvzResponse, Set typesInRequest) { var mismatchedTypes = findMimeTypeMismatches(tnvzResponse, typesInRequest); if (!mismatchedTypes.isEmpty()) { var acceptedTypesString = join(",", getAcceptedTypes(tnvzResponse)); var mismatchedTypesString = join(",", mismatchedTypes); var message = String.format(MIMETYPE_MISSMATCH_ERROR_MSG, mismatchedTypesString, acceptedTypesString); var code = MoaZSException.ERROR_MZS_MIMETYPE_MISSMATCH; throw MoaZSException.moaZSException(message, code); } } private Collection findMimeTypeMismatches(QueryPersonResponse response, Set typesInRequest) { var acceptedTypes = getAcceptedTypes(response); var result = getFirstResult(response); if (result.getSuccess().getAllStandardMimeTypes() != null) { return List.of(); } var typesInRequestCopy = new HashSet<>(typesInRequest); typesInRequestCopy.removeAll(acceptedTypes); return typesInRequestCopy; } private Set getAcceptedTypes(QueryPersonResponse response) { Set union = new HashSet<>(); var standardTypes = response.getStandardMimeTypeList().getMimeType(); union.addAll(standardTypes); var acceptedTypeList = getFirstResult(response).getSuccess().getMimeTypeList(); if(acceptedTypeList != null) { union.addAll(acceptedTypeList.getMimeType()); } return union; } }