All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.netgrif.application.engine.workflow.service.TaskService Maven / Gradle / Ivy

Go to download

System provides workflow management functions including user, role and data management.

There is a newer version: 6.3.3
Show newest version
package com.netgrif.application.engine.workflow.service;

import com.google.common.collect.Ordering;
import com.netgrif.application.engine.auth.domain.IUser;
import com.netgrif.application.engine.auth.domain.LoggedUser;
import com.netgrif.application.engine.auth.service.interfaces.IUserService;
import com.netgrif.application.engine.elastic.service.interfaces.IElasticTaskMappingService;
import com.netgrif.application.engine.elastic.service.interfaces.IElasticTaskService;
import com.netgrif.application.engine.history.domain.taskevents.AssignTaskEventLog;
import com.netgrif.application.engine.history.domain.taskevents.CancelTaskEventLog;
import com.netgrif.application.engine.history.domain.taskevents.DelegateTaskEventLog;
import com.netgrif.application.engine.history.domain.taskevents.FinishTaskEventLog;
import com.netgrif.application.engine.history.service.IHistoryService;
import com.netgrif.application.engine.petrinet.domain.*;
import com.netgrif.application.engine.petrinet.domain.arcs.Arc;
import com.netgrif.application.engine.petrinet.domain.arcs.ArcOrderComparator;
import com.netgrif.application.engine.petrinet.domain.arcs.ResetArc;
import com.netgrif.application.engine.petrinet.domain.dataset.Field;
import com.netgrif.application.engine.petrinet.domain.dataset.UserFieldValue;
import com.netgrif.application.engine.petrinet.domain.dataset.UserListFieldValue;
import com.netgrif.application.engine.petrinet.domain.events.EventPhase;
import com.netgrif.application.engine.petrinet.domain.events.EventType;
import com.netgrif.application.engine.petrinet.domain.roles.ProcessRole;
import com.netgrif.application.engine.petrinet.domain.throwable.TransitionNotExecutableException;
import com.netgrif.application.engine.petrinet.service.interfaces.IProcessRoleService;
import com.netgrif.application.engine.rules.domain.facts.TransitionEventFact;
import com.netgrif.application.engine.rules.service.interfaces.IRuleEngine;
import com.netgrif.application.engine.utils.DateUtils;
import com.netgrif.application.engine.utils.FullPageRequest;
import com.netgrif.application.engine.validation.service.interfaces.IValidationService;
import com.netgrif.application.engine.workflow.domain.Case;
import com.netgrif.application.engine.workflow.domain.Task;
import com.netgrif.application.engine.workflow.domain.TaskNotFoundException;
import com.netgrif.application.engine.workflow.domain.TaskPair;
import com.netgrif.application.engine.workflow.domain.eventoutcomes.EventOutcome;
import com.netgrif.application.engine.workflow.domain.eventoutcomes.dataoutcomes.SetDataEventOutcome;
import com.netgrif.application.engine.workflow.domain.eventoutcomes.taskoutcomes.*;
import com.netgrif.application.engine.workflow.domain.repositories.TaskRepository;
import com.netgrif.application.engine.workflow.domain.triggers.AutoTrigger;
import com.netgrif.application.engine.workflow.domain.triggers.TimeTrigger;
import com.netgrif.application.engine.workflow.domain.triggers.Trigger;
import com.netgrif.application.engine.workflow.service.interfaces.IDataService;
import com.netgrif.application.engine.workflow.service.interfaces.IEventService;
import com.netgrif.application.engine.workflow.service.interfaces.ITaskService;
import com.netgrif.application.engine.workflow.service.interfaces.IWorkflowService;
import com.netgrif.application.engine.workflow.web.requestbodies.TaskSearchRequest;
import com.netgrif.application.engine.workflow.web.responsebodies.TaskReference;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Service
public class TaskService implements ITaskService {

    @Autowired
    protected ApplicationEventPublisher publisher;

    @Autowired
    protected TaskRepository taskRepository;

    @Autowired
    protected IUserService userService;

    @Autowired
    protected MongoTemplate mongoTemplate;

    @Autowired
    protected TaskSearchService searchService;

    @Autowired
    @Qualifier("taskScheduler")
    protected TaskScheduler scheduler;

    @Autowired
    protected IWorkflowService workflowService;

    @Autowired
    protected IDataService dataService;

    @Autowired
    protected IProcessRoleService processRoleService;

    @Autowired
    protected IElasticTaskMappingService taskMappingService;

    @Autowired
    protected IEventService eventService;

    protected IElasticTaskService elasticTaskService;

    @Autowired
    protected IHistoryService historyService;

    @Autowired
    protected IValidationService validation;

    @Lazy
    @Autowired
    public void setElasticTaskService(IElasticTaskService elasticTaskService) {
        this.elasticTaskService = elasticTaskService;
    }

