| /** |
| * |
| * Copyright (c) 2011, 2016 - Loetz GmbH&Co.KG (69115 Heidelberg, Germany) |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Christophe Loetz (Loetz GmbH&Co.KG) - initial implementation |
| * |
| */ |
| package org.eclipse.osbp.vaaclipse.addons.softwarefactory.bpmImpl; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.UUID; |
| |
| import javax.annotation.PostConstruct; |
| import javax.annotation.PreDestroy; |
| import javax.inject.Inject; |
| |
| import org.drools.SystemEventListenerFactory; |
| import org.drools.event.process.ProcessCompletedEvent; |
| import org.drools.event.process.ProcessEventListener; |
| import org.drools.event.process.ProcessNodeLeftEvent; |
| import org.drools.event.process.ProcessNodeTriggeredEvent; |
| import org.drools.event.process.ProcessStartedEvent; |
| import org.drools.event.process.ProcessVariableChangedEvent; |
| import org.eclipse.e4.core.di.annotations.Creatable; |
| import org.eclipse.e4.core.di.annotations.Optional; |
| import org.eclipse.e4.core.services.events.IEventBroker; |
| import org.eclipse.osbp.bpm.api.IBPMEngine; |
| import org.eclipse.osbp.bpm.api.IBPMTaskClient; |
| import org.eclipse.osbp.bpm.api.IBPMTaskEventNotification; |
| import org.eclipse.osbp.dsl.common.datatypes.IDto; |
| import org.eclipse.osbp.eventbroker.EventBrokerMsg; |
| import org.eclipse.osbp.preferences.ProductConfiguration; |
| import org.eclipse.osbp.ui.api.user.IUser; |
| import org.jbpm.task.Status; |
| import org.jbpm.task.Task; |
| import org.jbpm.task.TaskData; |
| import org.jbpm.task.event.TaskEventListener; |
| import org.jbpm.task.event.entity.TaskEventType; |
| import org.jbpm.task.event.entity.TaskUserEvent; |
| import org.jbpm.task.query.TaskSummary; |
| import org.jbpm.task.service.FaultData; |
| import org.jbpm.task.service.Operation; |
| import org.jbpm.task.service.PermissionDeniedException; |
| import org.jbpm.task.service.TaskClient; |
| import org.jbpm.task.service.mina.MinaTaskClientConnector; |
| import org.jbpm.task.service.mina.MinaTaskClientHandler; |
| import org.jbpm.task.service.responsehandlers.BlockingGetTaskResponseHandler; |
| import org.jbpm.task.service.responsehandlers.BlockingTaskOperationResponseHandler; |
| import org.jbpm.task.service.responsehandlers.BlockingTaskSummaryResponseHandler; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import com.vaadin.ui.Notification; |
| import com.vaadin.ui.Notification.Type; |
| |
| @Creatable |
| public class BPMTaskClient implements IBPMTaskClient { |
| |
| @Inject |
| @Optional |
| private IBPMEngine bpmEngine; |
| |
| @Inject |
| private IEventBroker eventBroker; |
| |
| private static Logger log = LoggerFactory.getLogger(BPMTaskClient.class); |
| private TaskClient taskClient; |
| private MinaTaskClientHandler minaHandler; |
| private MinaTaskClientConnector minaConnector; |
| boolean isConnected = false; |
| private TaskEventListener taskEventListener; |
| private ProcessEventListener processEventListener; |
| private Map<TaskEventType, List<IBPMTaskEventNotification>> taskNotificationMap; |
| private List<IBPMTaskEventNotification> completedNotificationList; |
| private Map<Operation, Map<Long,List<PostponeNotification>>> inExecutionMap; |
| private BPMTaskVariablesCache taskVariablesCache; |
| |
| @Inject |
| public BPMTaskClient() { |
| minaHandler = new MinaTaskClientHandler(SystemEventListenerFactory.getSystemEventListener()); |
| minaConnector = new MinaTaskClientConnector(UUID.randomUUID().toString(), minaHandler); |
| taskClient = new TaskClient(minaConnector); |
| taskVariablesCache = new BPMTaskVariablesCache(); |
| } |
| |
| @PostConstruct |
| protected void init() { |
| log.debug("init"); |
| taskNotificationMap = new HashMap<TaskEventType, List<IBPMTaskEventNotification>>(); |
| inExecutionMap = new HashMap<Operation, Map<Long,List<PostponeNotification>>>(); |
| |
| taskEventListener = new TaskEventListener() { |
| @Override |
| public void taskCreated(TaskUserEvent event) { |
| log.debug("received taskCreated event from bpmEngine"); |
| notifySubscribers(TaskEventType.Create, event); |
| } |
| @Override |
| public void taskClaimed(TaskUserEvent event) { |
| log.debug("received taskClaimed event from bpmEngine"); |
| notifySubscribers(TaskEventType.Claim, event); |
| } |
| @Override |
| public void taskCompleted(TaskUserEvent event) { |
| log.debug("received taskCompleted event from bpmEngine"); |
| notifySubscribers(TaskEventType.Complete, event); |
| } |
| @Override |
| public void taskFailed(TaskUserEvent event) { |
| log.debug("received taskFailed event from bpmEngine"); |
| notifySubscribers(TaskEventType.Fail, event); |
| } |
| @Override |
| public void taskForwarded(TaskUserEvent event) { |
| log.debug("received taskForwarded event from bpmEngine"); |
| notifySubscribers(TaskEventType.Forward, event); |
| } |
| @Override |
| public void taskReleased(TaskUserEvent event) { |
| log.debug("received taskReleased event from bpmEngine"); |
| notifySubscribers(TaskEventType.Release, event); |
| } |
| @Override |
| public void taskSkipped(TaskUserEvent event) { |
| log.debug("received taskSkipped event from bpmEngine"); |
| notifySubscribers(TaskEventType.Skipped, event); |
| } |
| @Override |
| public void taskStarted(TaskUserEvent event) { |
| log.debug("received taskStarted event from bpmEngine"); |
| notifySubscribers(TaskEventType.Started, event); |
| } |
| @Override |
| public void taskStopped(TaskUserEvent event) { |
| log.debug("received taskStopped event from bpmEngine"); |
| notifySubscribers(TaskEventType.Stop, event); |
| } |
| }; |
| processEventListener = new ProcessEventListener() { |
| @Override |
| public void beforeVariableChanged(ProcessVariableChangedEvent arg0) {} |
| |
| @Override |
| public void beforeProcessStarted(ProcessStartedEvent arg0) {} |
| |
| @Override |
| public void beforeProcessCompleted(ProcessCompletedEvent arg0) {} |
| |
| @Override |
| public void beforeNodeTriggered(ProcessNodeTriggeredEvent arg0) {} |
| |
| @Override |
| public void beforeNodeLeft(ProcessNodeLeftEvent arg0) {} |
| |
| @Override |
| public void afterVariableChanged(ProcessVariableChangedEvent arg0) {} |
| |
| @Override |
| public void afterProcessStarted(ProcessStartedEvent arg0) {} |
| |
| @Override |
| public void afterProcessCompleted(ProcessCompletedEvent event) { |
| log.debug("received processCompleted event from bpmEngine"); |
| notifySubscribers(event); |
| } |
| |
| @Override |
| public void afterNodeTriggered(ProcessNodeTriggeredEvent arg0) {} |
| |
| @Override |
| public void afterNodeLeft(ProcessNodeLeftEvent arg0) {} |
| }; |
| |
| if(bpmEngine != null) { |
| bpmEngine.addTaskEventListener(taskEventListener); |
| bpmEngine.addProcessEventListener(processEventListener); |
| log.debug("connect with "+ProductConfiguration.getBpmServerIp()+" Port "+ProductConfiguration.getBpmServerPort()); |
| isConnected = taskClient.connect(ProductConfiguration.getBpmServerIp(),ProductConfiguration.getBpmServerPort()); |
| } else { |
| log.debug("bpm is not licensed"); |
| } |
| } |
| |
| @PreDestroy |
| protected void shutdown() { |
| log.debug("shutdown"); |
| if(bpmEngine != null) { |
| bpmEngine.removeTaskEventListener(taskEventListener); |
| bpmEngine.removeProcessEventListener(processEventListener); |
| if (isConnected) { |
| try { |
| taskClient.disconnect(); |
| } catch (Exception e) { |
| } |
| } |
| } |
| } |
| |
| public boolean operations(final long taskId, final IUser user, final IUser alternateUser, final Operation operation) { |
| log.debug("try task operation " + operation.name() + " for user " |
| + user.getUserName() + " with id " + Long.toString(taskId)); |
| if (!isConnected) { |
| return false; |
| } |
| boolean retval = true; |
| BlockingTaskOperationResponseHandler taskOperationResponseHandler = new BlockingTaskOperationResponseHandler(); |
| |
| addInExecution(operation, taskId); |
| try { |
| switch (operation) { |
| case Claim: |
| taskClient.claim(taskId, user.getUserName(), |
| taskOperationResponseHandler); |
| break; |
| case Start: |
| Task task = getTask(taskId); |
| TaskData taskData = task.getTaskData(); |
| if(taskData.getStatus()==Status.Ready || taskData.getStatus()==Status.Reserved) { |
| taskClient.start(taskId, user.getUserName(), |
| taskOperationResponseHandler); |
| } else if(taskData.getStatus()==Status.Created) { |
| taskClient.claim(taskId, user.getUserName(), |
| taskOperationResponseHandler); |
| } else if(taskData.getStatus()==Status.Suspended) { |
| taskClient.resume(taskId, user.getUserName(), |
| taskOperationResponseHandler); |
| } else if(taskData.getStatus()==Status.InProgress) { |
| taskOperationResponseHandler.setIsDone(true); |
| openPerspective(taskId, user); |
| } |
| break; |
| case Stop: |
| taskClient.stop(taskId, user.getUserName(), |
| taskOperationResponseHandler); |
| break; |
| case Release: |
| taskClient.release(taskId, user.getUserName(), |
| taskOperationResponseHandler); |
| break; |
| case Suspend: |
| //taskClient.setDocumentContent(taskId, content, responseHandler); |
| taskClient.suspend(taskId, user.getUserName(), taskOperationResponseHandler); |
| break; |
| case Resume: |
| taskClient.resume(taskId, user.getUserName(), |
| taskOperationResponseHandler); |
| break; |
| case Skip: |
| taskClient.skip(taskId, user.getUserName(), |
| taskOperationResponseHandler); |
| break; |
| case Delegate: |
| taskClient.delegate(taskId, user.getUserName(), |
| alternateUser.getUserName(), taskOperationResponseHandler); |
| break; |
| case Forward: |
| taskClient.forward(taskId, user.getUserName(), |
| alternateUser.getUserName(), taskOperationResponseHandler); |
| break; |
| case Complete: |
| TaskSummary taskSummary = getUserTask(taskId, user); |
| Map<String, Object> variables = getProcessVariables(taskSummary); |
| try { |
| taskClient.completeWithResults(taskId, user.getUserName(), variables, taskOperationResponseHandler); |
| } |
| catch (Exception e) { |
| log.error("complete "+taskId+" with results: ", e); |
| } |
| break; |
| case Fail: |
| FaultData fData = new FaultData(); |
| fData.setFaultName("user pressed fail"); |
| taskClient.fail(taskId, user.getUserName(), |
| fData, taskOperationResponseHandler); |
| break; |
| case Register: |
| taskClient.register(taskId, user.getUserName(), |
| taskOperationResponseHandler); |
| break; |
| case Remove: |
| taskClient.remove(taskId, user.getUserName(), |
| taskOperationResponseHandler); |
| break; |
| case Activate: |
| taskClient.activate(taskId, user.getUserName(), |
| taskOperationResponseHandler); |
| break; |
| case Exit: |
| taskClient.exit(taskId, user.getUserName(), |
| taskOperationResponseHandler); |
| break; |
| default: |
| break; |
| } |
| try { |
| taskOperationResponseHandler.waitTillDone(ProductConfiguration.getBpmResponseTimeout()); |
| } catch(RuntimeException ex) { |
| } |
| clearTaskVariablesCache(taskId); |
| removeInExecution(operation, taskId); |
| switch (operation) { |
| case Activate: |
| case Start: |
| case Resume: |
| openPerspective(taskId, user); |
| break; |
| case Suspend: |
| closePerspective(taskId, user); |
| default: |
| break; |
| } |
| } catch (PermissionDeniedException e) { |
| log.error("permission denied", e); |
| Notification.show("Permission denied "+e.getLocalizedMessage()+"!", |
| Type.ERROR_MESSAGE); |
| retval = false; |
| } |
| return retval; |
| } |
| |
| private void openPerspective(long taskId, IUser user) { |
| EventBrokerMsg msg = new EventBrokerMsg(); |
| msg.setLong(taskId); |
| // TaskSummary in object1 |
| msg.setObject1(getUserTask(taskId, user)); |
| eventBroker.send(EventBrokerMsg.OPEN_PERSPECTIVE, msg); |
| } |
| |
| private void closePerspective(long taskId, IUser user) { |
| EventBrokerMsg msg = new EventBrokerMsg(); |
| msg.setLong(taskId); |
| // TaskSummary in object1 |
| msg.setObject1(getUserTask(taskId, user)); |
| eventBroker.send(EventBrokerMsg.CLOSE_PERSPECTIVE, msg); |
| } |
| |
| public Task getTask(final Long taskId) { |
| log.debug("getTask "+((Long)taskId).toString()); |
| if (!isConnected) { |
| return null; |
| } |
| BlockingGetTaskResponseHandler taskResponseHandler = new BlockingGetTaskResponseHandler(); |
| taskClient.getTask(taskId, taskResponseHandler); |
| try { |
| taskResponseHandler.waitTillDone(ProductConfiguration.getBpmResponseTimeout()); |
| } catch (Exception e) { |
| if (taskResponseHandler.getError() != null) { |
| log.error("getTask ", taskResponseHandler.getError()); |
| } |
| } |
| if (taskResponseHandler.isDone()) { |
| log.debug("getUserTask returns"); |
| return taskResponseHandler.getTask(); |
| } |
| return null; |
| } |
| |
| public TaskSummary getUserTask(final Long taskId, final IUser user) { |
| log.debug("getUserTask user "+user.getUserName()+" locale "+user.getLocale().toLanguageTag()); |
| if (!isConnected) { |
| return null; |
| } |
| List<TaskSummary> tasks = getUserTaskList(user, false); |
| if (tasks == null || tasks.size() == 0) { |
| tasks = getUserTaskList(user, true); |
| } |
| if (tasks != null && tasks.size() > 0) { |
| for (TaskSummary task : tasks) { |
| if (taskId.equals(task.getId())) { |
| return task; |
| } |
| } |
| } |
| log.debug("task not found"); |
| return null; |
| } |
| |
| public List<TaskSummary> getUserTaskList(final IUser user,boolean owned) { |
| log.debug("getUserTaskList user "+user.getUserName()+" locale "+user.getLocale().toLanguageTag()); |
| if (!isConnected) { |
| return Collections.emptyList(); |
| } |
| List<TaskSummary> tasks = null; |
| BlockingTaskSummaryResponseHandler taskSummaryResponseHandler = new BlockingTaskSummaryResponseHandler(); |
| |
| if (!owned) { |
| if ("Administrator".equals(user.getUserName())) { |
| taskClient.getTasksAssignedAsBusinessAdministrator(user.getUserName(), |
| user.getLocale().toLanguageTag(), taskSummaryResponseHandler); |
| } else { |
| taskClient.getTasksAssignedAsPotentialOwner(user.getUserName(), |
| user.getLocale().toLanguageTag(), taskSummaryResponseHandler); |
| } |
| } |
| else |
| { |
| taskClient.getTasksOwned(user.getUserName(), user.getLocale().toLanguageTag(), taskSummaryResponseHandler); |
| } |
| try { |
| log.debug("awaiting summary response with timeout(ms):"+ProductConfiguration.getBpmResponseTimeout()); |
| taskSummaryResponseHandler.waitTillDone(ProductConfiguration.getBpmResponseTimeout()); |
| } catch (Exception e) { |
| if (taskSummaryResponseHandler.getError() != null) { |
| log.error("getTaskList ", taskSummaryResponseHandler.getError()); |
| } |
| } |
| tasks = taskSummaryResponseHandler.getResults(); |
| log.debug("getTaskList returns "+tasks.size()+(owned?" owned":" potential")+" tasks "); |
| return tasks; |
| } |
| |
| @Override |
| public void subscribeTaskEventNotification(IBPMTaskEventNotification notification) { |
| for(TaskEventType type : TaskEventType.values()) { |
| subscribeTaskEventNotification(type, notification); |
| } |
| subscribeProcessCompletedEventNotification(notification); |
| } |
| |
| @Override |
| public void subscribeTaskEventNotification(TaskEventType type, IBPMTaskEventNotification notification) { |
| if(!taskNotificationMap.containsKey(type)) { |
| List<IBPMTaskEventNotification> notificationList = new ArrayList<IBPMTaskEventNotification>(); |
| notificationList.add(notification); |
| taskNotificationMap.put(type, notificationList); |
| } |
| else |
| { |
| taskNotificationMap.get(type).add(notification); |
| } |
| } |
| |
| @Override |
| public void unsubscribeTaskEventNotification(IBPMTaskEventNotification notification) { |
| for(TaskEventType type : TaskEventType.values()) { |
| unsubscribeTaskEventNotification(type, notification); |
| } |
| unsubscribeProcessCompletedEventNotification(notification); |
| } |
| |
| @Override |
| public void unsubscribeTaskEventNotification(TaskEventType type, IBPMTaskEventNotification notification) { |
| if(taskNotificationMap.containsKey(type)) { |
| taskNotificationMap.get(type).remove(notification); |
| } |
| } |
| |
| @Override |
| public void subscribeProcessCompletedEventNotification(IBPMTaskEventNotification notification) { |
| if (completedNotificationList == null) { |
| completedNotificationList = new ArrayList<IBPMTaskEventNotification>(); |
| } |
| completedNotificationList.add(notification); |
| } |
| |
| @Override |
| public void unsubscribeProcessCompletedEventNotification(IBPMTaskEventNotification notification) { |
| if (completedNotificationList != null) { |
| completedNotificationList.remove(notification); |
| } |
| } |
| |
| // as the type is not set by jbpm, we provide it ourself |
| private void notifySubscribers(TaskEventType type, TaskUserEvent event) { |
| log.debug("notify for "+event.getTaskId()+": "+type.getValue()); |
| if(taskNotificationMap.containsKey(type)) { |
| for(IBPMTaskEventNotification subscriber : taskNotificationMap.get(type)) { |
| if(isInExecution(type, event.getTaskId())) { |
| log.debug("- postpone "+subscriber.getClass().getCanonicalName()); |
| postponeNotification(subscriber, type, event); |
| } |
| else { |
| log.debug("- notify "+subscriber.getClass().getCanonicalName()); |
| subscriber.notifyTaskEvent(type, event); |
| } |
| } |
| } |
| } |
| |
| // as the type is not set by jbpm, we provide it ourself |
| private void notifySubscribers(ProcessCompletedEvent event) { |
| log.debug("notify for "+event.getProcessInstance().getId()+": ProcessCompleted"); |
| for(IBPMTaskEventNotification subscriber : completedNotificationList) { |
| log.debug("- notify "+subscriber.getClass().getCanonicalName()); |
| subscriber.notifyProcessCompletedEvent(event); |
| } |
| } |
| |
| // postpone notification stuff |
| private void addInExecution(Operation operation, Long taskId) { |
| if (!inExecutionMap.containsKey(operation)) { |
| Map<Long,List<PostponeNotification>> ppn = new HashMap<Long,List<PostponeNotification>>(); |
| ppn.put(taskId, null); |
| inExecutionMap.put(operation, ppn); |
| } |
| else |
| { |
| inExecutionMap.get(operation).put(taskId, null); |
| } |
| } |
| |
| private void removeInExecution(Operation operation, Long taskId) { |
| if(inExecutionMap.containsKey(operation)) { |
| if(inExecutionMap.get(operation).containsKey(taskId)) { |
| if(inExecutionMap.get(operation).get(taskId) != null) { |
| for(PostponeNotification postponeNotification : inExecutionMap.get(operation).get(taskId)) { |
| postponeNotification.getNotification().notifyTaskEvent(postponeNotification.getType(), postponeNotification.getEvent()); |
| } |
| inExecutionMap.get(operation).get(taskId).clear(); |
| } |
| inExecutionMap.get(operation).remove(taskId); |
| } |
| } |
| } |
| |
| Operation mapEventTypeToOperation(TaskEventType type) { |
| Operation operation = null; |
| switch(type) { |
| case Claim: |
| operation = Operation.Claim; |
| break; |
| case Complete: |
| operation = Operation.Complete; |
| break; |
| case Delegated: |
| operation = Operation.Delegate; |
| break; |
| case Started: |
| operation = Operation.Start; |
| break; |
| case Resume: |
| operation = Operation.Resume; |
| break; |
| case Suspended: |
| operation = Operation.Suspend; |
| break; |
| case Skipped: |
| operation = Operation.Skip; |
| break; |
| case Stop: |
| operation = Operation.Stop; |
| break; |
| default: |
| operation = Operation.Activate; |
| // log.error("unmapped TaskEventType received:"+type.toString()); |
| break; |
| } |
| return operation; |
| } |
| |
| private boolean isInExecution(TaskEventType type, Long taskId) { |
| Operation operation = mapEventTypeToOperation(type); |
| if(inExecutionMap.containsKey(operation)) { |
| if (inExecutionMap.get(operation).containsKey(taskId)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private void postponeNotification(IBPMTaskEventNotification notification, TaskEventType type, TaskUserEvent event) { |
| Operation operation = mapEventTypeToOperation(type); |
| if(inExecutionMap.containsKey(operation)) { |
| if(inExecutionMap.get(operation).get(event.getTaskId()) == null) { |
| List<PostponeNotification> ppnList = new ArrayList<PostponeNotification>(); |
| inExecutionMap.get(operation).put(event.getTaskId(), ppnList); |
| } |
| inExecutionMap.get(operation).get(event.getTaskId()).add(new PostponeNotification(notification, type, event)); |
| } |
| } |
| |
| @Override |
| public String getProcessId(Object taskSummary) { |
| if (taskSummary instanceof TaskSummary) { |
| return ((TaskSummary) taskSummary).getProcessId(); |
| } |
| return null; |
| } |
| |
| private void clearTaskVariablesCache(long taskId) { |
| taskVariablesCache.clear(taskId); |
| } |
| |
| @Override |
| public Map<String, Object> getProcessVariables(Object taskSummary) { |
| if (taskSummary != null) { |
| if (taskVariablesCache.contains(taskSummary)) { |
| return taskVariablesCache.getVariables(taskSummary); |
| } |
| else { |
| return bpmEngine.getProcessVariables(taskSummary); |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public Object getProcessVariable(Object taskSummary, String variable) { |
| if (taskSummary != null) { |
| if (taskVariablesCache.contains(taskSummary)) { |
| return taskVariablesCache.getVariable(taskSummary, variable); |
| } |
| else { |
| return bpmEngine.getProcessVariable(taskSummary, variable); |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public String getWorkloadDtoFqn(Object taskSummary) { |
| Object value = getProcessVariable(taskSummary, VARIABLE_PROCESS_WORKLOAD_DTO_FQN); |
| if (value instanceof String) { |
| return (String) value; |
| } |
| return null; |
| } |
| |
| @Override |
| public IDto getWorkloadDto(Object taskSummary) { |
| Object value = getProcessVariable(taskSummary, VARIABLE_PROCESS_WORKLOAD_DTO); |
| if (value instanceof IDto) { |
| return (IDto) value; |
| } |
| return null; |
| } |
| |
| @Override |
| public void setWorkloadDto(Object taskSummary, IDto workloadDto) { |
| setProcessVariable(taskSummary, VARIABLE_PROCESS_WORKLOAD_DTO, workloadDto); |
| } |
| |
| @Override |
| public Object setProcessVariable(Object taskSummary, String variable, Object value) { |
| if (taskSummary != null) { |
| if (taskVariablesCache.getVariables(taskSummary) == null) { |
| taskVariablesCache.initialize(taskSummary, getProcessVariables(taskSummary)); |
| } |
| taskVariablesCache.setVariable(taskSummary, variable, value); |
| return bpmEngine.setProcessVariable(taskSummary, variable, value); |
| } |
| return null; |
| } |
| } |