package at.gv.egiz.moazs; import at.gv.e_government.reference.namespace.zustellung.msg.phase2._20181206_.DeliveryAnswerType.DeliveryAnswerTypeBuilder; import at.gv.e_government.reference.namespace.zustellung.msg.phase2._20181206_.DeliveryRequestStatusType; import at.gv.e_government.reference.namespace.zustellung.msg.phase2._20181206_.DeliveryRequestStatusType.DeliveryRequestStatusTypeBuilder; import at.gv.e_government.reference.namespace.zustellung.msg.phase2._20181206_.DeliveryRequestStatusType.Error.ErrorBuilder; import at.gv.e_government.reference.namespace.zustellung.msg.phase2._20181206_.ErrorInfoType.ErrorInfoTypeBuilder; import at.gv.e_government.reference.namespace.zustellung.mzs.app2mzs.App2MzsPortType; import at.gv.e_government.reference.namespace.zustellung.mzs.app2mzs_.DeliveryRequestType; import at.gv.egiz.moazs.pipeline.DeliveryPipeline; import at.gv.egiz.moazs.repository.DeliveryRepository; 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) { final var appDeliveryID = deliveryRequest.getMetaData().getAppDeliveryID(); var future = supplyAsync(() -> preprocessor.preProcess(deliveryRequest)) .thenApply((request) -> process(request)); 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 ) { logger.error("Could not deliver request.", e); var message = format("An error occured while delivering request: {0}", e.getMessage()); return generateErrorResponse(appDeliveryID, message); } } private DeliveryRequestStatusType generatePartialSuccessResponse(String appDeliveryId) { var answer = new DeliveryAnswerTypeBuilder() .withAppDeliveryID(appDeliveryId) .build(); return new DeliveryRequestStatusTypeBuilder() .withPartialSuccess(answer) .build(); } private DeliveryRequestStatusType generateErrorResponse(String appDeliveryId, String message) { var info = new ErrorInfoTypeBuilder() .withCode("500") .withText(message) .build(); var error = new ErrorBuilder() .withAppDeliveryID(appDeliveryId) .withErrorInfo(info) .build(); return new DeliveryRequestStatusTypeBuilder() .withError(error) .build(); } 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)); } }