    @Autowired
    private IRuleEngine ruleEngine;

    @Override
    public List assignTasks(List tasks, IUser user) throws TransitionNotExecutableException {
        return assignTasks(tasks, user, new HashMap<>());
    }

    @Override
    public List assignTasks(List tasks, IUser user, Map params) throws TransitionNotExecutableException {
        List outcomes = new ArrayList<>();
        for (Task task : tasks) {
            outcomes.add(assignTask(task, user, params));
        }
        return outcomes;
    }

    @Override
    public AssignTaskEventOutcome assignTask(LoggedUser loggedUser, String taskId) throws TransitionNotExecutableException {
        return assignTask(loggedUser, taskId, new HashMap<>());
    }

    @Override
    public AssignTaskEventOutcome assignTask(LoggedUser loggedUser, String taskId, Map params) throws TransitionNotExecutableException {
        Optional taskOptional = taskRepository.findById(taskId);
        if (taskOptional.isEmpty()) {
            throw new TaskNotFoundException("Could not find task with id [" + taskId + "]");
        }

        IUser user = getUserFromLoggedUser(loggedUser);
        return assignTask(taskOptional.get(), user, params);
    }

    @Override
    public AssignTaskEventOutcome assignTask(String taskId) throws TransitionNotExecutableException {
        return assignTask(taskId, new HashMap<>());
    }

    @Override
    public AssignTaskEventOutcome assignTask(String taskId, Map params) throws TransitionNotExecutableException {
        LoggedUser user = userService.getLoggedOrSystem().transformToLoggedUser();
        return assignTask(user, taskId, params);
    }

    @Override
    public AssignTaskEventOutcome assignTask(Task task, IUser user) throws TransitionNotExecutableException {
        return assignTask(task, user, new HashMap<>());
    }

    @Override
    public AssignTaskEventOutcome assignTask(Task task, IUser user, Map params) throws TransitionNotExecutableException {
        Case useCase = workflowService.findOne(task.getCaseId());
        Transition transition = useCase.getPetriNet().getTransition(task.getTransitionId());
        List outcomes = new ArrayList<>(eventService.runActions(transition.getPreAssignActions(), useCase, task, transition, params));
        task = findOne(task.getStringId());
        useCase = evaluateRules(useCase.getStringId(), task, EventType.ASSIGN, EventPhase.PRE);
        useCase = assignTaskToUser(user, task, useCase.getStringId());
        historyService.save(new AssignTaskEventLog(task, useCase, EventPhase.PRE, user));
        outcomes.addAll((eventService.runActions(transition.getPostAssignActions(), useCase, task, transition, params)));
        useCase = evaluateRules(useCase.getStringId(), task, EventType.ASSIGN, EventPhase.POST);
        historyService.save(new AssignTaskEventLog(task, useCase, EventPhase.POST, user));

        AssignTaskEventOutcome outcome = new AssignTaskEventOutcome(useCase, task, outcomes);
        addMessageToOutcome(transition, EventType.ASSIGN, outcome);

        log.info("[" + useCase.getStringId() + "]: Task [" + task.getTitle() + "] in case [" + useCase.getTitle() + "] assigned to [" + user.getSelfOrImpersonated().getEmail() + "]");
        return outcome;
    }

    protected Case assignTaskToUser(IUser user, Task task, String useCaseId) throws TransitionNotExecutableException {
        Case useCase = workflowService.findOne(useCaseId);
        useCase.getPetriNet().initializeArcs();
        Transition transition = useCase.getPetriNet().getTransition(task.getTransitionId());

        log.info("[" + useCaseId + "]: Assigning task [" + task.getTitle() + "] to user [" + user.getSelfOrImpersonated().getEmail() + "]");

        startExecution(transition, useCase);
        task.setUserId(user.getSelfOrImpersonated().getStringId());
        task.setStartDate(LocalDateTime.now());
        task.setUser(user.getSelfOrImpersonated());

        useCase = workflowService.save(useCase);
        save(task);
        reloadTasks(useCase);
        useCase = workflowService.findOne(useCase.getStringId());
        return useCase;
    }

    @Override
    public List finishTasks(List tasks, IUser user) throws TransitionNotExecutableException {
        return finishTasks(tasks, user, new HashMap<>());
    }

    @Override
    public List finishTasks(List tasks, IUser user, Map params) throws TransitionNotExecutableException {
        List outcomes = new ArrayList<>();
        for (Task task : tasks) {
            outcomes.add(finishTask(task, user, params));
        }
        return outcomes;
    }

    @Override
    public FinishTaskEventOutcome finishTask(String taskId) throws IllegalArgumentException, TransitionNotExecutableException {
        return finishTask(taskId, new HashMap<>());
    }

