diff options
| author | Christof Rabensteiner <christof.rabensteiner@iaik.tugraz.at> | 2019-04-18 11:05:31 +0200 | 
|---|---|---|
| committer | Christof Rabensteiner <christof.rabensteiner@iaik.tugraz.at> | 2019-04-18 14:48:17 +0200 | 
| commit | aed1250912476f47fd772b0cedd20c850cdcff6e (patch) | |
| tree | e7fe6aed56b12e53a9b2a7eef62d339e7d23b8b2 /src/main/java | |
| parent | 4215362c64064947cea880d55c4aae7894304783 (diff) | |
| download | moa-zs-aed1250912476f47fd772b0cedd20c850cdcff6e.tar.gz moa-zs-aed1250912476f47fd772b0cedd20c850cdcff6e.tar.bz2 moa-zs-aed1250912476f47fd772b0cedd20c850cdcff6e.zip | |
Change App2mzs Interface and Init Delivery Pipeline
- Change app2mzs interface: output message from
  app2mzs:DeliveryRequest was app2mzs:DeliveryResponse, now its
  msg:DeliveryRequestStatus. Reason: ZD returns
  msg:DeliveryRequestStatus which is signed. Moazs does not convert
  msg:DeliveryRequestStatus into app2mzs:DeliveryResponse because the
  conversion woudl break the signature.
- App2MzsService: Make beans final and inject them with constructor;
  Refactor DeliveryRequestHandler into App2MZSService.
- DeliveryPipeline: Add Interface and a "SameThreadImplementation"
  that executes the pipeline in the same threat and can be used in
  single mode.
- DeliveryRepository: Augment interface for storing and retrieving
  request status objects; Add in-memory-implementation for status objects.
- Utils: Add helper function for coalescing multiple values
Diffstat (limited to 'src/main/java')
9 files changed, 198 insertions, 77 deletions
| diff --git a/src/main/java/at/gv/egiz/moazs/App2MzsService.java b/src/main/java/at/gv/egiz/moazs/App2MzsService.java index f8c00fc..8626c24 100644 --- a/src/main/java/at/gv/egiz/moazs/App2MzsService.java +++ b/src/main/java/at/gv/egiz/moazs/App2MzsService.java @@ -1,18 +1,21 @@  package at.gv.egiz.moazs; +import at.gv.e_government.reference.namespace.zustellung.msg.phase2._20181206_.DeliveryRequestStatusType; +import at.gv.e_government.reference.namespace.zustellung.msg.phase2._20181206_.ObjectFactory;  import at.gv.e_government.reference.namespace.zustellung.mzs.app2mzs.App2MzsPortType; -import at.gv.e_government.reference.namespace.zustellung.mzs.app2mzs_.*; +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.math.BigInteger; -import java.util.concurrent.ExecutionException;  import java.util.concurrent.TimeUnit;  import java.util.concurrent.TimeoutException; +import static java.text.MessageFormat.format;  import static java.util.concurrent.CompletableFuture.supplyAsync;  @Service @@ -20,63 +23,93 @@ public class App2MzsService implements App2MzsPortType {      private static final Logger logger = LoggerFactory.getLogger(App2MzsService.class); -    //TODO move timeout to config -    private final int timeoutForAnwser = 10; -    private final String MZSTNS = "http://reference.e-government.gv.at/namespace/zustellung/mzs/app2mzs#"; +    //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#"; -    @Autowired -    private DeliveryRequestHandler deliveryRequestHandler; +    private final DeliveryRepository repository; +    private final DeliveryPipeline pipeline; +    private final Mzs2AppClient appClient; +    private final ObjectFactory objectFactory = new ObjectFactory(); -    @Autowired -    private Mzs2AppClient appClient; - -    @Autowired -    private ObjectFactory objectFactory; +    public App2MzsService(@Autowired DeliveryRepository repository, @Autowired DeliveryPipeline pipeline, @Autowired Mzs2AppClient appClient) { +        this.repository = repository; +        this.pipeline = pipeline; +        this.appClient = appClient; +    }      @Override -    public DeliveryResponseType app2Mzs( +    public DeliveryRequestStatusType app2Mzs(              @WebParam(partName = "DeliveryRequest",                        name = "DeliveryRequest",                        targetNamespace = MZSTNS)                      DeliveryRequestType deliveryRequest) { -        var future = supplyAsync(() -> deliveryRequestHandler.apply(deliveryRequest)); +        final var appDeliveryID = deliveryRequest.getMetaData().getAppDeliveryID(); + +        var future = supplyAsync(() -> process(deliveryRequest));          try { -            return future.get(timeoutForAnwser, TimeUnit.SECONDS); +            return future.get(TIMEOUT_FOR_ANWSER, TimeUnit.SECONDS);          } catch (TimeoutException e) {              future.thenAccept(appClient::sendNotification); -            logger.warn("Answer Timed Out", e); -            return generatePartialSuccessResponse(deliveryRequest); +            logger.info("Answer Timed Out", e); +            return generatePartialSuccessResponse(appDeliveryID, "Your request timed out; Wait until X for receiving a notification.");          } catch (Exception e ) {              logger.error("Could not deliver request.", e); -            return generateErrorResponse(); +            final var message = format("An error occured while delivering request: {}", e.getMessage()); +            return generateErrorResponse(appDeliveryID, message);          }      } -    private DeliveryResponseType generatePartialSuccessResponse(DeliveryRequestType deliveryRequest) { +    private DeliveryRequestStatusType generatePartialSuccessResponse(String appDeliveryId, String message) { -        var partialSuccess = objectFactory.createPartialSuccessType(); -        partialSuccess.setAppDeliveryID(deliveryRequest.getMetaData().getAppDeliveryID()); +        var partialSuccess = objectFactory.createDeliveryAnswerType(); +        partialSuccess.setAppDeliveryID(appDeliveryId); -        var response = objectFactory.createDeliveryResponseType(); +        var response = objectFactory.createDeliveryRequestStatusType();          response.setPartialSuccess(partialSuccess); +        response.setSignature(null); +          return response;      } -    private DeliveryResponseType generateErrorResponse() { +    private DeliveryRequestStatusType generateErrorResponse(String appDeliveryId, String message) { -        var error = objectFactory.createErrorType(); -        error.setText("Error Occurred"); -        error.setCode(BigInteger.valueOf(500)); +        var error = objectFactory.createDeliveryRequestStatusTypeError(); +        error.setAppDeliveryID(appDeliveryId); -        var response = objectFactory.createDeliveryResponseType(); +        var info = objectFactory.createErrorInfoType(); +        info.setCode("500"); +        info.setText(message); +        error.setErrorInfo(info); + +        var response = objectFactory.createDeliveryRequestStatusType();          response.setError(error); +        response.setSignature(null);          return response;      } +    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); + +        var status = repository.getDeliveryRequestStatus(appDeliveryID); + +        if (status.isEmpty()) { +            throw new RuntimeException(format("Could not get a response for request with appDeliveryId = {}", appDeliveryID)); +        } + +        return status.get(); + +    } +  }
\ No newline at end of file diff --git a/src/main/java/at/gv/egiz/moazs/DeliveryRequestHandler.java b/src/main/java/at/gv/egiz/moazs/DeliveryRequestHandler.java deleted file mode 100644 index 0dc0a15..0000000 --- a/src/main/java/at/gv/egiz/moazs/DeliveryRequestHandler.java +++ /dev/null @@ -1,38 +0,0 @@ -package at.gv.egiz.moazs; - -import at.gv.e_government.reference.namespace.zustellung.mzs.app2mzs_.DeliveryRequestType; -import at.gv.e_government.reference.namespace.zustellung.mzs.app2mzs_.DeliveryResponseType; -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.Component; - -import java.util.function.Function; - -@Component -public class DeliveryRequestHandler implements Function<DeliveryRequestType, DeliveryResponseType> { - -    private static final Logger logger = LoggerFactory.getLogger(DeliveryRequestHandler.class); - -    @Autowired -    private DeliveryRepository repository; - -    /** -     * Handles the Delivery Request -     */ -    @Override -    public DeliveryResponseType apply(DeliveryRequestType deliveryRequest) { - -        var deliveryId = deliveryRequest.getMetaData().getAppDeliveryID(); -        logger.info(String.format("Received Request with AppDeliveryID = %s", deliveryId)); - -        //check if DR is complete - - -        //store delivery request -        repository.add(deliveryRequest); - -        return null; -    } -} diff --git a/src/main/java/at/gv/egiz/moazs/Mzs2AppClient.java b/src/main/java/at/gv/egiz/moazs/Mzs2AppClient.java index 01f2787..d0d7936 100644 --- a/src/main/java/at/gv/egiz/moazs/Mzs2AppClient.java +++ b/src/main/java/at/gv/egiz/moazs/Mzs2AppClient.java @@ -1,12 +1,12 @@  package at.gv.egiz.moazs; -import at.gv.e_government.reference.namespace.zustellung.mzs.app2mzs_.DeliveryResponseType; +import at.gv.e_government.reference.namespace.zustellung.msg.phase2._20181206_.DeliveryRequestStatusType;  import org.springframework.stereotype.Component;  @Component  public class Mzs2AppClient { -    public void sendNotification(DeliveryResponseType response) { +    public void sendNotification(DeliveryRequestStatusType status) {      } diff --git a/src/main/java/at/gv/egiz/moazs/pipeline/DeliveryPipeline.java b/src/main/java/at/gv/egiz/moazs/pipeline/DeliveryPipeline.java new file mode 100644 index 0000000..1d3edb8 --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/pipeline/DeliveryPipeline.java @@ -0,0 +1,12 @@ +package at.gv.egiz.moazs.pipeline; + + +public interface DeliveryPipeline { + +    /** +     * Gets request that is referred by appDeliveryId from cache, +     * @param appDeliveryId +     */ +    void processRequest(String appDeliveryId); + +} diff --git a/src/main/java/at/gv/egiz/moazs/pipeline/SameThreadDeliveryPipeline.java b/src/main/java/at/gv/egiz/moazs/pipeline/SameThreadDeliveryPipeline.java new file mode 100644 index 0000000..3652662 --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/pipeline/SameThreadDeliveryPipeline.java @@ -0,0 +1,49 @@ +package at.gv.egiz.moazs.pipeline; + + +import at.gv.e_government.reference.namespace.zustellung.msg.phase2._20181206_.DeliveryRequestStatusType; +import at.gv.e_government.reference.namespace.zustellung.msg.phase2._20181206_.ObjectFactory; +import at.gv.e_government.reference.namespace.zustellung.mzs.app2mzs_.DeliveryRequestType; +import at.gv.egiz.moazs.repository.DeliveryRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +import static java.text.MessageFormat.format; + +@Component +@Profile("!cluster") +public class SameThreadDeliveryPipeline implements DeliveryPipeline { + +    private final DeliveryRepository repository; + +    public SameThreadDeliveryPipeline(@Autowired DeliveryRepository repository) { +        this.repository = repository; +    } + +    @Override +    public void processRequest(String appDeliveryId) { + +        Optional<DeliveryRequestType> request = repository.getDeliveryRequest(appDeliveryId); +        if (request.isEmpty()) { +            throw new RuntimeException(format( +                    "Request with appDeliveryId = {} does not exist.", appDeliveryId)); +        } + +        //do some logic. + +        //store response to repository +        repository.add(generateBogusStatus(appDeliveryId)); +    } + +    private DeliveryRequestStatusType generateBogusStatus(String appDeliveryId) { +        final var factory = new ObjectFactory(); +        final var status = factory.createDeliveryRequestStatusType(); +        final var success = factory.createDeliveryRequestStatusTypeSuccess(); +        success.setAppDeliveryID(appDeliveryId); +        status.setSuccess(success); +        return status; +    } +} diff --git a/src/main/java/at/gv/egiz/moazs/repository/DeliveryRepository.java b/src/main/java/at/gv/egiz/moazs/repository/DeliveryRepository.java index d5766b6..f736160 100644 --- a/src/main/java/at/gv/egiz/moazs/repository/DeliveryRepository.java +++ b/src/main/java/at/gv/egiz/moazs/repository/DeliveryRepository.java @@ -1,5 +1,6 @@  package at.gv.egiz.moazs.repository; +import at.gv.e_government.reference.namespace.zustellung.msg.phase2._20181206_.DeliveryRequestStatusType;  import at.gv.e_government.reference.namespace.zustellung.mzs.app2mzs_.DeliveryRequestType;  import org.springframework.stereotype.Repository; @@ -12,4 +13,9 @@ public interface DeliveryRepository {      Optional<DeliveryRequestType> getDeliveryRequest(String appDeliveryID); +    void add(DeliveryRequestStatusType status); + +    Optional<DeliveryRequestStatusType> getDeliveryRequestStatus(String appDeliveryID); + +  } diff --git a/src/main/java/at/gv/egiz/moazs/repository/InMemoryDeliveryRepository.java b/src/main/java/at/gv/egiz/moazs/repository/InMemoryDeliveryRepository.java index e5486d7..5712c2d 100644 --- a/src/main/java/at/gv/egiz/moazs/repository/InMemoryDeliveryRepository.java +++ b/src/main/java/at/gv/egiz/moazs/repository/InMemoryDeliveryRepository.java @@ -1,5 +1,6 @@  package at.gv.egiz.moazs.repository; +import at.gv.e_government.reference.namespace.zustellung.msg.phase2._20181206_.DeliveryRequestStatusType;  import at.gv.e_government.reference.namespace.zustellung.mzs.app2mzs_.DeliveryRequestType;  import com.google.common.cache.Cache;  import com.google.common.cache.CacheBuilder; @@ -11,30 +12,45 @@ import org.springframework.stereotype.Repository;  import java.util.Optional;  import java.util.concurrent.TimeUnit; +import static at.gv.egiz.moazs.util.NullCoalesce.coalesce; +import static java.util.Optional.ofNullable; +  @Repository  @Profile("!cluster")  public class InMemoryDeliveryRepository implements DeliveryRepository {      private static final Logger logger = LoggerFactory.getLogger(InMemoryDeliveryRepository.class); -    private static final Cache<String, DeliveryRequestType> rep = CacheBuilder.newBuilder() +    private static final Cache<String, DeliveryRequestType> requestRepository = CacheBuilder.newBuilder()              .expireAfterWrite(30, TimeUnit.MINUTES)              .build(); -    public InMemoryDeliveryRepository() { -        logger.info("InMemoryDeliveryRepository()"); -    } +    private static final Cache<String, DeliveryRequestStatusType> statusRepository = CacheBuilder.newBuilder() +            .expireAfterWrite(30, TimeUnit.MINUTES) +            .build();      @Override      public void add(DeliveryRequestType request) { -        String key = request.getMetaData().getAppDeliveryID(); -        logger.info("Save DeliveryRequest with AppDeliveryId = {} to Cache.", key); -        rep.put(key, request); +        var key = request.getMetaData().getAppDeliveryID(); +        requestRepository.put(key, request);      }      @Override      public Optional<DeliveryRequestType> getDeliveryRequest(String appDeliveryID) { -        DeliveryRequestType deliveryRequestType = rep.getIfPresent(appDeliveryID); -        return Optional.ofNullable(deliveryRequestType); +        var deliveryRequestType = requestRepository.getIfPresent(appDeliveryID); +        return ofNullable(deliveryRequestType); +    } + +    @Override +    public void add(DeliveryRequestStatusType status) { +        var key = coalesce(status.getSuccess(), status.getPartialSuccess(), status.getError()) +                .get().getAppDeliveryID(); +        statusRepository.put(key, status); +    } + +    @Override +    public Optional<DeliveryRequestStatusType> getDeliveryRequestStatus(String appDeliveryID) { +        var deliveryRequestType = statusRepository.getIfPresent(appDeliveryID); +        return ofNullable(deliveryRequestType);      }  } diff --git a/src/main/java/at/gv/egiz/moazs/repository/RedisDeliveryRepository.java b/src/main/java/at/gv/egiz/moazs/repository/RedisDeliveryRepository.java index 4f39f31..cd02dac 100644 --- a/src/main/java/at/gv/egiz/moazs/repository/RedisDeliveryRepository.java +++ b/src/main/java/at/gv/egiz/moazs/repository/RedisDeliveryRepository.java @@ -1,5 +1,6 @@  package at.gv.egiz.moazs.repository; +import at.gv.e_government.reference.namespace.zustellung.msg.phase2._20181206_.DeliveryRequestStatusType;  import at.gv.e_government.reference.namespace.zustellung.mzs.app2mzs_.DeliveryRequestType;  import at.gv.e_government.reference.namespace.zustellung.mzs.app2mzs_.ObjectFactory;  import at.gv.egiz.moazs.Marshaller; @@ -59,4 +60,13 @@ public class RedisDeliveryRepository implements DeliveryRepository {          return Optional.of(request.getValue());      } +    @Override +    public void add(DeliveryRequestStatusType status) { +        throw new RuntimeException("Not Implemented Yet"); +    } + +    @Override +    public Optional<DeliveryRequestStatusType> getDeliveryRequestStatus(String appDeliveryID) { +        throw new RuntimeException("Not Implemented Yet"); +    }  } diff --git a/src/main/java/at/gv/egiz/moazs/util/NullCoalesce.java b/src/main/java/at/gv/egiz/moazs/util/NullCoalesce.java new file mode 100644 index 0000000..4377140 --- /dev/null +++ b/src/main/java/at/gv/egiz/moazs/util/NullCoalesce.java @@ -0,0 +1,33 @@ +package at.gv.egiz.moazs.util; + +import java.util.Optional; + +import static java.util.Optional.ofNullable; + +/** + * Helper function for coalescing nullables value without cluttering code with if-else cascades + * @author les2 + * @source https://stackoverflow.com/questions/2768054/how-to-get-the-first-non-null-value-in-java + */ +public class NullCoalesce { + +    /** +     * @return the first not-null value +     * @param a +     * @param b +     * @param <T> +     * @return a if a != null, otherwise b. +     */ +    public static <T> Optional<T> coalesce(T a, T b) { +        return a != null ? ofNullable(a) : ofNullable(b); +    } + +    public static <T> Optional<T> coalesce(T a, T b, T c) { +        return a != null ? ofNullable(a) : coalesce(b,c); +    } + +    public static <T> Optional<T> coalesce(T a, T b, T c, T d) { +        return a != null ? ofNullable(a) : coalesce(b,c,d); +    } + +} | 
