blob: 71d4dd42c378ee9542cb186723deeb3606637b36 [file] [log] [blame]
/**
*
* 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;
}
}