    @Override
    public FinishTaskEventOutcome finishTask(String taskId, Map params) throws IllegalArgumentException, TransitionNotExecutableException {
        LoggedUser user = userService.getLoggedOrSystem().transformToLoggedUser();
        return finishTask(user, taskId, params);
    }

    @Override
    public FinishTaskEventOutcome finishTask(LoggedUser loggedUser, String taskId) throws IllegalArgumentException, TransitionNotExecutableException {
        return finishTask(loggedUser, taskId, new HashMap<>());
    }

    @Override
    public FinishTaskEventOutcome finishTask(LoggedUser loggedUser, String taskId, Map params) throws IllegalArgumentException, TransitionNotExecutableException {
        Optional taskOptional = taskRepository.findById(taskId);
        if (taskOptional.isEmpty()) {
            throw new IllegalArgumentException("Could not find task with id [" + taskId + "]");
        }
        Task task = taskOptional.get();
        IUser user = getUserFromLoggedUser(loggedUser);

        if (task.getUserId() == null) {
            throw new IllegalArgumentException("Task with id=" + taskId + " is not assigned to any user.");
        }
        // TODO: 14. 4. 2017 replace with @PreAuthorize
        if (!task.getUserId().equals(user.getSelfOrImpersonated().getStringId()) && !loggedUser.isAnonymous()) {
            throw new IllegalArgumentException("User that is not assigned tried to finish task");
        }

        return finishTask(task, user, params);
    }

    @Override
    public FinishTaskEventOutcome finishTask(Task task, IUser user) throws TransitionNotExecutableException {
        return finishTask(task, user, new HashMap<>());
    }

    @Override
    public FinishTaskEventOutcome finishTask(Task task, IUser user, Map params) throws TransitionNotExecutableException {
        Case useCase = workflowService.findOne(task.getCaseId());
        Transition transition = useCase.getPetriNet().getTransition(task.getTransitionId());

        log.info("[" + useCase.getStringId() + "]: Finishing task [" + task.getTitle() + "] to user [" + user.getSelfOrImpersonated().getEmail() + "]");

        validateData(transition, useCase);
        List outcomes = new ArrayList<>(eventService.runActions(transition.getPreFinishActions(), useCase, task, transition, params));
        task = findOne(task.getStringId());
        useCase = evaluateRules(useCase.getStringId(), task, EventType.FINISH, EventPhase.PRE);

        finishExecution(transition, useCase.getStringId());
        task.setFinishDate(LocalDateTime.now());
        task.setFinishedBy(task.getUserId());
        task.setUserId(null);

        useCase = workflowService.findOne(useCase.getStringId());
        save(task);
        reloadTasks(useCase);
        useCase = workflowService.findOne(useCase.getStringId());
        historyService.save(new FinishTaskEventLog(task, useCase, EventPhase.PRE, user));
        outcomes.addAll(eventService.runActions(transition.getPostFinishActions(), useCase, task, transition, params));
        useCase = evaluateRules(useCase.getStringId(), task, EventType.FINISH, EventPhase.POST);

        FinishTaskEventOutcome outcome = new FinishTaskEventOutcome(useCase, task, outcomes);
        addMessageToOutcome(transition, EventType.FINISH, outcome);
        historyService.save(new FinishTaskEventLog(task, useCase, EventPhase.POST, user));
        log.info("[" + useCase.getStringId() + "]: Task [" + task.getTitle() + "] in case [" + useCase.getTitle() + "] assigned to [" + user.getSelfOrImpersonated().getEmail() + "] was finished");

        return outcome;
    }

    @Override
    public List cancelTasks(List tasks, IUser user) {
        return cancelTasks(tasks, user, new HashMap<>());
    }

    @Override
    public List cancelTasks(List tasks, IUser user, Map params) {
        List outcomes = new ArrayList<>();
        for (Task task : tasks) {
            outcomes.add(cancelTask(task, user, params));
        }
        return outcomes;
    }

    @Override
    public CancelTaskEventOutcome cancelTask(LoggedUser loggedUser, String taskId) {
        return cancelTask(loggedUser, taskId, new HashMap<>());
    }

    @Override
    public CancelTaskEventOutcome cancelTask(LoggedUser loggedUser, String taskId, Map params) {
        Optional taskOptional = taskRepository.findById(taskId);
        if (taskOptional.isEmpty()) {
            throw new IllegalArgumentException("Could not find task with id [" + taskId + "]");
        }
        IUser user = getUserFromLoggedUser(loggedUser);
        return cancelTask(taskOptional.get(), user, params);
    }

    @Override
    public CancelTaskEventOutcome cancelTask(Task task, IUser user) {
        return cancelTask(task, user, new HashMap<>());
    }

