package at.gv.egiz.moazs.service; import at.gv.egiz.moazs.preprocess.DeliveryRequestAugmenter; import at.gv.egiz.moazs.repository.DeliveryRepository; import at.gv.egiz.moazs.scheme.Msg2MzsConverter; 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; import at.gv.zustellung.msg.xsd.DeliveryRequestStatusType; import org.apache.cxf.annotations.SchemaValidation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.jws.WebParam; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.function.Consumer; import static at.gv.egiz.moazs.MoaZSException.moaZSException; import static at.gv.zustellung.app2mzs.xsd.PartialSuccessType.partialSuccessTypeBuilder; import static java.lang.String.format; import static java.util.concurrent.CompletableFuture.supplyAsync; //todo : validate Schema in both directions. @Service @SchemaValidation(type = SchemaValidation.SchemaValidationType.IN) public class MzsService implements App2MzsPortType { private static final Logger logger = LoggerFactory.getLogger(MzsService.class); //TODO move timeout and namespaces to config private static final int TIMEOUT_FOR_ANWSER = 10; private static final String MZS_SERVICE_ERROR_MSG = "An error occurred while processing DeliveryRequest " + "with AppDeliveryID=%s."; private static final String RESPONSE_MISSING_ERROR_MSG = "Could not get a response for AppDeliveryID=%s."; private final DeliveryRepository repository; private final Consumer backend; private final DeliveryRequestAugmenter augmenter; private final Msg2MzsConverter converter; @Autowired public MzsService(DeliveryRepository repository, Consumer deliveryRequestBackend, DeliveryRequestAugmenter augmenter, Msg2MzsConverter converter) { this.repository = repository; this.backend = deliveryRequestBackend; this.augmenter = augmenter; this.converter = converter; } @Override public DeliveryResponseType app2Mzs( @WebParam(partName = "DeliveryRequest", name = "DeliveryRequest") 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.retrieveBinaryResponse(responseID))); try { return future.get(TIMEOUT_FOR_ANWSER, TimeUnit.SECONDS); } catch (TimeoutException e) { logger.info("Answer Timed Out", e); //TODO: revise how notification should be sent //future.thenAccept(appClient::sendNotification); return generatePartialSuccessResponse(appDeliveryID); } catch (Exception e) { var message = format(MZS_SERVICE_ERROR_MSG, appDeliveryID); throw moaZSException(message, e); } } private DeliveryRequestStatusType process(DeliveryRequestType deliveryRequest) { var appDeliveryID = deliveryRequest.getMetaData().getAppDeliveryID(); //TODO: fix too. logger.info("Receive request with appDeliveryID = {}.", appDeliveryID); repository.store(deliveryRequest); backend.accept(appDeliveryID); var statusId = RequestStatusResponse.getResponseID(appDeliveryID); var response = repository.retrieveResponse(statusId) .orElseThrow(() -> moaZSException(format(RESPONSE_MISSING_ERROR_MSG, appDeliveryID))); return (DeliveryRequestStatusType) response.getResponse(); } private DeliveryResponseType generatePartialSuccessResponse(String appDeliveryId) { var partial = partialSuccessTypeBuilder() .withAppDeliveryID(appDeliveryId) .build(); return DeliveryResponseType.deliveryResponseTypeBuilder() .withPartialSuccess(partial) .build(); } }