package at.gv.egiz.moazs; import at.gv.egiz.moazs.pipeline.DeliveryPipeline; import at.gv.egiz.moazs.preprocess.DeliveryRequestAugmenter; import at.gv.egiz.moazs.repository.DeliveryRepository; import at.gv.zustellung.app2mzs.xsd.App2MzsPortType; import at.gv.zustellung.app2mzs.xsd.DeliveryRequestType; 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 static at.gv.egiz.moazs.MoaZSException.moaZSException; import static at.gv.zustellung.msg.xsd.DeliveryAnswerType.deliveryAnswerTypeBuilder; import static at.gv.zustellung.msg.xsd.DeliveryRequestStatusType.deliveryRequestStatusTypeBuilder; 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 App2MzsService implements App2MzsPortType { private static final Logger logger = LoggerFactory.getLogger(App2MzsService.class); //TODO move timeout and namespaces to config private static final int TIMEOUT_FOR_ANWSER = 10; private final DeliveryRepository repository; private final DeliveryPipeline pipeline; private final Mzs2AppClient appClient; private final DeliveryRequestAugmenter augmenter; @Autowired public App2MzsService(DeliveryRepository repository, DeliveryPipeline pipeline, Mzs2AppClient appClient, DeliveryRequestAugmenter augmenter) { this.repository = repository; this.pipeline = pipeline; this.appClient = appClient; this.augmenter = augmenter; } @Override public DeliveryRequestStatusType app2Mzs( @WebParam(partName = "DeliveryRequest", name = "DeliveryRequest") DeliveryRequestType deliveryRequest) { var appDeliveryID = deliveryRequest.getMetaData().getAppDeliveryID(); var future = supplyAsync(() -> augmenter.augment(deliveryRequest)) .thenApply(this::process); try { return future.get(TIMEOUT_FOR_ANWSER, TimeUnit.SECONDS); } catch (TimeoutException e) { future.thenAccept(appClient::sendNotification); logger.info("Answer Timed Out", e); return generatePartialSuccessResponse(appDeliveryID); } catch (Exception e ) { var message = format("An error occurred while processing DeliveryRequest with AppDeliveryID=%s. ", appDeliveryID); throw new MoaZSException(message, e); } } private DeliveryRequestStatusType process(DeliveryRequestType deliveryRequest) { var appDeliveryID = deliveryRequest.getMetaData().getAppDeliveryID(); logger.info("Receive request with appDeliveryID = {}.", appDeliveryID); repository.add(deliveryRequest); pipeline.processRequest(appDeliveryID); return repository.getDeliveryRequestStatus(appDeliveryID) .orElseThrow(() -> moaZSException("Could not get a response for AppDeliveryID=%s.", appDeliveryID)); } private DeliveryRequestStatusType generatePartialSuccessResponse(String appDeliveryId) { var answer = deliveryAnswerTypeBuilder() .withAppDeliveryID(appDeliveryId) .build(); return deliveryRequestStatusTypeBuilder() .withPartialSuccess(answer) .build(); } }