    @Override
    public CancelTaskEventOutcome cancelTask(Task task, IUser user, Map params) {
        Case useCase = workflowService.findOne(task.getCaseId());
        Transition transition = useCase.getPetriNet().getTransition(task.getTransitionId());

        log.info("[" + useCase.getStringId() + "]: Canceling task [" + task.getTitle() + "] to user [" + user.getSelfOrImpersonated().getEmail() + "]");

        List outcomes = new ArrayList<>(eventService.runActions(transition.getPreCancelActions(), useCase, task, transition, params));
        task = findOne(task.getStringId());
        useCase = evaluateRules(useCase.getStringId(), task, EventType.CANCEL, EventPhase.PRE);
        task = returnTokens(task, useCase.getStringId());
        useCase = workflowService.findOne(useCase.getStringId());
        reloadTasks(useCase);
        useCase = workflowService.findOne(useCase.getStringId());
        historyService.save(new CancelTaskEventLog(task, useCase, EventPhase.PRE, user));
        outcomes.addAll(eventService.runActions(transition.getPostCancelActions(), useCase, task, transition, params));
        useCase = evaluateRules(useCase.getStringId(), task, EventType.CANCEL, EventPhase.POST);

        CancelTaskEventOutcome outcome = new CancelTaskEventOutcome(useCase, task);
        outcome.setOutcomes(outcomes);
        addMessageToOutcome(transition, EventType.CANCEL, outcome);

        historyService.save(new CancelTaskEventLog(task, useCase, EventPhase.POST, user));
        log.info("[" + useCase.getStringId() + "]: Task [" + task.getTitle() + "] in case [" + useCase.getTitle() + "] assigned to [" + user.getSelfOrImpersonated().getEmail() + "] was cancelled");
        return outcome;
    }

    /**
     * Used in cancel task action
     */
    @Override
    public void cancelTasksWithoutReload(Set transitions, String caseId) {
        cancelTasksWithoutReload(transitions, caseId, new HashMap<>());
    }

    /**
     * Used in cancel task action
     */
    @Override
    public void cancelTasksWithoutReload(Set transitions, String caseId, Map params) {
        List tasks = taskRepository.findAllByTransitionIdInAndCaseId(transitions, caseId);
        Case useCase = null;
        for (Task task : tasks) {
            if (task.getUserId() != null) {
                if (useCase == null)
                    useCase = workflowService.findOne(task.getCaseId());
                Transition transition = useCase.getPetriNet().getTransition(task.getTransitionId());
                eventService.runActions(transition.getPreCancelActions(), useCase, task, transition, params);
                returnTokens(task, useCase.getStringId());
                eventService.runActions(transition.getPostCancelActions(), useCase, task, transition, params);
            }
        }
    }

    private Task returnTokens(Task task, String useCaseId) {
        Case useCase = workflowService.findOne(useCaseId);
        PetriNet net = useCase.getPetriNet();
        net.getArcsOfTransition(task.getTransitionId()).stream()
                .filter(arc -> arc.getSource() instanceof Place)
                .forEach(arc -> {
                    arc.rollbackExecution(useCase.getConsumedTokens().get(arc.getStringId()));
                    useCase.getConsumedTokens().remove(arc.getStringId());
                });
        workflowService.updateMarking(useCase);

        task.setUserId(null);
        task.setStartDate(null);
        task = save(task);
        workflowService.save(useCase);

        return task;
    }

    @Override
    public DelegateTaskEventOutcome delegateTask(LoggedUser loggedUser, String delegatedId, String taskId) throws TransitionNotExecutableException {
        return delegateTask(loggedUser, delegatedId, taskId, new HashMap<>());
    }

    @Override
    public DelegateTaskEventOutcome delegateTask(LoggedUser loggedUser, String delegatedId, String taskId, Map params) throws TransitionNotExecutableException {
        IUser delegatedUser = userService.resolveById(delegatedId, true);
        IUser delegateUser = getUserFromLoggedUser(loggedUser);

        Optional taskOptional = taskRepository.findById(taskId);
        if (taskOptional.isEmpty()) {
            throw new IllegalArgumentException("Could not find task with id [" + taskId + "]");
        }
        Task task = taskOptional.get();

        Case useCase = workflowService.findOne(task.getCaseId());
        Transition transition = useCase.getPetriNet().getTransition(task.getTransitionId());

        log.info("[" + useCase.getStringId() + "]: Delegating task [" + task.getTitle() + "] to user [" + delegatedUser.getEmail() + "]");

        List outcomes = new ArrayList<>(eventService.runActions(transition.getPreDelegateActions(), useCase, task, transition, params));
        task = findOne(task.getStringId());
        useCase = evaluateRules(useCase.getStringId(), task, EventType.DELEGATE, EventPhase.PRE);
        delegate(delegatedUser, task, useCase);
        historyService.save(new DelegateTaskEventLog(task, useCase, EventPhase.PRE, delegateUser, delegatedUser.getStringId()));
        outcomes.addAll(eventService.runActions(transition.getPostDelegateActions(), useCase, task, transition, params));
        useCase = evaluateRules(useCase.getStringId(), task, EventType.DELEGATE, EventPhase.POST);

        useCase = workflowService.findOne(useCase.getStringId());
        reloadTasks(useCase);

        DelegateTaskEventOutcome outcome = new DelegateTaskEventOutcome(useCase, task, outcomes);
        addMessageToOutcome(transition, EventType.DELEGATE, outcome);
        historyService.save(new DelegateTaskEventLog(task, useCase, EventPhase.POST, delegateUser, delegatedUser.getStringId()));
        log.info("Task [" + task.getTitle() + "] in case [" + useCase.getTitle() + "] assigned to [" + delegateUser.getSelfOrImpersonated().getEmail() + "] was delegated to [" + delegatedUser.getEmail() + "]");

        return outcome;
    }

