package at.gv.egiz.moazs; import at.gv.egiz.moazs.pipeline.DeliveryPipeline; 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.DeliveryAnswerType; import at.gv.zustellung.msg.xsd.DeliveryAnswerType.DeliveryAnswerTypeBuilder; import at.gv.zustellung.msg.xsd.DeliveryRequestStatusType; import at.gv.zustellung.msg.xsd.DeliveryRequestStatusType.DeliveryRequestStatusTypeBuilder; 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 java.text.MessageFormat.format; import static java.util.concurrent.CompletableFuture.supplyAsync; @Service 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 static final String MZSTNS = "http://reference.e-government.gv.at/namespace/zustellung/mzs/app2mzs#"; private final DeliveryRepository repository; private final DeliveryPipeline pipeline; private final Mzs2AppClient appClient; private final DeliveryPreprocessor preprocessor; public App2MzsService(@Autowired DeliveryRepository repository, @Autowired DeliveryPipeline pipeline, @Autowired Mzs2AppClient appClient, @Autowired DeliveryPreprocessor preprocessor) { this.repository = repository; this.pipeline = pipeline; this.appClient = appClient; this.preprocessor = preprocessor; } @Override public DeliveryRequestStatusType app2Mzs( @WebParam(partName = "DeliveryRequest", name = "DeliveryRequest", targetNamespace = MZSTNS) DeliveryRequestType deliveryRequest) { var future = supplyAsync(() -> preprocessor.preProcess(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); var appDeliveryID = deliveryRequest.getMetaData().getAppDeliveryID(); return generatePartialSuccessResponse(appDeliveryID); } catch (Exception e ) { logger.error("Could not deliver request.", e); var message = format("An error occurred while processing DeliveryRequest"); throw new RuntimeException(message, e); } } private DeliveryRequestStatusType process(DeliveryRequestType deliveryRequest) throws RuntimeException { var appDeliveryID = deliveryRequest.getMetaData().getAppDeliveryID(); logger.info("Receive request with appDeliveryID = {}.", appDeliveryID); repository.add(deliveryRequest); pipeline.processRequest(appDeliveryID); return repository.getDeliveryRequestStatus(appDeliveryID) .orElseThrow(() -> new RuntimeException("Could not get a response for appDeliveryId = " + appDeliveryID)); } private DeliveryRequestStatusType generatePartialSuccessResponse(String appDeliveryId) { var answer = new DeliveryAnswerTypeBuilder() .withAppDeliveryID(appDeliveryId) .build(); return new DeliveryRequestStatusTypeBuilder() .withPartialSuccess(answer) .build(); } }