/** * Publishes a message to qpid that describes what action a user has just performed on a task. * These actions may be either TaskTaken or TaskCompleted. This calls checkInitialized to see if * there is a valid connection to qpid. * * @param task the task that has been acted upon * @param exchangeName the exchange name for messaging * @param eventName the event that correlates with the action * @param taskId the id of the task that was acted upon */ public void amqpTaskPublish(Task task, String exchangeName, String eventName, String taskId) { String info = ""; if (checkInitialized()) { if (eventName.equals("TaskTaken")) { try { info = "eventType=" + eventName + ";" + "processID=" + task.getProcessInstanceId() + ";" + "taskID=" + task.getId() + ";" + "assignee=" + task.getAssignee() + ";"; } catch (Exception e) { log.debug(e.getMessage()); } } else if (eventName.equals("TaskCompleted")) { try { org.jbpm.task.Task ht = taskRepo.findById(Long.decode(taskId)); String processName = ht.getTaskData().getProcessId(); String processId = Long.toString(ht.getTaskData().getProcessInstanceId()); String assignee = ht.getTaskData().getActualOwner().getId(); info = "eventType=" + eventName + ";" + "processID=" + processName + "." + processId + ";" + "taskID=" + taskId + ";" + "assignee=" + assignee + ";"; } catch (Exception e) { log.debug(e.getMessage()); } } sendMessage(info, exchangeName); } }
@Override public Task convert(org.jbpm.task.query.TaskSummary source) { Task target = new Task(); target.setDescription(source.getDescription()); if (source.getActualOwner() != null) { target.setAssignee(source.getActualOwner().getId()); } if (source.getCreatedOn() != null) { target.setCreateTime(convert(source.getCreatedOn(), XMLGregorianCalendar.class)); } if (source.getExpirationTime() != null) { target.setDueDate(convert(source.getExpirationTime(), XMLGregorianCalendar.class)); } target.setId(String.valueOf(source.getId())); if (source.getName() != null) { String[] parts = source.getName().split("/"); target.setActivityName(parts[0]); target.setName(parts[1]); } target.setState(source.getStatus().name()); target.setPriority(new Integer(source.getPriority())); target.setProcessInstanceId( source.getProcessId() + "." + Long.toString(source.getProcessInstanceId())); BlockingGetTaskResponseHandler getTaskResponseHandler = new BlockingGetTaskResponseHandler(); taskClient.getTask(source.getId(), getTaskResponseHandler); org.jbpm.task.Task task = getTaskResponseHandler.getTask(); BlockingGetContentResponseHandler getContentResponseHandler = new BlockingGetContentResponseHandler(); taskClient.getContent(task.getTaskData().getDocumentContentId(), getContentResponseHandler); Content content = getContentResponseHandler.getContent(); Map<String, Object> map = (Map<String, Object>) ContentMarshallerHelper.unmarshall(content.getContent(), null); for (String key : map.keySet()) { log.debug("Key: " + key); } // add task outcomes using the "Options" variable from the task String optionsString = (String) map.get("Options"); if (optionsString != null) { String[] options = ((String) map.get("Options")).split(","); target.getOutcomes().addAll(Arrays.asList(options)); } // get ad-hoc variables map Map<String, Object> contentMap = (Map<String, Object>) map.get(Bpmn20UserTaskNodeBuilder.TASK_INPUT_VARIABLES_NAME); if (contentMap != null) { for (Entry<String, Object> entry : contentMap.entrySet()) { log.debug(entry.getKey() + "=" + entry.getValue()); addVariable(target, entry.getKey(), entry.getValue()); } } else { log.debug("No Content found for task"); } // add variables /*Set<String> names = taskService.getVariableNames(source.getId()); Map<String, Object> variables = taskService.getVariables(source.getId(), names); // remove process name var variables.remove("_name"); for (String key : variables.keySet()) { Variable var = new Variable(); var.setName(key); // Support strings only. Other types will cause ClassCastException try { var.setValue((String) variables.get(key)); } catch (ClassCastException e) { var.setValue("Variable type " + variables.get(key).getClass().getName() + " is not supported"); } addVariable(target, var); } // Do this only if the task is not an ad-hoc task (as indicated by null executionId) if (source.getExecutionId() != null) { // name is the 'form' attribute in JPDL // this is used in the COW schema to store the display name, as distinct from the system-generated name target.setName(source.getFormResourceName()); // activityName is the 'name' from JPDL target.setActivityName(source.getActivityName()); Execution ex = executionService.findExecutionById(source.getExecutionId()); target.setProcessInstanceId(ex.getProcessInstance().getId()); // outcomes Set<String> outcomes = taskService.getOutcomes(source.getId()); for (String outcome : outcomes) { target.getOutcomes().add(outcome); } // Workaround to the fact that we cannot use autowiring here if (this.cowTaskService == null) { this.cowTaskService = (org.wiredwidgets.cow.server.service.TaskService) this.factory.getBean("taskService"); } // add process level task varibles ( String executionId = getTopLevelExecutionId(source.getExecutionId()); org.wiredwidgets.cow.server.api.model.v2.Activity activity = cowTaskService.getWorkflowActivity(executionId, source.getActivityName()); if (activity != null && activity instanceof org.wiredwidgets.cow.server.api.model.v2.Task) { org.wiredwidgets.cow.server.api.model.v2.Task cowTask = (org.wiredwidgets.cow.server.api.model.v2.Task) activity; if (cowTask.getVariables() != null) { for (org.wiredwidgets.cow.server.api.model.v2.Variable var : cowTask.getVariables().getVariables()) { Variable newVar = new Variable(); newVar.setName(var.getName()); newVar.setValue(var.getValue()); addVariable(target, newVar); } } } } else { // for ad-hoc tasks target.setName(source.getName()); }*/ return target; }
private void addVariable(Task task, Variable var) { if (task.getVariables() == null) { task.setVariables(new Variables()); } task.getVariables().getVariables().add(var); }
// TODO: Check if you can update a task. Can you update task by just adding a task with the same // ID? private org.jbpm.task.Task createOrUpdateTask(Task source) { org.jbpm.task.Task target; boolean newTask = false; if (source.getId() == null) { newTask = true; target = new org.jbpm.task.Task(); } else { BlockingGetTaskResponseHandler getTaskResponseHandler = new BlockingGetTaskResponseHandler(); taskClient.getTask(Long.valueOf(source.getId()), getTaskResponseHandler); target = getTaskResponseHandler.getTask(); } if (target == null) { return null; } if (source.getAssignee() != null) { PeopleAssignments pa = new PeopleAssignments(); List<OrganizationalEntity> orgEnt = new ArrayList<OrganizationalEntity>(); org.jbpm.task.User oe = new org.jbpm.task.User(); oe.setId(source.getAssignee()); pa.setTaskInitiator(oe); orgEnt.add(oe); pa.setPotentialOwners(orgEnt); target.setPeopleAssignments(pa); } if (source.getDescription() != null) { List<I18NText> desc = new ArrayList<I18NText>(); desc.add(new I18NText("en-UK", source.getDescription())); target.setDescriptions(desc); } if (source.getDueDate() != null) { Deadlines deadlines = new Deadlines(); List<Deadline> dls = new ArrayList<Deadline>(); Deadline dl = new Deadline(); dl.setDate(this.convert(source.getDueDate())); dls.add(dl); deadlines.setEndDeadlines(dls); target.setDeadlines(deadlines); } if (source.getName() != null) { List<I18NText> names = new ArrayList<I18NText>(); names.add(new I18NText("en-UK", source.getName())); target.setNames(names); } if (source.getPriority() != null) { target.setPriority(source.getPriority()); } TaskData td = new TaskData(); target.setTaskData(td); /* * if (source.getProgress() != null) { * target.setProgress(source.getProgress()); } */ // convert variables /* * if (source.getVariables() != null && * source.getVariables().getVariables().size() > 0) { Map<String, * Object> variables = new HashMap<String, Object>(); for (Variable * variable : source.getVariables().getVariables()) { * variables.put(variable.getName(), variable.getValue()); } * this.taskService.setVariables(target.getId(), variables); } */ if (newTask) { BlockingAddTaskResponseHandler addTaskResponseHandler = new BlockingAddTaskResponseHandler(); taskClient.addTask(target, null, addTaskResponseHandler); } return target; }
@Override public void completeTask( Long id, String assignee, String outcome, Map<String, Object> variables) { // should be handled upstream in controller assert (assignee != null); log.debug(assignee + " starting task with ID: " + id); BlockingGetTaskResponseHandler getTaskResponseHandler = new BlockingGetTaskResponseHandler(); taskClient.getTask(id, getTaskResponseHandler); org.jbpm.task.Task task = getTaskResponseHandler.getTask(); // convert to COW task so we can verify the decision Task cowTask = converter.convert(task, Task.class); if (cowTask.getOutcomes() != null && cowTask.getOutcomes().size() > 0) { // This is a decision task! if (outcome == null) { throw new RuntimeException("ERROR: no decision provided for a Decision task"); } if (!cowTask.getOutcomes().contains(outcome)) { throw new RuntimeException("ERROR: decision value " + outcome + " is not a valid choice."); } } BlockingGetContentResponseHandler getContentResponseHandler = new BlockingGetContentResponseHandler(); taskClient.getContent(task.getTaskData().getDocumentContentId(), getContentResponseHandler); Content inputContent = getContentResponseHandler.getContent(); Map<String, Object> inputMap = (Map<String, Object>) ContentMarshallerHelper.unmarshall(inputContent.getContent(), null); for (Map.Entry<String, Object> entry : inputMap.entrySet()) { log.debug(entry.getKey() + " = " + entry.getValue()); } Map<String, Object> outputMap = new HashMap<String, Object>(); // put Outcome into the outputMap // The InputMap contains a variable that tells us what key to use if (inputMap.get(DECISION_VAR_NAME) != null) { log.debug("Decision outcome: " + outcome); outputMap.put((String) inputMap.get(DECISION_VAR_NAME), outcome); } Map<String, Object> outputVarsMap = new HashMap<String, Object>(); // NOTE: obtaining the map from the Task results in a copy of the map as of the // time when the task became available. It's possible that in the meantime (e.g. due to // a parallel task) the map has been altered. // Map<String, Object> inputVarsMap = (Map<String, Object>) // inputMap.get(TASK_INPUT_VARIABLES_NAME); // So, instead, we get the current values directly from the process instance, rather than the // values copied into the task Long processInstanceId = task.getTaskData().getProcessInstanceId(); Map<String, Object> inputVarsMap = null; try { WorkflowProcessInstance pi = (WorkflowProcessInstance) kSession.getProcessInstance(processInstanceId); inputVarsMap = (Map<String, Object>) pi.getVariable(VARIABLES_PROPERTY); } catch (Exception e) { // not an active process? look in the dB. log.error(e); List<VariableInstanceLog> vars = JPAProcessInstanceDbLog.findVariableInstances(processInstanceId, VARIABLES_PROPERTY); log.info("variable count: " + vars.size()); if (vars.size() > 0) { // why more than one??? inputVarsMap = (Map<String, Object>) vars.get(0); } } if (inputVarsMap != null) { // initialize the output map with the input values log.debug("Copying input map: " + inputVarsMap); outputVarsMap.putAll(inputVarsMap); } if (variables != null && variables.size() > 0) { log.debug("Adding variables: " + variables); // update with any new or modified values outputVarsMap.putAll(variables); } if (outputVarsMap.size() > 0) { log.debug("Adding map to output"); outputMap.put(TASK_OUTPUT_VARIABLES_NAME, outputVarsMap); } // start the task if (task.getTaskData().getStatus().equals(org.jbpm.task.Status.Reserved)) { BlockingTaskOperationResponseHandler operationResponseHandler = new BlockingTaskOperationResponseHandler(); // change status to InProgress taskClient.start(id, assignee, operationResponseHandler); } // kSession.getWorkItemManager().completeWorkItem(task.getTaskData().getWorkItemId(), new // HashMap<String,Object>()); BlockingTaskOperationResponseHandler taskResponseHandler = new BlockingTaskOperationResponseHandler(); // TODO: since we're passing the variables map further down, maybe we don't need to pass it // here? Test this. ContentData contentData = ContentMarshallerHelper.marshal(outputMap, null); taskClient.complete(id, assignee, contentData, taskResponseHandler); taskResponseHandler.waitTillDone(1000); // note that we have to pass the variables again. kSession.getWorkItemManager().completeWorkItem(task.getTaskData().getWorkItemId(), outputMap); // update completed date // For some reason this does not get updated by default, and // there appears to be no JBPM API way to do this! org.jbpm.task.Task t = taskRepo.findOne(task.getId()); t.getTaskData().setCompletedOn(new Date()); // update the user t.getTaskData().setActualOwner(new User(assignee)); // note that JPA handles updating of this object automatically }