    protected void delegate(IUser delegated, Task task, Case useCase) throws TransitionNotExecutableException {
        if (task.getUserId() != null) {
            task.setUserId(delegated.getStringId());
            task.setUser(delegated);
            save(task);
        } else {
            assignTaskToUser(delegated, task, useCase.getStringId());
        }
    }

    protected Case evaluateRules(String caseId, Task task, EventType eventType, EventPhase eventPhase) {
        Case useCase = workflowService.findOne(caseId);
        log.info("[" + useCase.getStringId() + "]: Task [" + task.getTitle() + "] in case [" + useCase.getTitle() + "] evaluating rules of event " + eventType.name() + " of phase " + eventPhase.name());
        int rulesExecuted = ruleEngine.evaluateRules(useCase, task, TransitionEventFact.of(task, eventType, eventPhase));
        if (rulesExecuted == 0) {
            return useCase;
        }
        return workflowService.save(useCase);
    }

    /**
     * Reloads all unassigned tasks of given case:
     * 
     * 
     * 
     * 
     * 
     * 
     * 
     * 
     * 
     * 
     * 
Task is presentTask is not present
Transition executableno actioncreate task
Transition not executabledestroy taskno action
*/ @SuppressWarnings("StatementWithEmptyBody") @Override public void reloadTasks(Case useCase) { log.info("[" + useCase.getStringId() + "]: Reloading tasks in [" + useCase.getTitle() + "]"); PetriNet net = useCase.getPetriNet(); List newTasks = new ArrayList<>(); List disabledTasks = new ArrayList<>(); Map tasks = useCase.getTasks().stream().collect(Collectors.toMap(TaskPair::getTransition, TaskPair::getTask)); for (Transition transition : net.getTransitions().values()) { String taskId = tasks.get(transition.getImportId()); if (isExecutable(transition, net)) { if (taskId != null) { // task exists - do nothing } else { // task does not exist - create a new task newTasks.add(createFromTransition(transition, useCase)); } } else { if (taskId != null) { // task exists - delete task if not assigned Optional optionalTask = taskRepository.findById(taskId); if (optionalTask.isEmpty()) { continue; } Task task = optionalTask.get(); if (task.getUserId() != null && !task.getUserId().isBlank()) { // task is assigned - do not delete } else { // task is not assigned - delete disabledTasks.add(task); } } else { // task does not exist - do nothing } } } save(newTasks); delete(disabledTasks, useCase); useCase = workflowService.resolveUserRef(useCase); for (Task task : newTasks) { executeIfAutoTrigger(useCase, net, task); } } private void executeIfAutoTrigger(Case useCase, PetriNet net, Task task) { try { Transition transition = net.getTransition(task.getTransitionId()); if (transition.hasAutoTrigger()) { executeTransition(task, useCase); } } catch (TaskNotFoundException e) { log.info("Could not execute auto trigger on task [" + task.getStringId() + "],[" + task.getTransitionId() + "], reason: " + e.getMessage()); } catch (Exception e) { log.error(e.getMessage(), e); } } boolean isExecutable(Transition transition, PetriNet net) { Collection arcsOfTransition = net.getArcsOfTransition(transition); if (arcsOfTransition == null) { return true; } return arcsOfTransition.stream() .filter(arc -> arc.getDestination().equals(transition)) // todo: from same source error .allMatch(Arc::isExecutable); } void finishExecution(Transition transition, String useCaseId) throws TransitionNotExecutableException { Case useCase = workflowService.findOne(useCaseId); log.info("[" + useCaseId + "]: Finish execution of task [" + transition.getTitle() + "] in case [" + useCase.getTitle() + "]"); execute(transition, useCase, arc -> arc.getSource().equals(transition)); Supplier> arcStreamSupplier = () -> useCase.getPetriNet().getArcsOfTransition(transition.getStringId()).stream(); arcStreamSupplier.get().filter(arc -> useCase.getConsumedTokens().containsKey(arc.getStringId())).forEach(arc -> useCase.getConsumedTokens().remove(arc.getStringId())); workflowService.save(useCase); } public void startExecution(Transition transition, Case useCase) throws TransitionNotExecutableException { log.info("[" + useCase.getStringId() + "]: Start execution of " + transition.getTitle() + " in case " + useCase.getTitle()); execute(transition, useCase, arc -> arc.getDestination().equals(transition)); } protected void execute(Transition transition, Case useCase, Predicate predicate) throws TransitionNotExecutableException { Supplier> filteredSupplier = () -> useCase.getPetriNet().getArcsOfTransition(transition.getStringId()).stream().filter(predicate); if (!filteredSupplier.get().allMatch(Arc::isExecutable)) { throw new TransitionNotExecutableException("Not all arcs can be executed task [" + transition.getStringId() + "] in case [" + useCase.getTitle() + "]"); } filteredSupplier.get().sorted((o1, o2) -> ArcOrderComparator.getInstance().compare(o1, o2)).forEach(arc -> { if (arc instanceof ResetArc) { useCase.getConsumedTokens().put(arc.getStringId(), ((Place) arc.getSource()).getTokens()); } if (arc.getReference() != null && arc.getSource() instanceof Place) { useCase.getConsumedTokens().put(arc.getStringId(), arc.getReference().getMultiplicity()); } arc.execute(); }); workflowService.updateMarking(useCase); } protected List executeTransition(Task task, Case useCase) { log.info("[" + useCase.getStringId() + "]: executeTransition [" + task.getTransitionId() + "] in case [" + useCase.getTitle() + "]"); List outcomes = new ArrayList<>(); try { log.info("assignTask [" + task.getTitle() + "] in case [" + useCase.getTitle() + "]"); outcomes.add(assignTask(task.getStringId())); log.info("getData [" + task.getTitle() + "] in case [" + useCase.getTitle() + "]"); outcomes.add(dataService.getData(task.getStringId())); log.info("finishTask [" + task.getTitle() + "] in case [" + useCase.getTitle() + "]"); outcomes.add(finishTask(task.getStringId())); } catch (TransitionNotExecutableException e) { log.error("execution of task [" + task.getTitle() + "] in case [" + useCase.getTitle() + "] failed: ", e); } return outcomes; } void validateData(Transition transition, Case useCase) { for (Map.Entry entry : transition.getDataSet().entrySet()) { if (useCase.getPetriNet().getDataSet().get(entry.getKey()) != null && useCase.getPetriNet().getDataSet().get(entry.getKey()).getValidations() != null) { validation.valid(useCase.getPetriNet().getDataSet().get(entry.getKey()), useCase.getDataField(entry.getKey())); } if (!useCase.getDataField(entry.getKey()).isRequired(transition.getImportId())) continue; if (useCase.getDataField(entry.getKey()).isUndefined(transition.getImportId()) && !entry.getValue().isRequired()) continue; Object value = useCase.getDataSet().get(entry.getKey()).getValue(); if (value == null) { Field field = useCase.getField(entry.getKey()); throw new IllegalArgumentException("Field \"" + field.getName() + "\" has null value"); } if (value instanceof String && ((String) value).isEmpty()) { Field field = useCase.getField(entry.getKey()); throw new IllegalArgumentException("Field \"" + field.getName() + "\" has empty value"); } } } protected void scheduleTaskExecution(Task task, LocalDateTime time, Case useCase) { log.info("[" + useCase.getStringId() + "]: Task " + task.getTitle() + " scheduled to run at " + time.toString()); scheduler.schedule(() -> { try { executeTransition(task, useCase); } catch (Exception e) { log.info("[" + useCase.getStringId() + "]: Scheduled task [" + task.getTitle() + "] of case [" + useCase.getTitle() + "] could not be executed: " + e); } }, DateUtils.localDateTimeToDate(time)); } @Override public Task findOne(String taskId) { Optional optionalTask = taskRepository.findById(taskId); if (optionalTask.isEmpty()) { throw new IllegalArgumentException("Could not find task with id [" + taskId + "]"); } return optionalTask.get(); } @Override public Page getAll(LoggedUser loggedUser, Pageable pageable, Locale locale) { List tasks; LoggedUser loggedOrImpersonated = loggedUser.getSelfOrImpersonated(); if (loggedOrImpersonated.getProcessRoles().isEmpty()) { tasks = new ArrayList<>(); return new PageImpl<>(tasks, pageable, 0L); } else { StringBuilder queryBuilder = new StringBuilder(); queryBuilder.append("{$or:["); loggedOrImpersonated.getProcessRoles().forEach(role -> { queryBuilder.append("{\"roles."); queryBuilder.append(role); queryBuilder.append("\":{$exists:true}},"); }); if (!loggedOrImpersonated.getProcessRoles().isEmpty()) queryBuilder.deleteCharAt(queryBuilder.length() - 1); else queryBuilder.append("{}"); queryBuilder.append("]}"); BasicQuery query = new BasicQuery(queryBuilder.toString()); query = (BasicQuery) query.with(pageable); tasks = mongoTemplate.find(query, Task.class); return loadUsers(new PageImpl<>(tasks, pageable, mongoTemplate.count(new BasicQuery(queryBuilder.toString(), "{_id:1}"), Task.class))); } } @Override public Page search(List requests, Pageable pageable, LoggedUser user, Locale locale, Boolean isIntersection) { com.querydsl.core.types.Predicate searchPredicate = searchService.buildQuery(requests, user, locale, isIntersection); if (searchPredicate != null) { Page page = taskRepository.findAll(searchPredicate, pageable); page = loadUsers(page); page = dataService.setImmediateFields(page); return page; } else { return Page.empty(); } } @Override public long count(List requests, LoggedUser user, Locale locale, Boolean isIntersection) { com.querydsl.core.types.Predicate searchPredicate = searchService.buildQuery(requests, user, locale, isIntersection); if (searchPredicate != null) { return taskRepository.count(searchPredicate); } else { return 0; } } @Override public Page findByCases(Pageable pageable, List cases) { return loadUsers(taskRepository.findByCaseIdIn(pageable, cases)); } @Override public Task findById(String id) { Optional taskOptional = taskRepository.findById(id); if (taskOptional.isEmpty()) { throw new IllegalArgumentException("Could not find task with id [" + id + "]"); } Task task = taskOptional.get(); this.setUser(task); return task; } @Override public List findAllById(List ids) { return taskRepository.findAllBy_idIn(ids).stream() .filter(Objects::nonNull) .sorted(Ordering.explicit(ids).onResultOf(Task::getStringId)) .peek(this::setUser) .collect(Collectors.toList()); } @Override public Page findByUser(Pageable pageable, IUser user) { return loadUsers(taskRepository.findByUserId(pageable, user.getSelfOrImpersonated().getStringId())); } @Override public Page findByTransitions(Pageable pageable, List transitions) { return loadUsers(taskRepository.findByTransitionIdIn(pageable, transitions)); } @Override public Page searchAll(com.querydsl.core.types.Predicate predicate) { Page tasks = taskRepository.findAll(predicate, new FullPageRequest()); return loadUsers(tasks); } @Override public Page search(com.querydsl.core.types.Predicate predicate, Pageable pageable) { Page tasks = taskRepository.findAll(predicate, pageable); return loadUsers(tasks); } @Override public Task searchOne(com.querydsl.core.types.Predicate predicate) { Page tasks = taskRepository.findAll(predicate, PageRequest.of(0, 1)); if (tasks.getTotalElements() > 0) return tasks.getContent().get(0); return null; } @Override public List findAllByCase(String caseId, Locale locale) { return taskRepository.findAllByCaseId(caseId).stream() .map(task -> new TaskReference(task.getStringId(), task.getTitle().getTranslation(locale), task.getTransitionId())) .collect(Collectors.toList()); } @Override public List findAllByCase(String caseId) { return taskRepository.findAllByCaseId(caseId); } @Override public Task save(Task task) { task = taskRepository.save(task); elasticTaskService.index(this.taskMappingService.transform(task)); return task; } @Override public List save(List tasks) { tasks = taskRepository.saveAll(tasks); tasks.forEach(task -> elasticTaskService.index(this.taskMappingService.transform(task))); return tasks; } @Override public void resolveUserRef(Case useCase) { useCase.getTasks().forEach(taskPair -> { Optional taskOptional = taskRepository.findById(taskPair.getTask()); taskOptional.ifPresent(task -> resolveUserRef(task, useCase)); }); } @Override public Task resolveUserRef(Task task, Case useCase) { task.getUsers().clear(); task.getNegativeViewUsers().clear(); task.getUserRefs().forEach((id, permission) -> { List userIds = getExistingUsers((UserListFieldValue) useCase.getDataSet().get(id).getValue()); if (userIds != null && userIds.size() != 0 && permission.containsKey("view") && !permission.get("view")) { task.getNegativeViewUsers().addAll(userIds); } else if (userIds != null && userIds.size() != 0) { task.addUsers(new HashSet<>(userIds), permission); } }); task.resolveViewUsers(); return taskRepository.save(task); } private List getExistingUsers(UserListFieldValue userListValue) { if (userListValue == null) return null; return userListValue.getUserValues().stream().map(UserFieldValue::getId) .filter(id -> userService.resolveById(id, false) != null) .collect(Collectors.toList()); } private Task createFromTransition(Transition transition, Case useCase) { final Task task = Task.with() .title(transition.getTitle()) .processId(useCase.getPetriNetId()) .caseId(useCase.get_id().toString()) .transitionId(transition.getImportId()) .layout(transition.getLayout()) .tags(transition.getTags()) .caseColor(useCase.getColor()) .caseTitle(useCase.getTitle()) .priority(transition.getPriority()) .icon(transition.getIcon() == null ? useCase.getIcon() : transition.getIcon()) .immediateDataFields(new LinkedHashSet<>(transition.getImmediateData())) .assignPolicy(transition.getAssignPolicy()) .dataFocusPolicy(transition.getDataFocusPolicy()) .finishPolicy(transition.getFinishPolicy()) .build(); transition.getEvents().forEach((type, event) -> task.addEventTitle(type, event.getTitle())); task.addAssignedUserPolicy(transition.getAssignedUserPolicy()); for (Trigger trigger : transition.getTriggers()) { Trigger taskTrigger = trigger.clone(); task.addTrigger(taskTrigger); if (taskTrigger instanceof TimeTrigger) { TimeTrigger timeTrigger = (TimeTrigger) taskTrigger; scheduleTaskExecution(task, timeTrigger.getStartDate(), useCase); } } ProcessRole defaultRole = processRoleService.defaultRole(); ProcessRole anonymousRole = processRoleService.anonymousRole(); for (Map.Entry> entry : transition.getRoles().entrySet()) { if (useCase.getEnabledRoles().contains(entry.getKey()) || defaultRole.getStringId().equals(entry.getKey()) || anonymousRole.getStringId().equals(entry.getKey())) { task.addRole(entry.getKey(), entry.getValue()); } } transition.getNegativeViewRoles().forEach(task::addNegativeViewRole); for (Map.Entry> entry : transition.getUserRefs().entrySet()) { task.addUserRef(entry.getKey(), entry.getValue()); } task.resolveViewRoles(); task.resolveViewUserRefs(); Transaction transaction = useCase.getPetriNet().getTransactionByTransition(transition); if (transaction != null) { task.setTransactionId(transaction.getStringId()); } useCase.addTask(task); return task; } private Page loadUsers(Page tasks) { Map users = new HashMap<>(); tasks.forEach(task -> { if (task.getUserId() != null) { if (users.containsKey(task.getUserId())) task.setUser(users.get(task.getUserId())); else { task.setUser(userService.resolveById(task.getUserId(), true)); users.put(task.getUserId(), task.getUser()); } } }); return tasks; } @Override public void delete(List tasks, Case useCase) { workflowService.removeTasksFromCase(tasks, useCase); log.info("[" + useCase.getStringId() + "]: Tasks of case " + useCase.getTitle() + " are being deleted"); taskRepository.deleteAll(tasks); tasks.forEach(t -> elasticTaskService.remove(t.getStringId())); } @Override public void delete(List tasks, String caseId) { workflowService.removeTasksFromCase(tasks, caseId); log.info("[" + caseId + "]: Tasks of case are being deleted"); taskRepository.deleteAll(tasks); tasks.forEach(t -> elasticTaskService.remove(t.getStringId())); } @Override public void deleteTasksByCase(String caseId) { delete(taskRepository.findAllByCaseId(caseId), caseId); } @Override public void deleteTasksByPetriNetId(String petriNetId) { taskRepository.deleteAllByProcessId(petriNetId); } private void setUser(Task task) { if (task.getUserId() != null) { task.setUser(userService.resolveById(task.getUserId(), true)); } } private EventOutcome addMessageToOutcome(Transition transition, EventType type, TaskEventOutcome outcome) { if (transition.getEvents().containsKey(type)) { outcome.setMessage(transition.getEvents().get(type).getMessage()); } return outcome; } @Override public SetDataEventOutcome getMainOutcome(Map outcomes, String taskId) { SetDataEventOutcome mainOutcome; String key = taskId; if (!outcomes.containsKey(taskId)) { Optional optional = outcomes.keySet().stream().findFirst(); if (optional.isPresent()) { key = optional.get(); } } mainOutcome = outcomes.remove(key); mainOutcome.addOutcomes(new ArrayList<>(outcomes.values())); return mainOutcome; } protected IUser getUserFromLoggedUser(LoggedUser loggedUser) { IUser user = userService.resolveById(loggedUser.getId(), true); IUser fromLogged = loggedUser.transformToUser(); user.setImpersonated(fromLogged.getImpersonated()); return user; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy