kogito-quarkus-examples/process-usertasks-custom-lifecycle-quarkus/src/main/java/org/acme/travels/usertasks/CustomUserTaskLifeCycle.java [45:217]:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
public class CustomUserTaskLifeCycle implements UserTaskLifeCycle {
    public static final String WORKFLOW_ENGINE_USER = "WORKFLOW_ENGINE_USER";

    public static final String PARAMETER_USER = "USER";
    public static final String PARAMETER_NOTIFY = "NOTIFY";

    public static final String ACTIVATE = "activate";
    public static final String START = "start";
    public static final String CLAIM = "claim";
    public static final String RELEASE = "release";
    public static final String COMPLETE = "complete";
    public static final String SKIP = "skip";
    public static final String FAIL = "fail";

    public static final UserTaskState INACTIVE = UserTaskState.initalized();
    public static final UserTaskState ACTIVE = UserTaskState.of("Active");
    public static final UserTaskState STARTED = UserTaskState.of("Started");
    public static final UserTaskState RESERVED = UserTaskState.of("Reserved");
    public static final UserTaskState COMPLETED = UserTaskState.of("Completed", TerminationType.COMPLETED);
    public static final UserTaskState OBSOLETE = UserTaskState.of("Obsolete", TerminationType.OBSOLETE);

    private final UserTaskTransition T_NEW_ACTIVE = new DefaultUserTransition(ACTIVATE, INACTIVE, ACTIVE, this::activate);
    private final UserTaskTransition T_ACTIVE_START = new DefaultUserTransition(START, ACTIVE, STARTED, this::start);
    private final UserTaskTransition T_START_RESERVED = new DefaultUserTransition(CLAIM, STARTED, RESERVED, this::claim);
    private final UserTaskTransition T_RESERVED_COMPLETED = new DefaultUserTransition(COMPLETE, RESERVED, COMPLETED, this::complete);

    private final UserTaskTransition T_ACTIVE_SKIPPED = new DefaultUserTransition(SKIP, ACTIVE, OBSOLETE, this::skip);
    private final UserTaskTransition T_STARTED_SKIPPED = new DefaultUserTransition(SKIP, STARTED, OBSOLETE, this::skip);
    private final UserTaskTransition T_RESERVED_SKIPPED = new DefaultUserTransition(SKIP, RESERVED, OBSOLETE, this::skip);

    private final UserTaskTransition T_RESERVED_ACTIVE = new DefaultUserTransition(RELEASE, RESERVED, ACTIVE, this::release);

    private List<UserTaskTransition> transitions;

    public CustomUserTaskLifeCycle() {
        transitions = List.of(
                T_NEW_ACTIVE,
                T_ACTIVE_START,
                T_START_RESERVED,
                T_ACTIVE_SKIPPED,
                T_STARTED_SKIPPED,
                T_RESERVED_ACTIVE,
                T_RESERVED_COMPLETED,
                T_RESERVED_SKIPPED);
    }

    @Override
    public List<UserTaskTransition> allowedTransitions(UserTaskInstance userTaskInstance, IdentityProvider identity) {
        checkPermission(userTaskInstance, identity);
        return transitions.stream().filter(t -> t.source().equals(userTaskInstance.getStatus())).toList();
    }

    @Override
    public Optional<UserTaskTransitionToken> transition(UserTaskInstance userTaskInstance, UserTaskTransitionToken userTaskTransitionToken, IdentityProvider identityProvider) {
        checkPermission(userTaskInstance, identityProvider);
        UserTaskTransition transition = transitions.stream()
                .filter(t -> t.source().equals(userTaskInstance.getStatus()) && t.id().equals(userTaskTransitionToken.transitionId()))
                .findFirst()
                .orElseThrow(() -> new UserTaskTransitionException("Invalid transition from " + userTaskInstance.getStatus()));
        return transition.executor().execute(userTaskInstance, userTaskTransitionToken, identityProvider);
    }

    @Override
    public UserTaskTransitionToken newCompleteTransitionToken(UserTaskInstance userTaskInstance, Map<String, Object> data) {
        return newTransitionToken(COMPLETE, userTaskInstance.getStatus(), data);
    }

    @Override
    public UserTaskTransitionToken newAbortTransitionToken(UserTaskInstance userTaskInstance, Map<String, Object> data) {
        return newTransitionToken(SKIP, userTaskInstance.getStatus(), data);
    }

    @Override
    public UserTaskTransitionToken newTransitionToken(String transitionId, UserTaskInstance userTaskInstance, Map<String, Object> data) {
        return newTransitionToken(transitionId, userTaskInstance.getStatus(), data);
    }

