const { handle5thIndustryUserTask } = require('./5thIndustry.js');
const {
getProcessIds,
getDefinitionsAndProcessIdForEveryCallActivity,
} = require('@proceed/bpmn-helper');
const distribution = require('@proceed/distribution');
/**
* Creates a callback function that can be used to register to the userTask stream of the neo engine
*
* @param {Object} engine proceed engine instance that contains the process information
* @param {Object} instance the process instance the user task was encountered in
*/
function onUserTask(engine, instance, tokenId, userTask) {
return new Promise(async (resolve) => {
engine._log.info({
msg: `A new User Task was encountered, InstanceId = ${instance.id}`,
instanceId: instance.id,
});
function activate() {
resolve(true);
}
const extendedUserTask = {
processInstance: instance,
processChain: engine.processID,
tokenId,
...userTask,
attrs: userTask.$attrs || {},
activate,
};
if (userTask.implementation === '5thIndustry') {
const success = await handle5thIndustryUserTask(extendedUserTask, engine);
if (!success) {
return;
}
activate();
}
engine.userTasks.push(extendedUserTask);
});
}
/**
* Creates a callback that handles the execution of callActivities when one becomes active
*
* @param {Object} engine proceed engine instance that contains the process information
* @param {Class} Engine the process Execution class that we want to create a new Instance of to execute the callActivity process
* @param {Object} instance the process instance the call activity was encountered in
*/
function onCallActivity(engine, Engine, instance, tokenId, callActivity) {
return new Promise(async (resolve) => {
// get necessary process information about the process referenced by the callActivity
const callActivityDefinitionIdMapping = await getDefinitionsAndProcessIdForEveryCallActivity(
engine._bpmn
);
const callActivityDefinitionId = callActivityDefinitionIdMapping[callActivity.id].definitionId;
const importBPMN = await distribution.db.getImportedProcess(
engine.definitionId,
callActivityDefinitionId
);
const [importProcessId] = await getProcessIds(importBPMN);
// if there is no execution engine registered for the process to execute create a new one
if (!Object.keys(engine.callActivityExecutors).includes(importProcessId)) {
const CAExecutionEngine = new Engine();
engine.callActivityExecutors[importProcessId] = CAExecutionEngine;
CAExecutionEngine._log = engine._log;
await CAExecutionEngine.deployProcess(engine.definitionId, callActivityDefinitionId);
}
// get current variable state to pass on to the instance of the callActivity process
const variables = instance.getVariables();
// start execution of callActivity process with variables from the current instance
engine._log.info({
msg: `Starting callActivity with id ${callActivity.id}. Imported process definitionId: ${callActivityDefinitionId}. CallingInstanceId = ${instance.id}`,
instanceId: instance.id,
});
engine.callActivityExecutors[importProcessId].startProcess(
variables,
undefined,
// onStarted callBack: log that we started an instance of a callActivity process
(callActivityInstance) => {
callActivityInstance.callingInstance = instance;
resolve(true);
},
// onEnded callBack: return possibly changed variables from the callActivity instance back to the calling instance
(callActivityInstance) => {
const variables = callActivityInstance.getVariables();
instance.completeActivity(callActivity.id, tokenId, variables);
}
);
});
}
module.exports = {
getShouldActivateFlowNode(engine, Engine) {
return async function shouldActivateFlowNode(
processId,
processInstanceId,
tokenId,
flowNode,
state
) {
const instance = engine.getInstance(processInstanceId);
// flowNodes that are set to external should be handled through the Neo Engine API
if (flowNode.$attrs && flowNode.$attrs['proceed:external']) {
instance.updateToken(tokenId, { currentFlowNodeIsExternal: true });
return false;
}
if (flowNode.$type === 'bpmn:UserTask') {
await onUserTask(engine, instance, tokenId, flowNode);
}
if (flowNode.$type === 'bpmn:CallActivity') {
await onCallActivity(engine, Engine, instance, tokenId, flowNode);
}
return true;
};
},
};