/******************************************************************************* * Copyright 2019 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.backend; import at.gv.egiz.moazs.MoaZSException; import at.gv.egiz.moazs.client.ClientFactory; import at.gv.egiz.moazs.client.TnvzHelper; import at.gv.egiz.moazs.repository.DeliveryRepository; import at.gv.egiz.moazs.scheme.Marshaller; import at.gv.egiz.moazs.scheme.Mzs2MsgConverter; import at.gv.egiz.moazs.scheme.RequestStatusResponse; import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType; import at.gv.zustellung.msg.xsd.App2ZusePort; import at.gv.zustellung.msg.xsd.DeliveryRequestStatusType; import at.gv.zustellung.tnvz.xsd.TNVZServicePort; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component; import java.util.function.Consumer; import static at.gv.egiz.moazs.MoaZSException.moaZSException; import static at.gv.egiz.moazs.scheme.RequestStatusResponse.generateError; import static at.gv.egiz.moazs.scheme.RequestStatusResponse.getAnswer; import static at.gv.zustellung.msg.xsd.DeliveryRequestStatusType.Error.errorBuilder; import static java.lang.String.format; /** * @author Christof Rabensteiner * */ @Component @Profile("!cluster") public class DeliveryRequestBackend implements Consumer { private static final Logger log = LoggerFactory.getLogger(DeliveryRequestBackend.class); private static final String MZS_PIPELINE_ERROR_MSG = "An error occured while processing the DeliveryRequest with AppDeliveryID=%s. "; private static final String DELIVERY_REQUEST_MISSING_ERROR_MSG = "DeliveryRequest for AppDeliveryID=%s is not in repository. " ; private static final String BINARY_RESPONSE_MISSING_ERROR_MSG = "Binary DeliveryRequestStatus for AppDeliveryID=%s is not in repository. " ; private static final String BACKEND_ACCEPT_MSG = "Backend accepts mzs:DeliveryRequest with AppDeliveryID={}."; private static final at.gv.zustellung.app2mzs.xsd.ObjectFactory mzsOF = new at.gv.zustellung.app2mzs.xsd.ObjectFactory(); private static final at.gv.zustellung.msg.xsd.ObjectFactory msgOF = new at.gv.zustellung.msg.xsd.ObjectFactory(); @Autowired(required = false) private Marshaller mzsMarshaller; @Autowired(required = false) private Marshaller msgMarshaller; private final DeliveryRepository repository; private final TnvzHelper tnvzHelper; private final Mzs2MsgConverter converter; private final ClientFactory clientFactory; private final Consumer signatureVerifier; @Autowired public DeliveryRequestBackend(DeliveryRepository repository, TnvzHelper tnvzHelper, Mzs2MsgConverter converter, ClientFactory clientFactory, Consumer signatureVerifier) { this.repository = repository; this.tnvzHelper = tnvzHelper; this.converter = converter; this.clientFactory = clientFactory; this.signatureVerifier = signatureVerifier; } /** * Performs all {@code DeliveryRequest}'s Back-End Tasks. * * Fetches {@code DeliveryRequest} referred by appDeliveryID from * {@code DeliveryRepository}, makes sure that all necessary * tasks (query tnvz, query msg, accept status) are executed and * stores the response back to {@code DeliveryRepository}. * @param appDeliveryID */ @Override public void accept(String appDeliveryID) { log.info(BACKEND_ACCEPT_MSG, appDeliveryID); DeliveryRequestStatusType status = null; var fallbackAnswerBuilder = errorBuilder().withAppDeliveryID(appDeliveryID); try { var mzsRequest = repository.retrieveDeliveryRequest(appDeliveryID).orElseThrow( () -> moaZSException(format(DELIVERY_REQUEST_MISSING_ERROR_MSG, appDeliveryID))); traceMzsRequest(mzsRequest); fallbackAnswerBuilder.withDeliverySystem(mzsRequest.getConfig().getMSGClient().getURL()); var msgRequest = buildMsgRequest(mzsRequest); traceMsgRequest(msgRequest); var msgClientParams = mzsRequest.getConfig().getMSGClient(); App2ZusePort client = clientFactory.createSOAP12(msgClientParams, App2ZusePort.class); status = client.delivery(msgRequest); traceMsgResponse(status); var response = new RequestStatusResponse(status); verifySignedStatus(response.getResponseID(), appDeliveryID); repository.store(response); } catch (MoaZSException exception) { log.error(format(MZS_PIPELINE_ERROR_MSG, appDeliveryID), exception); var templateAnswer = (status == null) ? fallbackAnswerBuilder.build() : getAnswer(status); var errorStatus = generateError(exception, templateAnswer); repository.store(errorStatus); } } private void verifySignedStatus(String responseID, String appDeliveryID) throws MoaZSException { var signedStatus = repository.retrieveBinaryResponse(responseID).orElseThrow(() -> moaZSException( format(BINARY_RESPONSE_MISSING_ERROR_MSG, responseID), MoaZSException.ERROR_MZS_BINARY_RESPONSE_MISSING)); try { signatureVerifier.accept(signedStatus); } catch (MoaZSException ex) { var message = format(MsgResponseBackend.MOASP_SIGNATURE_INVALID_ERROR_MSG, appDeliveryID); var code = MoaZSException.ERROR_MOASP_SIGNATURE_INVALID; throw moaZSException(message, code, ex); } } private at.gv.zustellung.msg.xsd.DeliveryRequestType buildMsgRequest(DeliveryRequestType mzsRequest) throws MoaZSException { if (mzsRequest.getConfig().isPerformQueryPersonRequest()) { log.trace("Perform QueryPersonRequest. "); var tnvzClientParams = mzsRequest.getConfig().getTNVZClient(); TNVZServicePort tnvzPort = clientFactory.createSOAP12(tnvzClientParams, TNVZServicePort.class); var identification = tnvzHelper.performQueryPersonRequest(mzsRequest, tnvzPort); return converter.convert(mzsRequest, identification); } else { return converter.convert(mzsRequest); } } private void traceMzsRequest(DeliveryRequestType mzsRequest) { if (log.isTraceEnabled() && mzsMarshaller != null) { log.trace("mzs:DeliveryRequest: {}", mzsMarshaller.marshallXml(mzsOF.createDeliveryRequest(mzsRequest))); } } private void traceMsgRequest(at.gv.zustellung.msg.xsd.DeliveryRequestType msgRequest) { if (log.isTraceEnabled() && msgMarshaller != null) { log.trace("msg:DeliveryRequest: {}", msgMarshaller.marshallXml(msgOF.createDeliveryRequest(msgRequest))); } } private void traceMsgResponse(DeliveryRequestStatusType status) { if (log.isTraceEnabled() && msgMarshaller != null) { log.trace("msg:DeliveryResponse: {}", msgMarshaller.marshallXml(msgOF.createDeliveryResponse(status))); } } }