| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.syncope.core.flowable.impl; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Objects; |
| import java.util.Optional; |
| import java.util.Set; |
| import java.util.stream.Collectors; |
| import org.apache.commons.lang3.tuple.Pair; |
| import org.apache.syncope.common.lib.request.UserCR; |
| import org.apache.syncope.common.lib.request.UserUR; |
| import org.apache.syncope.common.lib.to.WorkflowTask; |
| import org.apache.syncope.common.lib.to.WorkflowTaskExecInput; |
| import org.apache.syncope.core.provisioning.api.PropagationByResource; |
| import org.apache.syncope.common.lib.types.ResourceOperation; |
| import org.apache.syncope.core.flowable.api.UserRequestHandler; |
| import org.apache.syncope.core.flowable.api.WorkflowTaskManager; |
| import org.apache.syncope.core.spring.security.AuthContextUtils; |
| import org.apache.syncope.core.persistence.api.entity.user.User; |
| import org.apache.syncope.core.provisioning.api.UserWorkflowResult; |
| import org.apache.syncope.core.flowable.support.DomainProcessEngine; |
| import org.apache.syncope.core.persistence.api.dao.UserDAO; |
| import org.apache.syncope.core.persistence.api.entity.EntityFactory; |
| import org.apache.syncope.core.provisioning.api.data.UserDataBinder; |
| import org.apache.syncope.core.workflow.api.WorkflowException; |
| import org.apache.syncope.core.workflow.java.AbstractUserWorkflowAdapter; |
| import org.flowable.bpmn.model.FlowElement; |
| import org.flowable.bpmn.model.Gateway; |
| import org.flowable.bpmn.model.SequenceFlow; |
| import org.flowable.bpmn.model.Process; |
| import org.flowable.common.engine.api.FlowableException; |
| import org.flowable.engine.runtime.ProcessInstance; |
| import org.flowable.task.api.Task; |
| import org.springframework.beans.BeanUtils; |
| |
| public class FlowableUserWorkflowAdapter extends AbstractUserWorkflowAdapter implements WorkflowTaskManager { |
| |
| protected final DomainProcessEngine engine; |
| |
| protected final UserRequestHandler userRequestHandler; |
| |
| public FlowableUserWorkflowAdapter( |
| final UserDataBinder dataBinder, |
| final UserDAO userDAO, |
| final EntityFactory entityFactory, |
| final DomainProcessEngine engine, |
| final UserRequestHandler userRequestHandler) { |
| |
| super(dataBinder, userDAO, entityFactory); |
| this.engine = engine; |
| this.userRequestHandler = userRequestHandler; |
| } |
| |
| @Override |
| public String getPrefix() { |
| return "ACT_"; |
| } |
| |
| @Override |
| public <T> T getVariable(final String executionId, final String variableName, final Class<T> variableClass) { |
| return engine.getRuntimeService().getVariable(executionId, variableName, variableClass); |
| } |
| |
| @Override |
| public void setVariable(final String executionId, final String variableName, final Object value) { |
| engine.getRuntimeService().setVariable(executionId, variableName, value); |
| } |
| |
| protected User lazyLoad(final User user) { |
| // using BeanUtils to access all user's properties and trigger lazy loading - we are about to |
| // serialize a User instance for availability within workflow tasks, and this breaks transactions |
| BeanUtils.copyProperties(user, entityFactory.newEntity(User.class)); |
| return user; |
| } |
| |
| @Override |
| protected UserWorkflowResult<Pair<String, Boolean>> doCreate( |
| final UserCR userCR, |
| final boolean disablePwdPolicyCheck, |
| final Boolean enabled, |
| final String creator, |
| final String context) { |
| |
| Map<String, Object> variables = new HashMap<>(); |
| variables.put(FlowableRuntimeUtils.WF_EXECUTOR, AuthContextUtils.getUsername()); |
| variables.put(FlowableRuntimeUtils.USER_CR, userCR); |
| variables.put(FlowableRuntimeUtils.ENABLED, enabled); |
| |
| ProcessInstance procInst = null; |
| try { |
| procInst = engine.getRuntimeService(). |
| startProcessInstanceByKey(FlowableRuntimeUtils.WF_PROCESS_ID, variables); |
| } catch (FlowableException e) { |
| FlowableRuntimeUtils.throwException( |
| e, "While starting " + FlowableRuntimeUtils.WF_PROCESS_ID + " instance"); |
| } |
| |
| engine.getRuntimeService().removeVariable( |
| Objects.requireNonNull(procInst).getProcessInstanceId(), FlowableRuntimeUtils.WF_EXECUTOR); |
| engine.getRuntimeService().removeVariable( |
| procInst.getProcessInstanceId(), FlowableRuntimeUtils.USER_CR); |
| engine.getRuntimeService().removeVariable( |
| procInst.getProcessInstanceId(), FlowableRuntimeUtils.USER_TO); |
| |
| User user = engine.getRuntimeService(). |
| getVariable(procInst.getProcessInstanceId(), FlowableRuntimeUtils.USER, User.class); |
| engine.getRuntimeService().removeVariable( |
| procInst.getProcessInstanceId(), FlowableRuntimeUtils.USER); |
| |
| Boolean updatedEnabled = engine.getRuntimeService(). |
| getVariable(procInst.getProcessInstanceId(), FlowableRuntimeUtils.ENABLED, Boolean.class); |
| engine.getRuntimeService().removeVariable( |
| procInst.getProcessInstanceId(), FlowableRuntimeUtils.ENABLED); |
| if (updatedEnabled != null) { |
| user.setSuspended(!updatedEnabled); |
| } |
| |
| // this will make UserValidator not to consider password policies at all |
| if (disablePwdPolicyCheck) { |
| user.removeClearPassword(); |
| } |
| |
| metadata(user, creator, context); |
| FlowableRuntimeUtils.updateStatus(engine, procInst.getProcessInstanceId(), user); |
| User created = userDAO.save(user); |
| |
| engine.getRuntimeService().updateBusinessKey( |
| procInst.getProcessInstanceId(), FlowableRuntimeUtils.getWFProcBusinessKey(created.getKey())); |
| |
| Boolean propagateEnable = engine.getRuntimeService().getVariable( |
| procInst.getProcessInstanceId(), FlowableRuntimeUtils.PROPAGATE_ENABLE, Boolean.class); |
| engine.getRuntimeService().removeVariable( |
| procInst.getProcessInstanceId(), FlowableRuntimeUtils.PROPAGATE_ENABLE); |
| if (propagateEnable == null) { |
| propagateEnable = enabled; |
| } |
| |
| PropagationByResource<String> propByRes = new PropagationByResource<>(); |
| propByRes.set(ResourceOperation.CREATE, userDAO.findAllResourceKeys(created.getKey())); |
| |
| PropagationByResource<Pair<String, String>> propByLinkedAccount = new PropagationByResource<>(); |
| user.getLinkedAccounts().forEach(account -> propByLinkedAccount.add( |
| ResourceOperation.CREATE, |
| Pair.of(account.getResource().getKey(), account.getConnObjectKeyValue()))); |
| |
| FlowableRuntimeUtils.saveForFormSubmit( |
| engine, |
| procInst.getProcessInstanceId(), |
| dataBinder.getUserTO(created, true), |
| userCR.getPassword(), |
| enabled, |
| propByRes, |
| propByLinkedAccount); |
| |
| Set<String> tasks = FlowableRuntimeUtils.getPerformedTasks(engine, procInst.getProcessInstanceId()); |
| |
| return new UserWorkflowResult<>( |
| Pair.of(created.getKey(), propagateEnable), |
| propByRes, |
| propByLinkedAccount, |
| tasks); |
| } |
| |
| protected Set<String> doExecuteNextTask( |
| final String procInstID, |
| final User user, |
| final Map<String, Object> moreVariables) { |
| |
| Set<String> preTasks = FlowableRuntimeUtils.getPerformedTasks(engine, procInstID); |
| |
| Map<String, Object> variables = new HashMap<>(); |
| variables.put(FlowableRuntimeUtils.WF_EXECUTOR, AuthContextUtils.getUsername()); |
| variables.put(FlowableRuntimeUtils.USER, lazyLoad(user)); |
| |
| if (moreVariables != null && !moreVariables.isEmpty()) { |
| variables.putAll(moreVariables); |
| } |
| |
| List<Task> tasks = engine.getTaskService().createTaskQuery().processInstanceId(procInstID).list(); |
| String task = null; |
| if (tasks.size() == 1) { |
| try { |
| engine.getTaskService().complete(tasks.get(0).getId(), variables); |
| task = tasks.get(0).getTaskDefinitionKey(); |
| } catch (FlowableException e) { |
| FlowableRuntimeUtils.throwException( |
| e, "While completing task '" + tasks.get(0).getName() + "' for " + user); |
| } |
| } else { |
| LOG.warn("Expected a single task, found {}", tasks.size()); |
| } |
| |
| Set<String> postTasks = FlowableRuntimeUtils.getPerformedTasks(engine, procInstID); |
| postTasks.removeAll(preTasks); |
| if (task != null) { |
| postTasks.add(task); |
| } |
| |
| return postTasks; |
| } |
| |
| @Override |
| protected UserWorkflowResult<String> doActivate( |
| final User user, final String token, final String updater, final String context) { |
| |
| String procInstID = FlowableRuntimeUtils.getWFProcInstID(engine, user.getKey()); |
| |
| Map<String, Object> variables = new HashMap<>(2); |
| variables.put(FlowableRuntimeUtils.TOKEN, token); |
| variables.put(FlowableRuntimeUtils.TASK, "activate"); |
| |
| Set<String> tasks = doExecuteNextTask(procInstID, user, variables); |
| |
| metadata(user, updater, context); |
| FlowableRuntimeUtils.updateStatus(engine, procInstID, user); |
| User updated = userDAO.save(user); |
| |
| variables.keySet().forEach(key -> engine.getRuntimeService().removeVariable(procInstID, key)); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.USER); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.WF_EXECUTOR); |
| |
| return new UserWorkflowResult<>(updated.getKey(), null, null, tasks); |
| } |
| |
| @Override |
| protected UserWorkflowResult<Pair<UserUR, Boolean>> doUpdate( |
| final User user, final UserUR userUR, final String updater, final String context) { |
| |
| String procInstID = FlowableRuntimeUtils.getWFProcInstID(engine, user.getKey()); |
| |
| // save some existing variable values for later processing, after actual update is made |
| UserUR beforeUpdate = engine.getRuntimeService(). |
| getVariable(procInstID, FlowableRuntimeUtils.USER_UR, UserUR.class); |
| @SuppressWarnings("unchecked") |
| PropagationByResource<String> propByResBeforeUpdate = engine.getRuntimeService().getVariable( |
| procInstID, FlowableRuntimeUtils.PROP_BY_RESOURCE, PropagationByResource.class); |
| @SuppressWarnings("unchecked") |
| PropagationByResource<Pair<String, String>> propByLinkedAccountBeforeUpdate = engine.getRuntimeService(). |
| getVariable(procInstID, FlowableRuntimeUtils.PROP_BY_LINKEDACCOUNT, PropagationByResource.class); |
| |
| // whether the initial status is a form task |
| boolean inFormTask = FlowableRuntimeUtils.getFormTask(engine, procInstID) != null; |
| |
| Map<String, Object> variables = new HashMap<>(2); |
| variables.put(FlowableRuntimeUtils.USER_UR, userUR); |
| variables.put(FlowableRuntimeUtils.TASK, "update"); |
| |
| Set<String> tasks = doExecuteNextTask(procInstID, user, variables); |
| |
| metadata(user, updater, context); |
| FlowableRuntimeUtils.updateStatus(engine, procInstID, user); |
| User updated = userDAO.save(user); |
| |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.USER); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.WF_EXECUTOR); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.TASK); |
| |
| // if the original status was a form task, restore the patch as before the process started |
| if (inFormTask) { |
| if (beforeUpdate == null) { |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.USER_UR); |
| } else { |
| engine.getRuntimeService().setVariable(procInstID, FlowableRuntimeUtils.USER_UR, beforeUpdate); |
| } |
| } |
| |
| // whether the after status is a form task |
| inFormTask = FlowableRuntimeUtils.getFormTask(engine, procInstID) != null; |
| if (!inFormTask) { |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.USER_UR); |
| } |
| |
| @SuppressWarnings("unchecked") |
| PropagationByResource<String> propByRes = engine.getRuntimeService().getVariable( |
| procInstID, FlowableRuntimeUtils.PROP_BY_RESOURCE, PropagationByResource.class); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.PROP_BY_RESOURCE); |
| |
| @SuppressWarnings("unchecked") |
| PropagationByResource<Pair<String, String>> propByLinkedAccount = engine.getRuntimeService().getVariable( |
| procInstID, FlowableRuntimeUtils.PROP_BY_LINKEDACCOUNT, PropagationByResource.class); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.PROP_BY_LINKEDACCOUNT); |
| |
| FlowableRuntimeUtils.saveForFormSubmit( |
| engine, |
| procInstID, |
| dataBinder.getUserTO(updated, true), |
| userUR.getPassword() == null ? null : userUR.getPassword().getValue(), |
| null, |
| Optional.ofNullable(propByResBeforeUpdate).orElse(propByRes), |
| Optional.ofNullable(propByLinkedAccountBeforeUpdate).orElse(propByLinkedAccount)); |
| |
| Boolean propagateEnable = engine.getRuntimeService().getVariable( |
| procInstID, FlowableRuntimeUtils.PROPAGATE_ENABLE, Boolean.class); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.PROPAGATE_ENABLE); |
| |
| return new UserWorkflowResult<>(Pair.of(userUR, propagateEnable), propByRes, propByLinkedAccount, tasks); |
| } |
| |
| @Override |
| protected UserWorkflowResult<String> doSuspend(final User user, final String updater, final String context) { |
| String procInstID = FlowableRuntimeUtils.getWFProcInstID(engine, user.getKey()); |
| |
| Set<String> performedTasks = |
| doExecuteNextTask(procInstID, user, Map.of(FlowableRuntimeUtils.TASK, "suspend")); |
| |
| metadata(user, updater, context); |
| FlowableRuntimeUtils.updateStatus(engine, procInstID, user); |
| User updated = userDAO.save(user); |
| |
| @SuppressWarnings("unchecked") |
| PropagationByResource<String> propByRes = engine.getRuntimeService().getVariable( |
| procInstID, FlowableRuntimeUtils.PROP_BY_RESOURCE, PropagationByResource.class); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.PROP_BY_RESOURCE); |
| |
| @SuppressWarnings("unchecked") |
| PropagationByResource<Pair<String, String>> propByLinkedAccount = engine.getRuntimeService().getVariable( |
| procInstID, FlowableRuntimeUtils.PROP_BY_LINKEDACCOUNT, PropagationByResource.class); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.PROP_BY_LINKEDACCOUNT); |
| |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.TASK); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.USER); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.WF_EXECUTOR); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.PROP_BY_RESOURCE); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.PROP_BY_LINKEDACCOUNT); |
| |
| return new UserWorkflowResult<>(updated.getKey(), propByRes, propByLinkedAccount, performedTasks); |
| } |
| |
| @Override |
| protected UserWorkflowResult<String> doReactivate(final User user, final String updater, final String context) { |
| String procInstID = FlowableRuntimeUtils.getWFProcInstID(engine, user.getKey()); |
| |
| Set<String> performedTasks = |
| doExecuteNextTask(procInstID, user, Map.of(FlowableRuntimeUtils.TASK, "reactivate")); |
| |
| metadata(user, updater, context); |
| FlowableRuntimeUtils.updateStatus(engine, procInstID, user); |
| User updated = userDAO.save(user); |
| |
| @SuppressWarnings("unchecked") |
| PropagationByResource<String> propByRes = engine.getRuntimeService().getVariable( |
| procInstID, FlowableRuntimeUtils.PROP_BY_RESOURCE, PropagationByResource.class); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.PROP_BY_RESOURCE); |
| |
| @SuppressWarnings("unchecked") |
| PropagationByResource<Pair<String, String>> propByLinkedAccount = engine.getRuntimeService().getVariable( |
| procInstID, FlowableRuntimeUtils.PROP_BY_LINKEDACCOUNT, PropagationByResource.class); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.PROP_BY_LINKEDACCOUNT); |
| |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.TASK); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.USER); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.WF_EXECUTOR); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.PROP_BY_RESOURCE); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.PROP_BY_LINKEDACCOUNT); |
| |
| return new UserWorkflowResult<>(updated.getKey(), propByRes, propByLinkedAccount, performedTasks); |
| } |
| |
| @Override |
| protected void doRequestPasswordReset(final User user, final String updater, final String context) { |
| Map<String, Object> variables = new HashMap<>(3); |
| variables.put(FlowableRuntimeUtils.USER_TO, dataBinder.getUserTO(user, true)); |
| variables.put(FlowableRuntimeUtils.TASK, "requestPasswordReset"); |
| variables.put(FlowableRuntimeUtils.EVENT, "requestPasswordReset"); |
| |
| String procInstID = FlowableRuntimeUtils.getWFProcInstID(engine, user.getKey()); |
| |
| doExecuteNextTask(procInstID, user, variables); |
| |
| metadata(user, updater, context); |
| userDAO.save(user); |
| |
| variables.keySet().forEach(key -> engine.getRuntimeService().removeVariable(procInstID, key)); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.USER); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.WF_EXECUTOR); |
| } |
| |
| @Override |
| protected UserWorkflowResult<Pair<UserUR, Boolean>> doConfirmPasswordReset( |
| final User user, final String token, final String password, final String updater, final String context) { |
| |
| Map<String, Object> variables = new HashMap<>(5); |
| variables.put(FlowableRuntimeUtils.TOKEN, token); |
| variables.put(FlowableRuntimeUtils.PASSWORD, password); |
| variables.put(FlowableRuntimeUtils.USER_TO, dataBinder.getUserTO(user, true)); |
| variables.put(FlowableRuntimeUtils.TASK, "confirmPasswordReset"); |
| variables.put(FlowableRuntimeUtils.EVENT, "confirmPasswordReset"); |
| |
| String procInstID = FlowableRuntimeUtils.getWFProcInstID(engine, user.getKey()); |
| |
| Set<String> tasks = doExecuteNextTask(procInstID, user, variables); |
| |
| metadata(user, updater, context); |
| userDAO.save(user); |
| |
| variables.keySet().forEach(key -> engine.getRuntimeService().removeVariable(procInstID, key)); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.USER); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.WF_EXECUTOR); |
| |
| @SuppressWarnings("unchecked") |
| PropagationByResource<String> propByRes = engine.getRuntimeService().getVariable( |
| procInstID, FlowableRuntimeUtils.PROP_BY_RESOURCE, PropagationByResource.class); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.PROP_BY_RESOURCE); |
| @SuppressWarnings("unchecked") |
| PropagationByResource<Pair<String, String>> propByLinkedAccount = engine.getRuntimeService().getVariable( |
| procInstID, FlowableRuntimeUtils.PROP_BY_LINKEDACCOUNT, PropagationByResource.class); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.PROP_BY_LINKEDACCOUNT); |
| UserUR updatedReq = engine.getRuntimeService().getVariable( |
| procInstID, FlowableRuntimeUtils.USER_UR, UserUR.class); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.USER_UR); |
| Boolean propagateEnable = engine.getRuntimeService().getVariable( |
| procInstID, FlowableRuntimeUtils.PROPAGATE_ENABLE, Boolean.class); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.PROPAGATE_ENABLE); |
| |
| return new UserWorkflowResult<>(Pair.of(updatedReq, propagateEnable), propByRes, propByLinkedAccount, tasks); |
| } |
| |
| @Override |
| protected void doDelete(final User user) { |
| String procInstID = FlowableRuntimeUtils.getWFProcInstID(engine, user.getKey()); |
| |
| doExecuteNextTask(procInstID, user, Map.of(FlowableRuntimeUtils.TASK, "delete")); |
| |
| PropagationByResource<String> propByRes = new PropagationByResource<>(); |
| propByRes.set(ResourceOperation.DELETE, userDAO.findAllResourceKeys(user.getKey())); |
| |
| PropagationByResource<Pair<String, String>> propByLinkedAccount = new PropagationByResource<>(); |
| user.getLinkedAccounts().forEach(account -> propByLinkedAccount.add( |
| ResourceOperation.DELETE, |
| Pair.of(account.getResource().getKey(), account.getConnObjectKeyValue()))); |
| |
| if (engine.getRuntimeService().createProcessInstanceQuery(). |
| processInstanceId(procInstID).active().list().isEmpty()) { |
| |
| userDAO.delete(user.getKey()); |
| |
| if (!engine.getHistoryService().createHistoricProcessInstanceQuery(). |
| processInstanceId(procInstID).list().isEmpty()) { |
| |
| engine.getHistoryService().deleteHistoricProcessInstance(procInstID); |
| } |
| } else { |
| FlowableRuntimeUtils.saveForFormSubmit( |
| engine, |
| procInstID, |
| dataBinder.getUserTO(user, true), |
| null, |
| null, |
| propByRes, |
| propByLinkedAccount); |
| |
| FlowableRuntimeUtils.updateStatus(engine, procInstID, user); |
| userDAO.save(user); |
| |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.TASK); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.USER); |
| engine.getRuntimeService().removeVariable(procInstID, FlowableRuntimeUtils.WF_EXECUTOR); |
| } |
| } |
| |
| @Override |
| public UserWorkflowResult<String> executeNextTask(final WorkflowTaskExecInput workflowTaskExecInput) { |
| User user = userDAO.authFind(workflowTaskExecInput.getUserKey()); |
| |
| String procInstID = FlowableRuntimeUtils.getWFProcInstID(engine, user.getKey()); |
| |
| Map<String, Object> variables = new HashMap<>(); |
| variables.put(FlowableRuntimeUtils.USER_TO, dataBinder.getUserTO(user, true)); |
| variables.putAll(workflowTaskExecInput.getVariables()); |
| |
| Set<String> performedTasks = doExecuteNextTask(procInstID, user, variables); |
| FlowableRuntimeUtils.updateStatus(engine, procInstID, user); |
| user = userDAO.save(user); |
| |
| engine.getRuntimeService().setVariable( |
| procInstID, FlowableRuntimeUtils.USER_TO, dataBinder.getUserTO(user, true)); |
| |
| if (engine.getRuntimeService().createProcessInstanceQuery(). |
| processInstanceId(procInstID).active().list().isEmpty()) { |
| |
| userDAO.delete(user.getKey()); |
| |
| if (!engine.getHistoryService().createHistoricProcessInstanceQuery(). |
| processInstanceId(procInstID).list().isEmpty()) { |
| |
| engine.getHistoryService().deleteHistoricProcessInstance(procInstID); |
| } |
| } else { |
| @SuppressWarnings("unchecked") |
| PropagationByResource<String> propByRes = engine.getRuntimeService(). |
| getVariable(procInstID, FlowableRuntimeUtils.PROP_BY_RESOURCE, PropagationByResource.class); |
| @SuppressWarnings("unchecked") |
| PropagationByResource<Pair<String, String>> propByLinkedAccount = engine.getRuntimeService().getVariable( |
| procInstID, FlowableRuntimeUtils.PROP_BY_LINKEDACCOUNT, PropagationByResource.class); |
| |
| FlowableRuntimeUtils.saveForFormSubmit( |
| engine, |
| procInstID, |
| dataBinder.getUserTO(user, true), |
| null, |
| null, |
| propByRes, |
| propByLinkedAccount); |
| } |
| |
| return new UserWorkflowResult<>(user.getKey(), null, null, performedTasks); |
| } |
| |
| protected static void navigateAvailableTasks(final FlowElement flow, final List<String> availableTasks) { |
| if (flow instanceof Gateway) { |
| ((Gateway) flow).getOutgoingFlows().forEach(subflow -> navigateAvailableTasks(subflow, availableTasks)); |
| } else if (flow instanceof SequenceFlow) { |
| navigateAvailableTasks(((SequenceFlow) flow).getTargetFlowElement(), availableTasks); |
| } else if (flow instanceof org.flowable.bpmn.model.Task) { |
| availableTasks.add(flow.getId()); |
| } else { |
| LOG.debug("Unexpected flow found: {}", flow); |
| } |
| } |
| |
| @Override |
| public List<WorkflowTask> getAvailableTasks(final String userKey) { |
| String procInstID = FlowableRuntimeUtils.getWFProcInstID(engine, userKey); |
| |
| List<String> availableTasks = new ArrayList<>(); |
| try { |
| Task currentTask = engine.getTaskService().createTaskQuery().processInstanceId(procInstID).singleResult(); |
| |
| Process process = engine.getRepositoryService(). |
| getBpmnModel(FlowableRuntimeUtils.getLatestProcDefByKey( |
| engine, FlowableRuntimeUtils.WF_PROCESS_ID).getId()).getProcesses().get(0); |
| process.getFlowElements().stream(). |
| filter(SequenceFlow.class::isInstance). |
| map(SequenceFlow.class::cast). |
| filter(flow -> flow.getSourceRef().equals(currentTask.getTaskDefinitionKey())). |
| forEach(flow -> navigateAvailableTasks(flow.getTargetFlowElement(), availableTasks)); |
| } catch (FlowableException e) { |
| throw new WorkflowException( |
| "While reading available tasks for workflow instance " + procInstID, e); |
| } |
| |
| return availableTasks.stream().map(input -> { |
| WorkflowTask workflowTaskTO = new WorkflowTask(); |
| workflowTaskTO.setName(input); |
| return workflowTaskTO; |
| }).collect(Collectors.toList()); |
| } |
| } |