Search in sources :

Example 1 with Compensate

use of io.narayana.lra.annotation.Compensate in project narayana by jbosstm.

the class LraAnnotationProcessingExtension method processLraAnnotatedType.

<X> void processLraAnnotatedType(@Observes @WithAnnotations({ LRA.class }) ProcessAnnotatedType<X> classAnnotatedWithLra) {
    // All compulsory LRA annotations are available at the class
    Supplier<Stream<AnnotatedMethod<? super X>>> sup = () -> classAnnotatedWithLra.getAnnotatedType().getMethods().stream();
    Set<Class<? extends Annotation>> missing = new HashSet<>();
    if (!sup.get().anyMatch(m -> m.isAnnotationPresent(Compensate.class)))
        missing.add(Compensate.class);
    // gathering all LRA annotations in the class
    List<LRA> lraAnnotations = new ArrayList<>();
    LRA classLraAnnotation = classAnnotatedWithLra.getAnnotatedType().getAnnotation(LRA.class);
    if (classLraAnnotation != null)
        lraAnnotations.add(classLraAnnotation);
    List<LRA> methodlraAnnotations = sup.get().filter(m -> m.isAnnotationPresent(LRA.class)).map(m -> m.getAnnotation(LRA.class)).collect(Collectors.toList());
    lraAnnotations.addAll(methodlraAnnotations);
    // when LRA annotations expect no context then they are not part of the LRA and no handling
    // of the completion or compensation is needed
    boolean isNoLRAContext = lraAnnotations.stream().allMatch(lraAnn -> (lraAnn.value() == LRA.Type.NEVER || lraAnn.value() == LRA.Type.NOT_SUPPORTED));
    if (isNoLRAContext)
        return;
    // if any of the LRA annotations have set the join attribute to true (join to be true means
    // handling it as full LRA participant which needs to be completed, compensated...)
    // then have to process checks for compulsory LRA annotations
    boolean isJoin = lraAnnotations.stream().anyMatch(lraAnn -> lraAnn.join());
    final String classAnnotatedWithLraName = classAnnotatedWithLra.getAnnotatedType().getJavaClass().getName();
    if (!missing.isEmpty() && isJoin) {
        FailureCatalog.INSTANCE.add("Class " + classAnnotatedWithLraName + " uses " + LRA.class.getName() + " which requires methods handling LRA events. Missing annotations in the class: " + missing);
    }
    // Only one of each LRA annotation is placed in the class
    List<AnnotatedMethod<? super X>> methodsWithCompensate = sup.get().filter(m -> m.isAnnotationPresent(Compensate.class)).collect(Collectors.toList());
    List<AnnotatedMethod<? super X>> methodsWithComplete = sup.get().filter(m -> m.isAnnotationPresent(Complete.class)).collect(Collectors.toList());
    List<AnnotatedMethod<? super X>> methodsWithStatus = sup.get().filter(m -> m.isAnnotationPresent(Status.class)).collect(Collectors.toList());
    List<AnnotatedMethod<? super X>> methodsWithLeave = sup.get().filter(m -> m.isAnnotationPresent(Leave.class)).collect(Collectors.toList());
    List<AnnotatedMethod<? super X>> methodsWithForget = sup.get().filter(m -> m.isAnnotationPresent(Forget.class)).collect(Collectors.toList());
    BiFunction<Class<?>, List<AnnotatedMethod<? super X>>, String> errorMsg = (clazz, methods) -> String.format("There are used multiple annotations '%s' in the class '%s' on methods %s. Only one per the class is expected.", clazz.getName(), classAnnotatedWithLraName, methods.stream().map(a -> a.getJavaMember().getName()).collect(Collectors.toList()));
    if (methodsWithCompensate.size() > 1) {
        FailureCatalog.INSTANCE.add(errorMsg.apply(Compensate.class, methodsWithCompensate));
    }
    if (methodsWithComplete.size() > 1) {
        FailureCatalog.INSTANCE.add(errorMsg.apply(Complete.class, methodsWithComplete));
    }
    if (methodsWithStatus.size() > 1) {
        FailureCatalog.INSTANCE.add(errorMsg.apply(Status.class, methodsWithStatus));
    }
    if (methodsWithLeave.size() > 1) {
        FailureCatalog.INSTANCE.add(errorMsg.apply(Leave.class, methodsWithLeave));
    }
    if (methodsWithForget.size() > 1) {
        FailureCatalog.INSTANCE.add(errorMsg.apply(Forget.class, methodsWithForget));
    }
    if (methodsWithCompensate.size() > 0) {
        // Each method annotated with LRA-style annotations contain all necessary REST annotations
        // @Compensate - requires @Path and @PUT
        final AnnotatedMethod<? super X> methodWithCompensate = methodsWithCompensate.get(0);
        Function<Class<?>, String> getCompensateMissingErrMsg = (wrongAnnotation) -> getMissingAnnotationError(methodWithCompensate, classAnnotatedWithLra, Compensate.class, wrongAnnotation);
        boolean isCompensateContainsPathAnnotation = methodWithCompensate.getAnnotations().stream().anyMatch(a -> a.annotationType().equals(Path.class));
        if (!isCompensateContainsPathAnnotation) {
            FailureCatalog.INSTANCE.add(getCompensateMissingErrMsg.apply(Path.class));
        }
        boolean isCompensateContainsPutAnnotation = methodWithCompensate.getAnnotations().stream().anyMatch(a -> a.annotationType().equals(PUT.class));
        if (!isCompensateContainsPutAnnotation) {
            FailureCatalog.INSTANCE.add(getCompensateMissingErrMsg.apply(PUT.class));
        }
        boolean isCompensateParametersContainsSuspended = methodWithCompensate.getParameters().stream().flatMap(p -> p.getAnnotations().stream()).anyMatch(a -> a.annotationType().equals(Suspended.class));
        if (isCompensateParametersContainsSuspended) {
            if (methodsWithStatus.size() == 0 || methodsWithForget.size() == 0) {
                FailureCatalog.INSTANCE.add(getMissingAnnotationsForAsynchHandling(methodWithCompensate, classAnnotatedWithLra, Compensate.class));
            }
        }
    }
    if (methodsWithComplete.size() > 0) {
        // @Complete - requires @Path and @PUT
        final AnnotatedMethod<? super X> methodWithComplete = methodsWithComplete.get(0);
        Function<Class<?>, String> getCompleteMissingErrMsg = (wrongAnnotation) -> getMissingAnnotationError(methodWithComplete, classAnnotatedWithLra, Complete.class, wrongAnnotation);
        boolean isCompleteContainsPathAnnotation = methodWithComplete.getAnnotations().stream().anyMatch(a -> a.annotationType().equals(Path.class));
        if (!isCompleteContainsPathAnnotation) {
            FailureCatalog.INSTANCE.add(getCompleteMissingErrMsg.apply(Path.class));
        }
        boolean isCompleteContainsPutAnnotation = methodWithComplete.getAnnotations().stream().anyMatch(a -> a.annotationType().equals(PUT.class));
        if (!isCompleteContainsPutAnnotation) {
            FailureCatalog.INSTANCE.add(getCompleteMissingErrMsg.apply(PUT.class));
        }
        boolean isCompleteParametersContainsSuspended = methodWithComplete.getParameters().stream().flatMap(p -> p.getAnnotations().stream()).anyMatch(a -> a.annotationType().equals(Suspended.class));
        if (isCompleteParametersContainsSuspended) {
            if (methodsWithStatus.size() == 0 || methodsWithForget.size() == 0) {
                FailureCatalog.INSTANCE.add(getMissingAnnotationsForAsynchHandling(methodWithComplete, classAnnotatedWithLra, Complete.class));
            }
        }
    }
    if (methodsWithStatus.size() > 0) {
        // @Status - requires @Path and @GET
        final AnnotatedMethod<? super X> methodWithStatus = methodsWithStatus.get(0);
        Function<Class<?>, String> getStatusMissingErrMsg = (wrongAnnotation) -> getMissingAnnotationError(methodWithStatus, classAnnotatedWithLra, Status.class, wrongAnnotation);
        boolean isStatusContainsPathAnnotation = methodWithStatus.getAnnotations().stream().anyMatch(a -> a.annotationType().equals(Path.class));
        if (!isStatusContainsPathAnnotation) {
            FailureCatalog.INSTANCE.add(getStatusMissingErrMsg.apply(Path.class));
        }
        boolean isStatusContainsGetAnnotation = methodWithStatus.getAnnotations().stream().anyMatch(a -> a.annotationType().equals(GET.class));
        if (!isStatusContainsGetAnnotation) {
            FailureCatalog.INSTANCE.add(getStatusMissingErrMsg.apply(GET.class));
        }
    }
    if (methodsWithLeave.size() > 0) {
        // @Leave - requires @PUT
        final AnnotatedMethod<? super X> methodWithLeave = methodsWithLeave.get(0);
        boolean isLeaveContainsPutAnnotation = methodWithLeave.getAnnotations().stream().anyMatch(a -> a.annotationType().equals(PUT.class));
        if (!isLeaveContainsPutAnnotation) {
            FailureCatalog.INSTANCE.add(getMissingAnnotationError(methodWithLeave, classAnnotatedWithLra, Leave.class, PUT.class));
        }
    }
    if (methodsWithForget.size() > 0) {
        // @Forget - requires @DELETE
        final AnnotatedMethod<? super X> methodWithForget = methodsWithForget.get(0);
        boolean isForgetContainsPutAnnotation = methodWithForget.getAnnotations().stream().anyMatch(a -> a.annotationType().equals(DELETE.class));
        if (!isForgetContainsPutAnnotation) {
            FailureCatalog.INSTANCE.add(getMissingAnnotationError(methodWithForget, classAnnotatedWithLra, Forget.class, DELETE.class));
        }
    }
}
Also used : GET(javax.ws.rs.GET) BiFunction(java.util.function.BiFunction) Path(javax.ws.rs.Path) Complete(io.narayana.lra.annotation.Complete) Function(java.util.function.Function) Supplier(java.util.function.Supplier) Compensate(io.narayana.lra.annotation.Compensate) Forget(io.narayana.lra.annotation.Forget) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) Leave(io.narayana.lra.annotation.Leave) Observes(javax.enterprise.event.Observes) Status(io.narayana.lra.annotation.Status) LRA(io.narayana.lra.annotation.LRA) DELETE(javax.ws.rs.DELETE) FailureCatalog(io.narayana.lra.checker.FailureCatalog) Extension(javax.enterprise.inject.spi.Extension) ProcessAnnotatedType(javax.enterprise.inject.spi.ProcessAnnotatedType) Set(java.util.Set) WithAnnotations(javax.enterprise.inject.spi.WithAnnotations) Collectors(java.util.stream.Collectors) Suspended(javax.ws.rs.container.Suspended) List(java.util.List) Stream(java.util.stream.Stream) Annotation(java.lang.annotation.Annotation) PUT(javax.ws.rs.PUT) AnnotatedMethod(javax.enterprise.inject.spi.AnnotatedMethod) AnnotatedMethod(javax.enterprise.inject.spi.AnnotatedMethod) Complete(io.narayana.lra.annotation.Complete) ArrayList(java.util.ArrayList) Leave(io.narayana.lra.annotation.Leave) Forget(io.narayana.lra.annotation.Forget) Compensate(io.narayana.lra.annotation.Compensate) DELETE(javax.ws.rs.DELETE) Stream(java.util.stream.Stream) ArrayList(java.util.ArrayList) List(java.util.List) Suspended(javax.ws.rs.container.Suspended) HashSet(java.util.HashSet) Status(io.narayana.lra.annotation.Status) Path(javax.ws.rs.Path) Annotation(java.lang.annotation.Annotation) PUT(javax.ws.rs.PUT) GET(javax.ws.rs.GET) LRA(io.narayana.lra.annotation.LRA)