    public UserTaskTransitionToken newTransitionToken(String transitionId, UserTaskState state, Map<String, Object> data) {
        UserTaskTransition transition = transitions.stream().filter(e -> e.source().equals(state) && e.id().equals(transitionId)).findAny()
                .orElseThrow(() -> new RuntimeException("Invalid transition " + transitionId + " from " + state));
        return new DefaultUserTaskTransitionToken(transition.id(), transition.source(), transition.target(), data);
    }

    public Optional<UserTaskTransitionToken> activate(UserTaskInstance userTaskInstance, UserTaskTransitionToken token, IdentityProvider identityProvider) {
        return Optional.empty();
    }

    public Optional<UserTaskTransitionToken> start(UserTaskInstance userTaskInstance, UserTaskTransitionToken token, IdentityProvider identityProvider) {
        String user = assignStrategy(userTaskInstance, identityProvider);
        if (user != null) {
            return Optional.of(newTransitionToken(CLAIM, STARTED, Map.of(PARAMETER_USER, user)));
        }
        return Optional.empty();
    }

    public Optional<UserTaskTransitionToken> claim(UserTaskInstance userTaskInstance, UserTaskTransitionToken token, IdentityProvider identityProvider) {
        if (userTaskInstance instanceof DefaultUserTaskInstance defaultUserTaskInstance) {
            if (token.data().containsKey(PARAMETER_USER)) {
                defaultUserTaskInstance.setActualOwner((String) token.data().get(PARAMETER_USER));
            } else {
                defaultUserTaskInstance.setActualOwner(identityProvider.getName());
            }
        }
        return Optional.empty();
    }

    public Optional<UserTaskTransitionToken> release(UserTaskInstance userTaskInstance, UserTaskTransitionToken token, IdentityProvider identityProvider) {
        if (userTaskInstance instanceof DefaultUserTaskInstance defaultUserTaskInstance) {
            defaultUserTaskInstance.setActualOwner(null);
        }
        return Optional.empty();
    }

    public Optional<UserTaskTransitionToken> complete(UserTaskInstance userTaskInstance, UserTaskTransitionToken token, IdentityProvider identityProvider) {
        token.data().forEach(userTaskInstance::setOutput);
        return Optional.empty();
    }

    public Optional<UserTaskTransitionToken> skip(UserTaskInstance userTaskInstance, UserTaskTransitionToken token, IdentityProvider identityProvider) {
        if (token.data().containsKey(PARAMETER_NOTIFY)) {
            userTaskInstance.getMetadata().put(PARAMETER_NOTIFY, token.data().get(PARAMETER_NOTIFY));
        }
        if (userTaskInstance instanceof DefaultUserTaskInstance defaultUserTaskInstance) {
            defaultUserTaskInstance.setActualOwner(identityProvider.getName());
        }
        return Optional.empty();
    }

    private String assignStrategy(UserTaskInstance userTaskInstance, IdentityProvider identityProvider) {
        UserTaskAssignmentStrategy assignmentStrategy = userTaskInstance.getUserTask().getAssignmentStrategy();
        return assignmentStrategy.computeAssignment(userTaskInstance, identityProvider).orElse(null);
    }

    private void checkPermission(UserTaskInstance userTaskInstance, IdentityProvider identityProvider) {
        String user = identityProvider.getName();
        Collection<String> roles = identityProvider.getRoles();

        if (WORKFLOW_ENGINE_USER.equals(user)) {
            return;
        }

        // first we check admins
        Set<String> adminUsers = userTaskInstance.getAdminUsers();
        if (adminUsers.contains(user)) {
            return;
        }

        Set<String> userAdminGroups = new HashSet<>(userTaskInstance.getAdminGroups());
        userAdminGroups.retainAll(roles);
        if (!userAdminGroups.isEmpty()) {
            return;
        }

        if (userTaskInstance.getActualOwner() != null && userTaskInstance.getActualOwner().equals(user)) {
            return;
        }

        if (List.of(INACTIVE, ACTIVE, STARTED).contains(userTaskInstance.getStatus())) {
            // there is no user
            Set<String> users = new HashSet<>(userTaskInstance.getPotentialUsers());
            users.removeAll(userTaskInstance.getExcludedUsers());
            if (users.contains(identityProvider.getName())) {
                return;
            }

            Set<String> userPotGroups = new HashSet<>(userTaskInstance.getPotentialGroups());
            userPotGroups.retainAll(roles);
            if (!userPotGroups.isEmpty()) {
                return;
            }
        }

        throw new NotAuthorizedException("user " + user + " with roles " + roles + " not autorized to perform an operation on user task " + userTaskInstance.getId());
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



kogito-springboot-examples/process-usertasks-custom-lifecycle-springboot/src/main/java/org/acme/travels/usertasks/CustomUserTaskLifeCycle.java [44:216]:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
public class CustomUserTaskLifeCycle implements UserTaskLifeCycle {
    public static final String WORKFLOW_ENGINE_USER = "WORKFLOW_ENGINE_USER";

    public static final String PARAMETER_USER = "USER";
    public static final String PARAMETER_NOTIFY = "NOTIFY";

    public static final String ACTIVATE = "activate";
    public static final String START = "start";
    public static final String CLAIM = "claim";
    public static final String RELEASE = "release";
    public static final String COMPLETE = "complete";
    public static final String SKIP = "skip";
    public static final String FAIL = "fail";

    public static final UserTaskState INACTIVE = UserTaskState.initalized();
    public static final UserTaskState ACTIVE = UserTaskState.of("Active");
    public static final UserTaskState STARTED = UserTaskState.of("Started");
    public static final UserTaskState RESERVED = UserTaskState.of("Reserved");
    public static final UserTaskState COMPLETED = UserTaskState.of("Completed", TerminationType.COMPLETED);
    public static final UserTaskState OBSOLETE = UserTaskState.of("Obsolete", TerminationType.OBSOLETE);

    private final UserTaskTransition T_NEW_ACTIVE = new DefaultUserTransition(ACTIVATE, INACTIVE, ACTIVE, this::activate);
    private final UserTaskTransition T_ACTIVE_START = new DefaultUserTransition(START, ACTIVE, STARTED, this::start);
    private final UserTaskTransition T_START_RESERVED = new DefaultUserTransition(CLAIM, STARTED, RESERVED, this::claim);
    private final UserTaskTransition T_RESERVED_COMPLETED = new DefaultUserTransition(COMPLETE, RESERVED, COMPLETED, this::complete);

    private final UserTaskTransition T_ACTIVE_SKIPPED = new DefaultUserTransition(SKIP, ACTIVE, OBSOLETE, this::skip);
    private final UserTaskTransition T_STARTED_SKIPPED = new DefaultUserTransition(SKIP, STARTED, OBSOLETE, this::skip);
    private final UserTaskTransition T_RESERVED_SKIPPED = new DefaultUserTransition(SKIP, RESERVED, OBSOLETE, this::skip);

    private final UserTaskTransition T_RESERVED_ACTIVE = new DefaultUserTransition(RELEASE, RESERVED, ACTIVE, this::release);

    private List<UserTaskTransition> transitions;

    public CustomUserTaskLifeCycle() {
        transitions = List.of(
                T_NEW_ACTIVE,
                T_ACTIVE_START,
                T_START_RESERVED,
                T_ACTIVE_SKIPPED,
                T_STARTED_SKIPPED,
                T_RESERVED_ACTIVE,
                T_RESERVED_COMPLETED,
                T_RESERVED_SKIPPED);
    }

    @Override
    public List<UserTaskTransition> allowedTransitions(UserTaskInstance userTaskInstance, IdentityProvider identity) {
        checkPermission(userTaskInstance, identity);
        return transitions.stream().filter(t -> t.source().equals(userTaskInstance.getStatus())).toList();
    }

    @Override
    public Optional<UserTaskTransitionToken> transition(UserTaskInstance userTaskInstance, UserTaskTransitionToken userTaskTransitionToken, IdentityProvider identityProvider) {
        checkPermission(userTaskInstance, identityProvider);
        UserTaskTransition transition = transitions.stream()
                .filter(t -> t.source().equals(userTaskInstance.getStatus()) && t.id().equals(userTaskTransitionToken.transitionId()))
                .findFirst()
                .orElseThrow(() -> new UserTaskTransitionException("Invalid transition from " + userTaskInstance.getStatus()));
        return transition.executor().execute(userTaskInstance, userTaskTransitionToken, identityProvider);
    }

    @Override
    public UserTaskTransitionToken newCompleteTransitionToken(UserTaskInstance userTaskInstance, Map<String, Object> data) {
        return newTransitionToken(COMPLETE, userTaskInstance.getStatus(), data);
    }

    @Override
    public UserTaskTransitionToken newAbortTransitionToken(UserTaskInstance userTaskInstance, Map<String, Object> data) {
        return newTransitionToken(SKIP, userTaskInstance.getStatus(), data);
    }

    @Override
    public UserTaskTransitionToken newTransitionToken(String transitionId, UserTaskInstance userTaskInstance, Map<String, Object> data) {
        return newTransitionToken(transitionId, userTaskInstance.getStatus(), data);
    }

    public UserTaskTransitionToken newTransitionToken(String transitionId, UserTaskState state, Map<String, Object> data) {
        UserTaskTransition transition = transitions.stream().filter(e -> e.source().equals(state) && e.id().equals(transitionId)).findAny()
                .orElseThrow(() -> new RuntimeException("Invalid transition " + transitionId + " from " + state));
        return new DefaultUserTaskTransitionToken(transition.id(), transition.source(), transition.target(), data);
    }

    public Optional<UserTaskTransitionToken> activate(UserTaskInstance userTaskInstance, UserTaskTransitionToken token, IdentityProvider identityProvider) {
        return Optional.empty();
    }

    public Optional<UserTaskTransitionToken> start(UserTaskInstance userTaskInstance, UserTaskTransitionToken token, IdentityProvider identityProvider) {
        String user = assignStrategy(userTaskInstance, identityProvider);
        if (user != null) {
            return Optional.of(newTransitionToken(CLAIM, STARTED, Map.of(PARAMETER_USER, user)));
        }
        return Optional.empty();
    }

    public Optional<UserTaskTransitionToken> claim(UserTaskInstance userTaskInstance, UserTaskTransitionToken token, IdentityProvider identityProvider) {
        if (userTaskInstance instanceof DefaultUserTaskInstance defaultUserTaskInstance) {
            if (token.data().containsKey(PARAMETER_USER)) {
                defaultUserTaskInstance.setActualOwner((String) token.data().get(PARAMETER_USER));
            } else {
                defaultUserTaskInstance.setActualOwner(identityProvider.getName());
            }
        }
        return Optional.empty();
    }

    public Optional<UserTaskTransitionToken> release(UserTaskInstance userTaskInstance, UserTaskTransitionToken token, IdentityProvider identityProvider) {
        if (userTaskInstance instanceof DefaultUserTaskInstance defaultUserTaskInstance) {
            defaultUserTaskInstance.setActualOwner(null);
        }
        return Optional.empty();
    }

    public Optional<UserTaskTransitionToken> complete(UserTaskInstance userTaskInstance, UserTaskTransitionToken token, IdentityProvider identityProvider) {
        token.data().forEach(userTaskInstance::setOutput);
        return Optional.empty();
    }

    public Optional<UserTaskTransitionToken> skip(UserTaskInstance userTaskInstance, UserTaskTransitionToken token, IdentityProvider identityProvider) {
        if (token.data().containsKey(PARAMETER_NOTIFY)) {
            userTaskInstance.getMetadata().put(PARAMETER_NOTIFY, token.data().get(PARAMETER_NOTIFY));
        }
        if (userTaskInstance instanceof DefaultUserTaskInstance defaultUserTaskInstance) {
            defaultUserTaskInstance.setActualOwner(identityProvider.getName());
        }
        return Optional.empty();
    }

    private String assignStrategy(UserTaskInstance userTaskInstance, IdentityProvider identityProvider) {
        UserTaskAssignmentStrategy assignmentStrategy = userTaskInstance.getUserTask().getAssignmentStrategy();
        return assignmentStrategy.computeAssignment(userTaskInstance, identityProvider).orElse(null);
    }

    private void checkPermission(UserTaskInstance userTaskInstance, IdentityProvider identityProvider) {
        String user = identityProvider.getName();
        Collection<String> roles = identityProvider.getRoles();

        if (WORKFLOW_ENGINE_USER.equals(user)) {
            return;
        }

        // first we check admins
        Set<String> adminUsers = userTaskInstance.getAdminUsers();
        if (adminUsers.contains(user)) {
            return;
        }

        Set<String> userAdminGroups = new HashSet<>(userTaskInstance.getAdminGroups());
        userAdminGroups.retainAll(roles);
        if (!userAdminGroups.isEmpty()) {
            return;
        }

        if (userTaskInstance.getActualOwner() != null && userTaskInstance.getActualOwner().equals(user)) {
            return;
        }

        if (List.of(INACTIVE, ACTIVE, STARTED).contains(userTaskInstance.getStatus())) {
            // there is no user
            Set<String> users = new HashSet<>(userTaskInstance.getPotentialUsers());
            users.removeAll(userTaskInstance.getExcludedUsers());
            if (users.contains(identityProvider.getName())) {
                return;
            }

            Set<String> userPotGroups = new HashSet<>(userTaskInstance.getPotentialGroups());
            userPotGroups.retainAll(roles);
            if (!userPotGroups.isEmpty()) {
                return;
            }
        }

        throw new NotAuthorizedException("user " + user + " with roles " + roles + " not autorized to perform an operation on user task " + userTaskInstance.getId());
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



