Executing the Java Task
Overview
Once the task has been submitted on the Atoti Limits UI, the details are sent to the Atoti Limits server, where the action is completed by the IWorkflowTaskActionDelegator
. This delegator accepts the submitted WorkflowTaskActionExecutionDTO
, then delegates and
executes the task as required.
The Submitted DTO
The WorkflowTaskActionExecutionDTO
object looks as follows:
public class WorkflowTaskActionExecutionDTO implements Serializable {
private static final long serialVersionUID = 6548671478152737730L;
// The key of the task to be executed
protected String taskKey;
// The type of workflow. Either INCIDENT or LIMIT
protected String workflowType;
// The object keys (limitIds or incidentIds) for which to process the task action.
protected ArrayList<Integer> keys;
// Optional workflow variables to provide in the DTO
protected Map<String, String> taskVariables;
}
where:
- the
taskKey
is used by the delegator to determine which task to execute - the
workflowType
indicates the type of workflow for which the task exists - the
keys
indicate the objects upon which the task is executed - the
taskVariables
store optional task variables to be handled by the backend and are the result of the inputs to theWorkflowTaskActionInputFieldDTO
The Delegator
The IWorkflowTaskActionDelegator
is a simple delegator that accepts a WorkflowTaskActionExecutionDTO
and delegates the work to a backend service. It contains two methods:
public interface IWorkflowTaskActionDelegator {
/**
* This initiates a workflow task action related to the button the user selected. This function will have to be updated for every new button.
*
* @param workflowTaskActionExecutionDTO
* @throws ValidationException
* @throws Exception
* @throws AccessDeniedException
*/
void executeTaskActionForTaskActionKey(WorkflowTaskActionExecutionDTO workflowTaskActionExecutionDTO) throws ValidationException, AccessDeniedException, Exception;
/**
* A map of workflow processes to a user specified workflow name.
*
* Ex.
* {
* StraightThrough: "limit-process-instance.straight-through",
* FourEyes: "limit-process-instance.four-eyes",
* Exception: "limit-process-instance.exception"
* }
* @return
*/
Map<String, String> retrieveWorkflowKey();
}
The executeTaskActionForTaskActionKey()
method accepts the WorkflowTaskActionExecutionDTO
and delegates it to a task action based on its taskKey
.
The retrieveWorkflowKey()
method is used to retrieve a map of all workflows by their name. The default implementation maps to the limit workflow properties.
Customizing the Java tasks
The delegator has a custom implementation defined. This can be overridden if you’re not using the out-of-the-box workflows.
Alternatively, you can append custom actions to the default implementation by implementing the ICustomWorkflowTaskActionService
.
The Default Delegator
The default delegator is defined in the starter’s DefaultWorkflowTaskActionDelegator
. Take a look to see how the tasks are delegated, but note that the methods of
delegation are completely optional to you.
Overriding the default delegator
To override the delegator, implement your own IWorkflowTaskActionDelegator
.
Here’s an example of a simple delegator that only logs the action that is executed:
@Component
@Slf4j
public class LogWorkflowTaskActionDelegator implements IWorkflowTaskActionDelegator {
@Autowired
protected LimitsProperties limitsProperties;
@Override
public void executeTaskActionForTaskActionKey(WorkflowTaskActionExecutionDTO workflowTaskActionExecutionDTO)
throws ValidationException, AccessDeniedException, Exception {
log.info("Executing task for key {}", workflowTaskActionExecutionDTO.getTaskKey());
}
@Override
public Map<String, String> retrieveWorkflowKey() {
return limitsProperties.getWorkflowTypes();
}
}
Appending to the default delegator
To append to the default delegator, add an implementation of ICustomWorkflowTaskActionService
.
The ICustomWorkflowTaskActionService
has one method which needs to be overridden: executeCustomTask()
. This method is responsible for managing how the task is executed in the backend.
public interface ICustomWorkflowTaskActionService {
/**
* @param workflowTaskActionExecutionDTO - the custom workflow task action to execute
*/
void executeCustomTask(WorkflowTaskActionExecutionDTO workflowTaskActionExecutionDTO);
}
note
If a task key is provided that is not handled, it will eventually be routed to the ICustomWorkflowTaskActionService
and the default implementation in the starter will throw an exception:
@Slf4j
@Service
public class DefaultCustomWorkflowService implements ICustomWorkflowTaskActionService {
@Override
public void executeCustomTask(WorkflowTaskActionExecutionDTO workflowTaskActionExecutionDTO) {
String message = String.format(
"No workflow found for taskKey %s. If this is a custom workflow then please implement your own ICustomWorkflowService to handle it.",
workflowTaskActionExecutionDTO.getTaskKey());
throw new ActiveViamRuntimeException(message);
}
}
Here’s an example of a custom comment action:
@Slf4j
@Service
public class CustomCommentWorkflowTaskActionService implements ICustomWorkflowTaskActionService {
protected static final String COMMENT_KEY = "CUSTOM_COMMENT";
@Autowired
protected ILimitsProcessInstanceWorkflowService limitsProcessInstanceWorkflowService;
@Override
public void executeCustomTask(WorkflowTaskActionExecutionDTO workflowTaskActionExecutionDTO) {
try {
String taskKey = workflowTaskActionExecutionDTO.getTaskKey();
List<LimitsProcessInstance> limitsProcessInstanceS = getLimitsProcessInstances(workflowTaskActionExecutionDTO);
if (taskKey.equals(CUSTOM_KEY)) {
executeCommentTask(limitsProcessInstanceS, workflowTaskActionExecutionDTO.getTaskVariables());
} else {
log.error("No custom task action configured for key {}", taskKey);
}
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
}
}
protected List<LimitsProcessInstance> getLimitsProcessInstances(WorkflowTaskActionExecutionDTO workflowTaskActionExecutionDTO) {
List<LimitsProcessInstance> limitsProcessInstances = new ArrayList<>();
LimitsProcessInstanceType limitsProcessInstanceType = getLimitsProcessInstanceType(workflowTaskActionExecutionDTO);
for (Integer objectKey : workflowTaskActionExecutionDTO.getKeys()) {
LimitsProcessInstanceKey limitsProcessInstanceKey = new LimitsProcessInstanceKey(objectKey, limitsProcessInstanceType);
limitsProcessInstances.add(limitsProcessInstanceWorkflowService.get(limitsProcessInstanceKey.getKeyString()));
}
return limitsProcessInstances;
}
protected LimitsProcessInstanceType getLimitsProcessInstanceType(WorkflowTaskActionExecutionDTO workflowTaskActionExecutionDTO) {
String workflowType = workflowTaskActionExecutionDTO.getWorkflowType();
switch (workflowType) {
// Limit Workflow
case "LIMIT":
return CREATION;
// Incident Workflow
case "INCIDENT":
return EXCEPTION;
default:
throw new ActiveViamRuntimeException("Workflow type (" + workflowType + ") does not exist!");
}
}
protected void executeCommentTask(List<LimitsProcessInstance> limitsProcessInstances, Map<String, String> workflowVariables) throws ValidationException {
Map<String, Object> variables = new HashMap<>();
variables.put("action", "comment");
variables.putAll(workflowVariables);
for (LimitsProcessInstance limitsProcessInstance : limitsProcessInstances) {
// Submit the task to Activiti and retrieve the history record
UserTaskRecordDTO historyRecordDto = limitsProcessInstanceWorkflowService.taskStateTransition(limitsProcessInstance.getKey(),
limitsProcessInstance,
COMMENT_KEY,
"N/A",
variables);
String status = historyRecordDto.getStatus();
// Update the incident in the datastore
limitsProcessInstanceWorkflowService.transitIncidentWorkflowStatus(limitsProcessInstance, status);
}
}
}
Importing the Services
Once the appropriate components/services have been defined, import them to the project using a Spring configuration class.