Example 2 with Compensate

use of io.narayana.lra.annotation.Compensate in project narayana by jbosstm.

the class ActivityController method compensateWork.

@PUT
@Path("/compensate")
@Produces(MediaType.APPLICATION_JSON)
@Compensate
public Response compensateWork(@HeaderParam(LRA_HTTP_HEADER) String lraId, String userData) throws NotFoundException {
    compensatedCount.incrementAndGet();
    assert lraId != null;
    String txId = NarayanaLRAClient.getLRAId(lraId);
    Activity activity = activityService.getActivity(txId);
    activity.setEndData(userData);
    if (activity.getAndDecrementAcceptCount() > 0) {
        activity.status = CompensatorStatus.Compensating;
        activity.statusUrl = String.format("%s/%s/%s/status", context.getBaseUri(), ACTIVITIES_PATH, txId);
        return Response.accepted().location(URI.create(activity.statusUrl)).build();
    }
    activity.status = CompensatorStatus.Compensated;
    activity.statusUrl = String.format("%s/%s/activity/compensated", context.getBaseUri(), txId);
    System.out.printf("ActivityController compensating %s%n", txId);
    return Response.ok(activity.statusUrl).build();
}
Also used : Activity(io.narayana.lra.participant.model.Activity) Path(javax.ws.rs.Path) Produces(javax.ws.rs.Produces) Compensate(io.narayana.lra.annotation.Compensate) PUT(javax.ws.rs.PUT)

Aggregations

Compensate (io.narayana.lra.annotation.Compensate)2 PUT (javax.ws.rs.PUT)2 Path (javax.ws.rs.Path)2 Complete (io.narayana.lra.annotation.Complete)1 Forget (io.narayana.lra.annotation.Forget)1 LRA (io.narayana.lra.annotation.LRA)1 Leave (io.narayana.lra.annotation.Leave)1 Status (io.narayana.lra.annotation.Status)1 FailureCatalog (io.narayana.lra.checker.FailureCatalog)1 Activity (io.narayana.lra.participant.model.Activity)1 Annotation (java.lang.annotation.Annotation)1 ArrayList (java.util.ArrayList)1 HashSet (java.util.HashSet)1 List (java.util.List)1 Set (java.util.Set)1 BiFunction (java.util.function.BiFunction)1 Function (java.util.function.Function)1 Supplier (java.util.function.Supplier)1 Collectors (java.util.stream.Collectors)1 Stream (java.util.stream.Stream)1