ProcessManager = function (options){ var self = this; options = options || {}; self._processCache = {}; self._initialized = true; self._initialising = false; self._initializationError = null; self._definitionsToInitialize = []; self._initialiseCallbacks = []; self._persistency = null; if (options.persistencyOptions) { self._persistency = new Persistency(options.persistencyOptions); self._doneLoadingHandler = options.persistencyOptions.doneLoading; self._doneSavingHandler = options.persistencyOptions.doneSaving; } self._processHandlers = {}; self._processDefinitions = {}; if(!options.handlerFilePath){ options.handlerFilePath = []; } if(!util.isArray(options.handlerFilePath)){ options.handlerFilePath = [options.handlerFilePath]; } options.handlerFilePath.forEach(function(handlerDescriptor){ if(!handlerDescriptor.name || !handlerDescriptor.filePath){ throw new Error("handlerFilePath needs a name and a filePath"); } self.addHandlerFilePath(handlerDescriptor.name, handlerDescriptor.filePath); }); if(!options.handler){ options.handler = []; } if(!util.isArray(options.handler)){ options.handler = [options.handler]; } options.handler.forEach(function(handlerDescriptor){ if(!handlerDescriptor.name || !handlerDescriptor.module){ throw new Error("handler needs a name and a module"); } self.addHandler(handlerDescriptor.name, handlerDescriptor.module); }); if(!options.handlerString){ options.handlerString = []; } if(!util.isArray(options.handlerString)){ options.handlerString = [options.handlerString]; } options.handlerString.forEach(function(handlerString){ if(!handlerString.name || !handlerString.string){ throw new Error("handlerString needs a name and a string"); } self.addHandlerString(handlerString.name, handlerString.string); }); if(!options.bpmnFilePath){ options.bpmnFilePath = []; } if(!util.isArray(options.bpmnFilePath)){ options.bpmnFilePath = [options.bpmnFilePath]; } options.bpmnFilePath.forEach(function(filePath){ self.addBpmnFilePath(filePath); }); if(!options.bpmnXML){ options.bpmnXML = []; } if(!util.isArray(options.bpmnXML)){ options.bpmnXML = [options.bpmnXML]; } options.bpmnXML.forEach(function(bpmnXML){ if(!bpmnXML.name || !bpmnXML.xml){ throw new Error("bpmnXML needs a name and a xml"); } self.addBpmnXML(bpmnXML.xml, bpmnXML.name); }); }
...
bpmnProcess.removeLogTransport(winston.transports.File);
Managing processes
==================
Process managers are used to create multiple processes using the same definitions and find them back later.
var manager = new bpmn.ProcessManager();
manager.addBpmnFilePath("path/to/myProcess.bpmn");
manager.createProcess("myId", function(err, myProcess){
// we start the process
myProcess.triggerEvent("MyStart");
...
clearCache = function () { definitions.clearCache(); }
...
var ProcessManager = require('./manager').ProcessManager;
module.exports = exports = new ProcessManager();
exports.ProcessManager = ProcessManager;
exports.clearCache = function() {
definitions.clearCache();
};
exports.logLevels = logger.logLevels;
/**
* A BPMN process is created.
*
...
createUnmanagedCollaboratingProcesses = function (bpmnFilePath, callback) { var processes = {}; var processDefinitions = definitions.getBPMNProcessDefinitions(bpmnFilePath); var handler = handlers.getHandlerFromFile(bpmnFilePath); async.eachSeries(processDefinitions, function(processDefinition, done) { bpmnProcesses.createBPMNProcess(null, processDefinition, handler, function(err, bpmnProcess){ if(err){ done(err); } processes[processDefinition.name] = bpmnProcess; done(); }); }, function(err){ var clients = []; Object.keys(processes).forEach(function(name){ var bpmnProcess = processes[name]; var participants = bpmnProcess.getProcessDefinition().getCollaboratingParticipants(); participants.forEach(function (participant) { bpmnProcess.addParticipant(participant.name, processes[participant.name]); }); clients.push(bpmnProcess.processClient); }); callback(err, clients); }); }
...
BPMN also supports collaborating processes as depicted below.

These processes must be created together:
// create collaborating processes
bpmn.createUnmanagedCollaboratingProcesses("my/collaboration/example.bpmn",
function(err, collaboratingProcesses){
// start the second process
var secondProcess = collaboratingProcesses[1];
secondProcess.triggerEvent("Start Event 2");
});
...
createUnmanagedCollaboratingProcessesFromXML = function (bpmnXML, handler, callback) { var processes = {}; var processDefinitions = definitions.getBPMNDefinitionsFromXML(bpmnXML); if(typeof handler === 'string'){ handler = handlers.getHandlerFromString(handler); } async.eachSeries(processDefinitions, function(processDefinition, done) { bpmnProcesses.createBPMNProcess(null, processDefinition, handler, function(err, bpmnProcess){ if(err){ done(err); } processes[processDefinition.name] = bpmnProcess; done(); }); }, function(err){ var clients = []; Object.keys(processes).forEach(function(name){ var bpmnProcess = processes[name]; var participants = bpmnProcess.getProcessDefinition().getCollaboratingParticipants(); participants.forEach(function (participant) { bpmnProcess.addParticipant(participant.name, processes[participant.name]); }); clients.push(bpmnProcess.processClient); }); callback(err, clients); }); }
n/a
createUnmanagedProcess = function (bpmnFilePath, callback) { var processDefinition, error; var processDefinitions = definitions.getBPMNProcessDefinitions(bpmnFilePath); var handler = handlers.getHandlerFromFile(bpmnFilePath); if (processDefinitions.length === 1) { processDefinition = processDefinitions[0]; } else { error = new Error("The BPMN file '" + bpmnFilePath + "'. contains more than one process definition. Use 'createCollaboratingProcesses ' instead of 'createProcess'"); if(!callback) { throw error; } else { callback(error); } } bpmnProcesses.createBPMNProcess(null, processDefinition, handler, function(err, bpmnProcess){ if(!callback){ return; } callback(err, bpmnProcess.processClient); }); }
...

then this process can be created by
var bpmn = require("bpmn");
// We assume there is a myProcess.js besides myProcess.bpmn that contains the handlers
bpmn.createUnmanagedProcess("path/to/myProcess.bpmn", function(err, myProcess
){
// we start the process
myProcess.triggerEvent("MyStart");
});
The handler file looks like:
...
createUnmanagedProcessFromXML = function (bpmnXML, handler, callback) { var processDefinition, error; var processDefinitions = definitions.getBPMNDefinitionsFromXML(bpmnXML, "Standalone"); if (processDefinitions.length === 1) { processDefinition = processDefinitions[0]; } else { error = new Error("The BPMN XML contains more than one process definition. Use 'createCollaboratingProcesses' instead of 'createProcess'"); return callback(error); } if(typeof handler === 'string') { handler = handlers.getHandlerFromString(handler); } bpmnProcesses.createBPMNProcess(null, processDefinition, handler, function(err, bpmnProcess){ callback(err, bpmnProcess.processClient); }); }
...
// Called after MyEnd has been reached
done(data);
};
Processes can also be created from an xml string instead of file. In this case the handler can be an object or a javascript string
that would be parsed.
bpmn.createUnmanagedProcessFromXML("<definitions ... </definitions>
;", "exports.MyStart = ...", function(err, myProcess){
// we start the process
myProcess.triggerEvent("MyStart");
});
...
getBPMNDefinitions = function (bpmnFilePath, cache) { var bpmnDefinitions = null; if (cache) { bpmnDefinitions = definitions.getCachedBPMNDefinitions(bpmnFilePath); } else { bpmnDefinitions = definitions.getBPMNDefinitions(bpmnFilePath); } return bpmnDefinitions; }
n/a
mapName2HandlerName = function (bpmnName) { return handlers.mapName2HandlerName(bpmnName); }
...
* @private
*/
BPMNProcess.prototype._registerActivityEndEvents = function() {
var self = this;
self.on(ACTIVITY_END_EVENT, function(activityName, data) {
var currentToken, owningProcessId, currentProcess, currentFlowObject, activityEndHandlerIsDone;
var handlerName = handler.mapName2HandlerName(activityName) + activityEndHandlerPostfix
;
var trx = self.currentTrx = null;
if(self.transactionLogger){
trx = self.currentTrx = self.transactionLogger.startTransaction(self.processDefinition.name, 'PSTATE', 'TRANSITION
', null, activityName+'Done');
}
if (self.state.hasTokens(activityName)) {
...
ProcessManager = function (options){ var self = this; options = options || {}; self._processCache = {}; self._initialized = true; self._initialising = false; self._initializationError = null; self._definitionsToInitialize = []; self._initialiseCallbacks = []; self._persistency = null; if (options.persistencyOptions) { self._persistency = new Persistency(options.persistencyOptions); self._doneLoadingHandler = options.persistencyOptions.doneLoading; self._doneSavingHandler = options.persistencyOptions.doneSaving; } self._processHandlers = {}; self._processDefinitions = {}; if(!options.handlerFilePath){ options.handlerFilePath = []; } if(!util.isArray(options.handlerFilePath)){ options.handlerFilePath = [options.handlerFilePath]; } options.handlerFilePath.forEach(function(handlerDescriptor){ if(!handlerDescriptor.name || !handlerDescriptor.filePath){ throw new Error("handlerFilePath needs a name and a filePath"); } self.addHandlerFilePath(handlerDescriptor.name, handlerDescriptor.filePath); }); if(!options.handler){ options.handler = []; } if(!util.isArray(options.handler)){ options.handler = [options.handler]; } options.handler.forEach(function(handlerDescriptor){ if(!handlerDescriptor.name || !handlerDescriptor.module){ throw new Error("handler needs a name and a module"); } self.addHandler(handlerDescriptor.name, handlerDescriptor.module); }); if(!options.handlerString){ options.handlerString = []; } if(!util.isArray(options.handlerString)){ options.handlerString = [options.handlerString]; } options.handlerString.forEach(function(handlerString){ if(!handlerString.name || !handlerString.string){ throw new Error("handlerString needs a name and a string"); } self.addHandlerString(handlerString.name, handlerString.string); }); if(!options.bpmnFilePath){ options.bpmnFilePath = []; } if(!util.isArray(options.bpmnFilePath)){ options.bpmnFilePath = [options.bpmnFilePath]; } options.bpmnFilePath.forEach(function(filePath){ self.addBpmnFilePath(filePath); }); if(!options.bpmnXML){ options.bpmnXML = []; } if(!util.isArray(options.bpmnXML)){ options.bpmnXML = [options.bpmnXML]; } options.bpmnXML.forEach(function(bpmnXML){ if(!bpmnXML.name || !bpmnXML.xml){ throw new Error("bpmnXML needs a name and a xml"); } self.addBpmnXML(bpmnXML.xml, bpmnXML.name); }); }
...
bpmnProcess.removeLogTransport(winston.transports.File);
Managing processes
==================
Process managers are used to create multiple processes using the same definitions and find them back later.
var manager = new bpmn.ProcessManager();
manager.addBpmnFilePath("path/to/myProcess.bpmn");
manager.createProcess("myId", function(err, myProcess){
// we start the process
myProcess.triggerEvent("MyStart");
...
_afterInitialization = function (callback){ if(this._initialized){ return callback(this._initializationError); } this._initialiseCallbacks.push(callback); }
...
/**
* @param {String} processId
* @param {Function} callback
*/
ProcessManager.prototype.get = function get(processId, callback) {
var self = this;
this._afterInitialization(function(err){
if(callback){
callback(err, self._processCache[processId]);
}
});
};
/**
...
_createCollaboratingProcesses = function (processDescriptors, callback) { var self = this; var processes = {}; async.eachSeries(processDescriptors, function(processDescriptor, done) { self._createSingleProcess(processDescriptor.id, processDescriptor.name, function(err, bpmnProcess){ if(err){ done(err); } processes[processDescriptor.name] = bpmnProcess; done(); }); }, function(err){ var results = []; Object.keys(processes).forEach(function(name){ var bpmnProcess = processes[name]; var participants = bpmnProcess.getProcessDefinition().getCollaboratingParticipants(); participants.forEach(function (participant) { bpmnProcess.addParticipant(participant.name, processes[participant.name]); }); results.push(bpmnProcess); }); callback(err, results); }); }
...
err = new Error('id already used');
}
});
if(err){
return callback(err);
}
self._createCollaboratingProcesses(descriptors, function(err, bpmnProcesses
){
if(err){
return callback(err);
}
descriptors.forEach(function(descriptor){ // check if one of the ids is already used
if(self._processCache[descriptor.id]){ // again because a process could have been created in between
err = new Error('id already used');
...
_createSingleProcess = function (processId, processName, callback){ createBPMNProcess(processId, this._processDefinitions[processName], this._processHandlers[processName], this._persistency, function (err, bpmnProcess){ callback(err, bpmnProcess); }); }
...
return;
}
self._processDefinitions[currentDefinition.name] = currentDefinition;
async.each(documents, function(document, done){ // for each
persisted document found
self._createSingleProcess(document.processId, currentDefinition.name,
function(err, bpmnProcess){ // create the process
if(err){
return done(err);
}
if(self._processCache[bpmnProcess.getProcessId()]){ // check if id already used
return done(new Error('duplicated id in persisted data'));
}
...
_getAllProcesses = function (callback) { var self = this; var allProcessIds = Object.keys(this._processCache); if(!callback){ return; } callback(null, allProcessIds.map(function(loadedProcessId) { return self._processCache[loadedProcessId]; })); }
...
this._afterInitialization(function(err){
if (err) {
return callback(err);
}
self._getAllProcesses(function (err, bpmnProcesses) {
if (err) {
return callback(err);
}
callback(null, bpmnProcesses.map(function (bpmnProcess) {
return bpmnProcess.processClient;
}));
...
_initialiseDefinition = function (processDefinition){ var self = this; self._initializationError = null; self._initialized = false; self._definitionsToInitialize.push(processDefinition); if(!self._initialising){ // if already initialising we don't call next, the definition will be initialised after current one. next(); } /** * Called after all initializations are done. * @param err */ function execCallbacks(err){ self._definitionsToInitialize = []; self._initializationError = err; self._initialized = true; self._initialising = false; self._initialiseCallbacks.forEach(function(callback){ // call all waiting callbacks callback(err); }); } function next(){ self._initialising = true; if(self._definitionsToInitialize.length === 0){ // if all definitions have been initialized return execCallbacks(); } var currentDefinition = self._definitionsToInitialize.pop(); // get the next definition if(self._processDefinitions[currentDefinition.name] || // if the definition already exist it means the processes were already loaded !self._persistency){ // if there is no persistency nothing needs to be loaded self._processDefinitions[currentDefinition.name] = currentDefinition; // we simply add or replace the definition return next(); } self._persistency.loadAll(currentDefinition.name, function(err, documents){ // load all saved document if(err){ execCallbacks(err); return; } self._processDefinitions[currentDefinition.name] = currentDefinition; async.each(documents, function(document, done){ // for each persisted document found self._createSingleProcess(document.processId, currentDefinition.name, function(err, bpmnProcess){ // create the process if(err){ return done(err); } if(self._processCache[bpmnProcess.getProcessId()]){ // check if id already used return done(new Error('duplicated id in persisted data')); } self._processCache[bpmnProcess.getProcessId()] = bpmnProcess; done(); }); }, function(err){ if(err){ return execCallbacks(err); } next(); }); }); } }
...
if(processHandler) {
self._processHandlers[processDefinition.name] = processHandler;
} else if(!self._processHandlers[processDefinition.name]){
throw new Error('No process handler defined for process "'+processDefinition.name+'". The process
handler must be defined before the process or with the process.');
}
self._initialiseDefinition(processDefinition);
});
};
/**
* Add a bpmn XML to the manager.
* All process definition found in this file will be initialized and replace the old ones if exists.
* A process handler object or file path can be passed. If none passed the same file path as the bpmn is used or the existing handler
.
...
addBpmnFilePath = function (bpmnFilePath, processHandler){ var self = this; var processDefinitions; if(typeof processHandler === 'string'){ processHandler = handlers.getHandlerFromFile(processHandler); } if(!processHandler){ try{ processHandler = handlers.getHandlerFromFile(bpmnFilePath); processHandler.doneLoadingHandler = self._doneLoadingHandler; processHandler.doneSavingHandler = self._doneSavingHandler; }catch(err){} } processDefinitions = definitions.getBPMNProcessDefinitions(bpmnFilePath); processDefinitions.forEach(function(processDefinition){ if(processHandler) { self._processHandlers[processDefinition.name] = processHandler; } else if(!self._processHandlers[processDefinition.name]){ throw new Error('No process handler defined for process "'+processDefinition.name+'". The process handler must be defined before the process or with the process.'); } self._initialiseDefinition(processDefinition); }); }
...
Managing processes
==================
Process managers are used to create multiple processes using the same definitions and find them back later.
var manager = new bpmn.ProcessManager();
manager.addBpmnFilePath("path/to/myProcess.bpmn");
manager.createProcess("myId", function(err, myProcess){
// we start the process
myProcess.triggerEvent("MyStart");
});
...
addBpmnXML = function (bpmnXml, processName, processHandler){ var self = this; var processDefinitions; if(typeof processHandler === 'string'){ processHandler = handlers.getHandlerFromString(processHandler); } processDefinitions = definitions.getBPMNDefinitionsFromXML(bpmnXml, processName); processDefinitions.forEach(function(processDefinition){ if(processHandler) { self._processHandlers[processDefinition.name] = processHandler; } else if(!self._processHandlers[processDefinition.name]){ throw new Error('No process handler defined for process "'+processDefinition.name+'". The process handler must be defined before the process or with the process.'); } self._initialiseDefinition(processDefinition); }); }
...
}
options.bpmnXML.forEach(function(bpmnXML){
if(!bpmnXML.name || !bpmnXML.xml){
throw new Error("bpmnXML needs a name and a xml");
}
self.addBpmnXML(bpmnXML.xml, bpmnXML.name);
});
};
/**
* Initialise a new definition by loading all persisted process.
* All other function that need the initialise state will wait until initialization is done.
*
...
addHandler = function (name, handler){ this._processHandlers[name] = handler; this._processHandlers[name].doneLoadingHandler = this._doneLoadingHandler || this._processHandlers[name].doneLoadingHandler; this._processHandlers[name].doneSavingHandler = this._doneSavingHandler || this._processHandlers[name].doneSavingHandler; }
...
}
options.handler.forEach(function(handlerDescriptor){
if(!handlerDescriptor.name || !handlerDescriptor.module){
throw new Error("handler needs a name and a module");
}
self.addHandler(handlerDescriptor.name, handlerDescriptor.module);
});
if(!options.handlerString){
options.handlerString = [];
}
if(!util.isArray(options.handlerString)){
...
addHandlerFilePath = function (name, handlerFilePath){ this._processHandlers[name] = handlers.getHandlerFromFile(handlerFilePath); this._processHandlers[name].doneLoadingHandler = this._doneLoadingHandler || this._processHandlers[name].doneLoadingHandler; this._processHandlers[name].doneSavingHandler = this._doneSavingHandler || this._processHandlers[name].doneSavingHandler; }
...
var manager = new bpmn.ProcessManager({
bpmnFilePath: "path/to/myProcess.bpmn"
});
ProcessManager.addHandlerFilePath(name, handlerFilePath)
- **name**: The name of the process definition for which the handler will be used.
- **handlerFilePath**: Path to the javascript file defining the handler module.
ProcessManager.addHandlerString = function(name, handlerString)
- **name**: The name of the process definition for which the handler will be used.
...
addHandlerString = function (name, handlerString){ this._processHandlers[name] = handlers.getHandlerFromString(handlerString); this._processHandlers[name].doneLoadingHandler = this._doneLoadingHandler || this._processHandlers[name].doneLoadingHandler; this._processHandlers[name].doneSavingHandler = this._doneSavingHandler || this._processHandlers[name].doneSavingHandler; }
...
}
options.handlerString.forEach(function(handlerString){
if(!handlerString.name || !handlerString.string){
throw new Error("handlerString needs a name and a string");
}
self.addHandlerString(handlerString.name, handlerString.string);
});
if(!options.bpmnFilePath){
options.bpmnFilePath = [];
}
...
createProcess = function (descriptors, callback) { var self = this; this._afterInitialization(function(err){ if(err){ return callback(err); } if (typeof descriptors === 'string' && Object.keys(self._processDefinitions).length !== 1) { return callback(new Error("The manager contains more than one process definition. " + "processId have to be an Array.<{name: String, id: String}>} ")); } if(util.isArray(descriptors)) { descriptors.forEach(function(descriptor){ // check if one of the ids is already used if(self._processCache[descriptor.id]){ err = new Error('id already used'); } }); if(err){ return callback(err); } self._createCollaboratingProcesses(descriptors, function(err, bpmnProcesses){ if(err){ return callback(err); } descriptors.forEach(function(descriptor){ // check if one of the ids is already used if(self._processCache[descriptor.id]){ // again because a process could have been created in between err = new Error('id already used'); } }); if(err){ return callback(err); } callback(null, bpmnProcesses.map(function(bpmnProcess){ self._processCache[bpmnProcess.getProcessId()] = bpmnProcess; return bpmnProcess.processClient; })); }); return; } if(typeof descriptors === 'string') { descriptors = { id: descriptors, name: Object.keys(self._processDefinitions)[0] }; } if(self._processCache[descriptors.id]){ // check if id already used return callback(new Error('id already used')); } self._createSingleProcess(descriptors.id, descriptors.name, function(err, bpmnProcess){ if(err){ return callback(err); } if(self._processCache[descriptors.id]){ // check if id already used return callback(new Error('id already used')); // again because a process could have been created in between } self._processCache[descriptors.id] = bpmnProcess; callback(null, bpmnProcess.processClient); }); }); }
...
Process managers are used to create multiple processes using the same definitions and find them back later.
var manager = new bpmn.ProcessManager();
manager.addBpmnFilePath("path/to/myProcess.bpmn");
manager.createProcess("myId", function(err, myProcess){
// we start the process
myProcess.triggerEvent("MyStart");
});
If the process id is already used an error is returned.
...
createServer = function (options, restifyOptions){ return rest.createServer(this, options, restifyOptions); }
...
Server
------
The above API can also be called by REST HTTP calls. To do this, you have first to instantiate a server from ta manager. For example
:
// Returns a restify server.
var server = manager.createServer();
server.listen(9009, function() {
console.log('%s listening at %s', server.name, server.url);
});
The server is a node restify server. So all features of this package can be used.
The full signature of `createProcess` is
...
findByName = function (processName, caseSensitive, callback) { var self = this; if(typeof caseSensitive === 'function'){ callback = caseSensitive; caseSensitive = true; } if(!callback){ return; } this._afterInitialization(function(err){ if (err) { return callback(err); } self.getAllProcesses(function (err, bpmnProcesses) { if (err) { return callback(err); } callback(null, find.findByName(bpmnProcesses, processName, caseSensitive)); }); }); }
...
// returns all processes in this state (callActivity, tasks, event, ...)
bpmn.findByState(stateName, function(err, processes){
...
});
// returns all processes using this definition
bpmn.findByName(definitionName, function(err, processes){
...
});
Persistency
-----------
...
findByProperty = function (query, callback) { var self = this; if(!callback){ return; } this._afterInitialization(function(err){ if (err) { return callback(err); } self.getAllProcesses(function (err, bpmnProcesses) { if (err) { return callback(err); } callback(null, find.findByProperty(bpmnProcesses, query)); }); }); }
...
// returns all processes
bpmn.getAllProcesses(function(err, processes){
...
});
// returns all processes having the property names
bpmn.findByProperty({propName1: propValue1, propName2: propValue2, ...}, function(err
, processes){
...
});
// returns all processes in this state (callActivity, tasks, event, ...)
bpmn.findByState(stateName, function(err, processes){
...
});
...
findByState = function (stateName, callback) { var self = this; if(!callback){ return; } this._afterInitialization(function(err){ if (err) { return callback(err); } self.getAllProcesses(function (err, bpmnProcesses) { if (err) { return callback(err); } callback(null, find.findByState(bpmnProcesses, stateName)); }); }); }
...
// returns all processes having the property names
bpmn.findByProperty({propName1: propValue1, propName2: propValue2, ...}, function(err, processes){
...
});
// returns all processes in this state (callActivity, tasks, event, ...)
bpmn.findByState(stateName, function(err, processes){
...
});
// returns all processes using this definition
bpmn.findByName(definitionName, function(err, processes){
...
});
...
function get(processId, callback) { var self = this; this._afterInitialization(function(err){ if(callback){ callback(err, self._processCache[processId]); } }); }
...
Finding processes
-----------------
Existing processes in a manager can be retrived using these functions:
// returns the process with the corresponding id
bpmn.get(processId, function(err, process){
...
});
// returns all processes
bpmn.getAllProcesses(function(err, processes){
...
});
...
getAllProcesses = function (callback) { var self = this; if(!callback){ return; } this._afterInitialization(function(err){ if (err) { return callback(err); } self._getAllProcesses(function (err, bpmnProcesses) { if (err) { return callback(err); } callback(null, bpmnProcesses.map(function (bpmnProcess) { return bpmnProcess.processClient; })); }); }); }
...
// returns the process with the corresponding id
bpmn.get(processId, function(err, process){
...
});
// returns all processes
bpmn.getAllProcesses(function(err, processes){
...
});
// returns all processes having the property names
bpmn.findByProperty({propName1: propValue1, propName2: propValue2, ...}, function(err, processes){
...
});
...
getDefinitionNames = function (callback){ var self = this; this._afterInitialization(function(err){ callback(err, Object.keys(self._processDefinitions)); }); }
...
* @param {ProcessManager} manager
* @param {String} name
* @param {Function} callback
* @returns {*}
*/
function getNameWithCase(manager, name, callback){
manager.getDefinitionNames(function(err, names){
if(err){
return callback(err);
}
var ret = null;
names.forEach(function(nameWithCase){
...
BPMNActivity = function (bpmnId, name, type) { BPMNFlowObject.call(this, bpmnId, name, type); this.isActivity = true; }
n/a
BPMNBoundaryEvent = function (bpmnId, name, type, attachedToRef) { BPMNFlowObject.call(this, bpmnId, name, type); this.isBoundaryEvent = true; this.attachedToRef = attachedToRef; }
n/a
createBPMNBoundaryEvent = function (node) { var getValue = parserUtils.getAttributesValue; return (new BPMNBoundaryEvent( getValue(node, "id"), getValue(node, "name"), node.local, getValue(node, "attachedToRef") )); }
...
} else if (sequenceFlows.isSequenceFlowName(localName)) {
currentProcessElement = sequenceFlows.createBPMNSequenceFlow(node);
currentProcessDefinition.addSequenceFlow(currentProcessElement);
} else if (startEvents.isStartEventName(localName)) {
currentProcessElement = startEvents.createBPMNStartEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (boundaryEvents.isBoundaryEventName(localName)) {
currentProcessElement = boundaryEvents.createBPMNBoundaryEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (boundaryEvents.isTimerEventName(localName)) {
currentProcessElement.isTimerEvent = true;
} else if (endEvents.isEndEventName(localName)) {
currentProcessElement = endEvents.createBPMNEndEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (gateways.isGatewayName(localName)) {
...
isBoundaryEventName = function (localName) { return (localName === "boundaryEvent"); }
...
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (sequenceFlows.isSequenceFlowName(localName)) {
currentProcessElement = sequenceFlows.createBPMNSequenceFlow(node);
currentProcessDefinition.addSequenceFlow(currentProcessElement);
} else if (startEvents.isStartEventName(localName)) {
currentProcessElement = startEvents.createBPMNStartEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (boundaryEvents.isBoundaryEventName(localName)) {
currentProcessElement = boundaryEvents.createBPMNBoundaryEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (boundaryEvents.isTimerEventName(localName)) {
currentProcessElement.isTimerEvent = true;
} else if (endEvents.isEndEventName(localName)) {
currentProcessElement = endEvents.createBPMNEndEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
...
isTimerEventName = function (localName) { return (localName === "timerEventDefinition"); }
...
currentProcessDefinition.addSequenceFlow(currentProcessElement);
} else if (startEvents.isStartEventName(localName)) {
currentProcessElement = startEvents.createBPMNStartEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (boundaryEvents.isBoundaryEventName(localName)) {
currentProcessElement = boundaryEvents.createBPMNBoundaryEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (boundaryEvents.isTimerEventName(localName)) {
currentProcessElement.isTimerEvent = true;
} else if (endEvents.isEndEventName(localName)) {
currentProcessElement = endEvents.createBPMNEndEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (gateways.isGatewayName(localName)) {
currentProcessElement = gateways.createBPMNGateway(node, errorQueue);
currentProcessDefinition.addFlowObject(currentProcessElement);
...
createLogger = function (log) { return bunyan.createLogger({ name: 'bpmnRESTServer', streams: [{ type: 'raw', level: 'trace', stream: new Bunyan2Winston(log) }] }); }
...
logger = new log.Logger(null, settings);
serverOptions = restifyOptions || {};
serverOptions.name = serverOptions.name || "BPMNProcessServer";
// Shimming the log doesn't work as expected: I cannot switch it off for example.
// Additionally, the log format is horrible. So for the time being we use our own logging
// serverOptions.log = serverOptions.log || bunyan2winston.createLogger(logger.winstonLogger
);
server = restify.createServer(serverOptions);
server.use(restify.queryParser({ mapParams: false }));
server.use(restify.bodyParser({ mapParams: false }));
server.on('after', function( request, response, route, error) {
var handler = options.onServerAfterEvent || onServerAfterEvent;
...
BPMNCallActivity = function (bpmnId, name, type, calledElementName, calledElementNamespace, location) { BPMNActivity.call(this, bpmnId, name, type); this.isCallActivity = true; this.calledElementName = calledElementName; this.calledElementNamespace = calledElementNamespace; this.location = location; }
n/a
createBPMNCallActivity = function (node, baseFileName, prefix2NamespaceMap, importNamespace2LocationMap) { var getValue = parserUtils.getAttributesValue; var calledElement = getValue(node, "calledElement"); var splitName = parserUtils.splitPrefixedName(calledElement); var calledElementName = splitName.localName; var calledElementNamespace = prefix2NamespaceMap[splitName.prefix]; var relativeLocation = importNamespace2LocationMap[calledElementNamespace]; var location = relativeLocation ? path.join(path.dirname(baseFileName), relativeLocation) : ""; return (new BPMNCallActivity( getValue(node, "id"), getValue(node, "name"), node.local, calledElementName, calledElementNamespace, location )); }
...
} else if (endEvents.isEndEventName(localName)) {
currentProcessElement = endEvents.createBPMNEndEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (gateways.isGatewayName(localName)) {
currentProcessElement = gateways.createBPMNGateway(node, errorQueue);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (callActivity.isCallActivityName(localName)) {
currentProcessElement = callActivity.createBPMNCallActivity(node, fileName, prefix2NamespaceMap
, importNamespace2LocationMap);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (intermediateEvents.isIntermediateThrowEventName(localName)) {
currentProcessElement = intermediateEvents.createBPMNIntermediateThrowEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (intermediateEvents.isIntermediateCatchEventName(localName)) {
currentProcessElement = intermediateEvents.createBPMNIntermediateCatchEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
...
isCallActivityName = function (localName) { return (localName.toLowerCase().indexOf("call") > -1); }
...
currentProcessElement.isTimerEvent = true;
} else if (endEvents.isEndEventName(localName)) {
currentProcessElement = endEvents.createBPMNEndEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (gateways.isGatewayName(localName)) {
currentProcessElement = gateways.createBPMNGateway(node, errorQueue);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (callActivity.isCallActivityName(localName)) {
currentProcessElement = callActivity.createBPMNCallActivity(node, fileName, prefix2NamespaceMap, importNamespace2LocationMap
);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (intermediateEvents.isIntermediateThrowEventName(localName)) {
currentProcessElement = intermediateEvents.createBPMNIntermediateThrowEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (intermediateEvents.isIntermediateCatchEventName(localName)) {
currentProcessElement = intermediateEvents.createBPMNIntermediateCatchEvent(node);
...
BPMNProcessClient = function (bpmnProcess) { this._implementation = bpmnProcess; }
n/a
BPMNCollaborationDefinition = function (bpmnId) { this.bpmnId = bpmnId; this.participants = []; this.messageFlows = []; this.isCollaborationDefinition = true; }
n/a
createBPMNCollaborationDefinition = function (node) { var getValue = parserUtils.getAttributesValue; return (new BPMNCollaborationDefinition(getValue(node, "id"))); }
...
if (!debuggerInterface && debug.isDebuggerElement(node) && fileName) {
debuggerInterface = debug.createDebuggerInterface(node, fileName);
}
if (inBPMN2Namespace) {
if (collaborationDefinition.isCollaborationDefinitionName(localName)) {
currentCollaborationDefinition = collaborationDefinition.createBPMNCollaborationDefinition
(node);
topLevelDefinitions.push(currentCollaborationDefinition);
currentProcessDefinition = null;
}
if (currentCollaborationDefinition) {
if (messageFlows.isMessageFlowName(localName)) {
currentCollaborationElement = messageFlows.createBPMNMessageFlow(node);
...
isCollaborationDefinitionName = function (localName) { return (localName === "collaboration"); }
...
if (!debuggerInterface && debug.isDebuggerElement(node) && fileName) {
debuggerInterface = debug.createDebuggerInterface(node, fileName);
}
if (inBPMN2Namespace) {
if (collaborationDefinition.isCollaborationDefinitionName(localName)) {
currentCollaborationDefinition = collaborationDefinition.createBPMNCollaborationDefinition(node);
topLevelDefinitions.push(currentCollaborationDefinition);
currentProcessDefinition = null;
}
if (currentCollaborationDefinition) {
if (messageFlows.isMessageFlowName(localName)) {
...
DebuggerInterface = function (url, fileName) { this.fileName = fileName; this.url = urls.parse(url); }
n/a
createDebuggerInterface = function (node, fileName) { return (new DebuggerInterface(parserUtils.getAttributesValue(node, "href"), fileName)); }
...
parser.onopentag = function (node) {
var localName = node.local;
var inBPMN2Namespace = node.uri === BPMN2NAMESPACE;
addNamespaces(prefix2NamespaceMap, node);
if (!debuggerInterface && debug.isDebuggerElement(node) && fileName) {
debuggerInterface = debug.createDebuggerInterface(node, fileName);
}
if (inBPMN2Namespace) {
if (collaborationDefinition.isCollaborationDefinitionName(localName)) {
currentCollaborationDefinition = collaborationDefinition.createBPMNCollaborationDefinition(node);
topLevelDefinitions.push(currentCollaborationDefinition);
...
isDebuggerElement = function (node) { return (node.uri === 'http://e2e.ch/bpmneditor/debugger' && node.local === 'position'); }
...
parser.onopentag = function (node) {
var localName = node.local;
var inBPMN2Namespace = node.uri === BPMN2NAMESPACE;
addNamespaces(prefix2NamespaceMap, node);
if (!debuggerInterface && debug.isDebuggerElement(node) &&
; fileName) {
debuggerInterface = debug.createDebuggerInterface(node, fileName);
}
if (inBPMN2Namespace) {
if (collaborationDefinition.isCollaborationDefinitionName(localName)) {
currentCollaborationDefinition = collaborationDefinition.createBPMNCollaborationDefinition(node);
...
clearCache = function () { bpmnDefinitionsCache = {}; }
...
var ProcessManager = require('./manager').ProcessManager;
module.exports = exports = new ProcessManager();
exports.ProcessManager = ProcessManager;
exports.clearCache = function() {
definitions.clearCache();
};
exports.logLevels = logger.logLevels;
/**
* A BPMN process is created.
*
...
getBPMNCollaborationDefinitions = function (bpmnFilePath) { var bpmnDefinitions = getCachedBPMNDefinitions(bpmnFilePath); return getCollaborationDefinitions(bpmnDefinitions); }
...
test.done();
};
exports.testGetAllBPMNCollaborationDefinitions = function(test) {
var fileName = path.join(__dirname, "../../resources/bpmn/pool.bpmn");
bpmnDefinitions.clearCache();
var collaborationDefinitions = bpmnDefinitions.getBPMNCollaborationDefinitions(fileName
);
test.deepEqual(collaborationDefinitions,
[
{
"bpmnId": "COLLABORATION_1",
"participants": [
{
...
function getBPMNDefinitions(bpmnFilePath) { var errorQueue = errors.createBPMNParseErrorQueue(); var bpmnDefinitions, bpmnXML; try { bpmnXML = fs.readFileSync(bpmnFilePath, "utf8"); bpmnDefinitions = parser.parse(bpmnXML, errorQueue, utils.toUpperCamelCase(fileUtils.removeFileExtension(path.basename(bpmnFilePath ))), bpmnFilePath); } catch (e) { errorQueue.addError("DF1", null, "Could not parse the BPMN file '" + bpmnFilePath + "'. Error: '" + e + "'"); } errorQueue.check(); setCollaborationDefinitions(bpmnDefinitions); return bpmnDefinitions; }
n/a
function getBPMNDefinitionsFromXML(bpmnXML, mainProcessName, bpmnFilePath) { var errorQueue = errors.createBPMNParseErrorQueue(); var bpmnDefinitions; try { bpmnDefinitions = parser.parse(bpmnXML, errorQueue, mainProcessName, bpmnFilePath); } catch (e) { errorQueue.addError("DF1", null, "Could not parse the BPMN XML string'. Error: '" + e + "'"); } errorQueue.check(); setCollaborationDefinitions(bpmnDefinitions); return bpmnDefinitions; }
...
var self = this;
var processDefinitions;
if(typeof processHandler === 'string'){
processHandler = handlers.getHandlerFromString(processHandler);
}
processDefinitions = definitions.getBPMNDefinitionsFromXML(bpmnXml, processName);
processDefinitions.forEach(function(processDefinition){
if(processHandler) {
self._processHandlers[processDefinition.name] = processHandler;
} else if(!self._processHandlers[processDefinition.name]){
throw new Error('No process handler defined for process "'+processDefinition.name+'". The process handler
must be defined before the process or with the process.');
...
getBPMNProcessDefinition = function (bpmnFilePath) { var processDefinition; var processDefinitions = getBPMNProcessDefinitions(bpmnFilePath); if (processDefinitions.length === 1) { processDefinition = processDefinitions[0]; } else { throw new Error("The BPMN file '" + bpmnFilePath + "'. contains more than one process definition. Use 'getBPMNProcessDefinitions ' instead of 'getBPMNProcessDefinition'"); } return processDefinition; }
...
if(typeof calledProcessDefinition === 'function'){
callback = calledProcessDefinition;
calledProcessDefinition = null;
}
var handler = this.getHandler(currentProcess);
var processDefinition = calledProcessDefinition || bpmnDefinitions.getBPMNProcessDefinition(this.location);
var callActivityHistoryEntry = currentProcess.getHistory().getLastEntry(callActivityToken.position);
createBPMNProcess(
callActivityToken.calledProcessId,
processDefinition,
handler,
currentProcess.persistency,
...
getBPMNProcessDefinitions = function (bpmnFilePath) { var bpmnDefinitions = getCachedBPMNDefinitions(bpmnFilePath); return getProcessDefinitions(bpmnDefinitions); }
...
try{
processHandler = handlers.getHandlerFromFile(bpmnFilePath);
processHandler.doneLoadingHandler = self._doneLoadingHandler;
processHandler.doneSavingHandler = self._doneSavingHandler;
}catch(err){}
}
processDefinitions = definitions.getBPMNProcessDefinitions(bpmnFilePath);
processDefinitions.forEach(function(processDefinition){
if(processHandler) {
self._processHandlers[processDefinition.name] = processHandler;
} else if(!self._processHandlers[processDefinition.name]){
throw new Error('No process handler defined for process "'+processDefinition.name+'". The process handler
must be defined before the process or with the process.');
...
function getCachedBPMNDefinitions(bpmnFilePath) { var bpmnDefinitions = bpmnDefinitionsCache[bpmnFilePath]; if (!bpmnDefinitions) { bpmnDefinitions = getBPMNDefinitions(bpmnFilePath); bpmnDefinitionsCache[bpmnFilePath] = bpmnDefinitions; } return bpmnDefinitions; }
...
* @param {String} bpmnFilePath
* @param {Boolean=} cache If true, the definitions are cached.
* @return {Array.<BPMNProcessDefinition|BPMNCollaborationDefinition>}
*/
exports.getBPMNDefinitions = function(bpmnFilePath, cache) {
var bpmnDefinitions = null;
if (cache) {
bpmnDefinitions = definitions.getCachedBPMNDefinitions(bpmnFilePath);
} else {
bpmnDefinitions = definitions.getBPMNDefinitions(bpmnFilePath);
}
return bpmnDefinitions;
};
...
BPMNEndEvent = function (bpmnId, name, type) { BPMNFlowObject.call(this, bpmnId, name, type); this.isEndEvent = true; }
n/a
createBPMNEndEvent = function (node) { var getValue = parserUtils.getAttributesValue; return (new BPMNEndEvent( getValue(node, "id"), getValue(node, "name"), node.local )); }
...
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (boundaryEvents.isBoundaryEventName(localName)) {
currentProcessElement = boundaryEvents.createBPMNBoundaryEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (boundaryEvents.isTimerEventName(localName)) {
currentProcessElement.isTimerEvent = true;
} else if (endEvents.isEndEventName(localName)) {
currentProcessElement = endEvents.createBPMNEndEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (gateways.isGatewayName(localName)) {
currentProcessElement = gateways.createBPMNGateway(node, errorQueue);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (callActivity.isCallActivityName(localName)) {
currentProcessElement = callActivity.createBPMNCallActivity(node, fileName, prefix2NamespaceMap, importNamespace2LocationMap
);
currentProcessDefinition.addFlowObject(currentProcessElement);
...
isEndEventName = function (localName) { return (localName.toLowerCase().indexOf("end") > -1); }
...
/**
* @param {String} flowObjectName
*/
BPMNProcessHistory.prototype.setEnd = function(flowObjectName) {
var historyEntry = this.getLastEntry(flowObjectName);
historyEntry.setEnd();
if (endEvents.isEndEventName(historyEntry.type)) {
this.finishedAt = historyEntry.end;
}
};
BPMNProcessHistory.prototype.isFinished = function() {
if(this.historyEntries.length){
return endEvents.isEndEventName(this.historyEntries[this.historyEntries.length - 1].type)
...
createBPMNParseErrorQueue = function (fileName) { return (new BPMNParseErrorQueue(fileName)); }
...
/**
*
* @param bpmnDefinitions
*/
function setCollaborationDefinitions(bpmnDefinitions){
var collaborationDefinitions = getCollaborationDefinitions(bpmnDefinitions);
var processDefinitions = getProcessDefinitions(bpmnDefinitions);
var errorQueue = errors.createBPMNParseErrorQueue();
processDefinitions.forEach(function(processDefinition) {
processDefinition.validate(errorQueue);
errorQueue.check();
processDefinition.attachCollaborationDefinitions(collaborationDefinitions);
});
}
...
isMessageEventName = function (localName) { return (localName === "messageEventDefinition"); }
...
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (intermediateEvents.isIntermediateThrowEventName(localName)) {
currentProcessElement = intermediateEvents.createBPMNIntermediateThrowEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (intermediateEvents.isIntermediateCatchEventName(localName)) {
currentProcessElement = intermediateEvents.createBPMNIntermediateCatchEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (events.isMessageEventName(localName)) {
currentProcessElement.isMessageEvent = true;
} else if (subProcess.isSubProcessName(localName)) {
subProcessDefinition = processDefinition.createBPMNProcessDefinition(node, errorQueue);
currentProcessElement = subProcess.createBPMNSubProcess(node, subProcessDefinition);
currentProcessDefinition.addFlowObject(currentProcessElement);
processStack.push(currentProcessDefinition);
currentProcessDefinition = subProcessDefinition;
...
Persistency = function (path) { this.path = path; this.db = new JaguarDb(); }
n/a
findByName = function (bpmnProcesses, processName, caseSensitive) { var foundProcesses = []; if (processName) { var compare = function(a, b) { var result; if (caseSensitive === undefined || caseSensitive) { result = (a === b); } else { result = (a.toLowerCase() === b.toLowerCase()); } return result; }; bpmnProcesses.forEach(function(bpmnProcess) { var name = bpmnProcess.getProcessDefinition().name; if (compare(name, processName)) { foundProcesses.push(bpmnProcess.processClient || bpmnProcess); } }); } return foundProcesses; }
...
// returns all processes in this state (callActivity, tasks, event, ...)
bpmn.findByState(stateName, function(err, processes){
...
});
// returns all processes using this definition
bpmn.findByName(definitionName, function(err, processes){
...
});
Persistency
-----------
...
findByProperty = function (bpmnProcesses, query) { var foundProcesses = []; var findAll = !query; bpmnProcesses.forEach(function(bpmnProcess) { if (findAll || hasMatchingProperties(bpmnProcess.getProperties(), query)) { foundProcesses.push(bpmnProcess.processClient || bpmnProcess); } }); return foundProcesses; }
...
// returns all processes
bpmn.getAllProcesses(function(err, processes){
...
});
// returns all processes having the property names
bpmn.findByProperty({propName1: propValue1, propName2: propValue2, ...}, function(err
, processes){
...
});
// returns all processes in this state (callActivity, tasks, event, ...)
bpmn.findByState(stateName, function(err, processes){
...
});
...
findByState = function (bpmnProcesses, stateName) { var foundProcesses = []; var findAll = !stateName; bpmnProcesses.forEach(function(bpmnProcess) { if (findAll || bpmnProcess.getState().hasTokens(stateName)) { foundProcesses.push(bpmnProcess.processClient || bpmnProcess); } }); return foundProcesses; }
...
// returns all processes having the property names
bpmn.findByProperty({propName1: propValue1, propName2: propValue2, ...}, function(err, processes){
...
});
// returns all processes in this state (callActivity, tasks, event, ...)
bpmn.findByState(stateName, function(err, processes){
...
});
// returns all processes using this definition
bpmn.findByName(definitionName, function(err, processes){
...
});
...
BPMNFlowObject = function (bpmnId, name, type) { this.bpmnId = bpmnId; this.name = name; this.type = type; this.isFlowObject = true; }
n/a
BPMNExclusiveGateway = function (bpmnId, name, type) { BPMNFlowObject.call(this, bpmnId, name, type); this.isExclusiveGateway = true; }
n/a
BPMNParallelGateway = function (bpmnId, name, type) { BPMNFlowObject.call(this, bpmnId, name, type); this.isParallelGateway = true; }
n/a
createBPMNGateway = function (node, errorQueue) { var getAttributeValue = parserUtils.getAttributesValue; var gateway = null; var localName = node.local; var name = getAttributeValue(node, "name"); var id = getAttributeValue(node, "id"); if (isExclusiveGatewayName(localName)) { gateway = new BPMNExclusiveGateway(id, name, node.local); } else if (isParallelGatewayName(localName)) { gateway = new BPMNParallelGateway(id, name, node.local); } else { errorQueue.addError("UnsupportedGateway", {bpmnId: id, name: name, type: node.local}, "The gateway '" + name + "' is not supported yet."); } return gateway; }
...
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (boundaryEvents.isTimerEventName(localName)) {
currentProcessElement.isTimerEvent = true;
} else if (endEvents.isEndEventName(localName)) {
currentProcessElement = endEvents.createBPMNEndEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (gateways.isGatewayName(localName)) {
currentProcessElement = gateways.createBPMNGateway(node, errorQueue);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (callActivity.isCallActivityName(localName)) {
currentProcessElement = callActivity.createBPMNCallActivity(node, fileName, prefix2NamespaceMap, importNamespace2LocationMap
);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (intermediateEvents.isIntermediateThrowEventName(localName)) {
currentProcessElement = intermediateEvents.createBPMNIntermediateThrowEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
...
isGatewayName = function (localName) { return (localName.toLowerCase().indexOf("gateway") > -1); }
...
currentProcessElement = boundaryEvents.createBPMNBoundaryEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (boundaryEvents.isTimerEventName(localName)) {
currentProcessElement.isTimerEvent = true;
} else if (endEvents.isEndEventName(localName)) {
currentProcessElement = endEvents.createBPMNEndEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (gateways.isGatewayName(localName)) {
currentProcessElement = gateways.createBPMNGateway(node, errorQueue);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (callActivity.isCallActivityName(localName)) {
currentProcessElement = callActivity.createBPMNCallActivity(node, fileName, prefix2NamespaceMap, importNamespace2LocationMap
);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (intermediateEvents.isIntermediateThrowEventName(localName)) {
currentProcessElement = intermediateEvents.createBPMNIntermediateThrowEvent(node);
...
callHandler = function (name, process, data, handlerDoneCallback) { var result, handlerType; var done = handlerDoneCallback || function() {}; var eventType = "callHandler"; var handler = getHandlerFromProcess(name, process); if (handler) { handlerType = typeof handler; if (handlerType === 'function') { try { result = handler.call(process.processClient, data, done); } catch (error) { process.logger.error("Error in handler '" + name + "': " + error.toString()); process.defaultErrorHandler.call(process.processClient, error, done); } } else if (handlerType === 'object') { // hierarchical handler used for mocking up sub process handlers. See test cases for examples // To keep going we have to call done() done(); } else { process.callDefaultEventHandler(eventType, name, mapName2HandlerName(name), "Unknown handler type: '" + handlerType + "'", done); } } else { process.callDefaultEventHandler(eventType, name, mapName2HandlerName(name), "No handler found", done); } return result; }
...
trx.processStateEnd(self.processDefinition.name, self.getProcessId(), activityName);
trx.end();
}
self.logger.trace("Calling done() of '" + handlerName + "'.");
currentProcess._emitTokens(currentFlowObject, data, true);
};
self.logger.trace("Calling '" + handlerName + "' for " + ACTIVITY_END_EVENT + " '"
; + activityName + "'.");
handler.callHandler(handlerName, currentProcess, data, activityEndHandlerIsDone);
} else {
self.callDefaultEventHandler(ACTIVITY_END_EVENT, activityName, handlerName,
"Process cannot handle this activity because it is not currently executed.",
function(){
if(trx){
trx.end();
}
...
getHandlerFileName = function (bpmnFilePath) { return (fileUtils.removeFileExtension(bpmnFilePath) + ".js"); }
n/a
getHandlerFromFile = function (bpmnFilePath) { var handlerFilePath = getHandlerFileName(bpmnFilePath); return require(handlerFilePath); }
...
/**
* Change the process handler using a file.
*
* @param {String} name Name of the process
* @param {String} handlerFilePath
*/
ProcessManager.prototype.addHandlerFilePath = function(name, handlerFilePath){
this._processHandlers[name] = handlers.getHandlerFromFile(handlerFilePath);
this._processHandlers[name].doneLoadingHandler = this._doneLoadingHandler || this._processHandlers[name].doneLoadingHandler;
this._processHandlers[name].doneSavingHandler = this._doneSavingHandler || this._processHandlers[name].doneSavingHandler;
};
/**
* Change the process handler using a string.
*
...
getHandlerFromProcess = function (name, process) { var handlerName = mapName2HandlerName(name); var handler = process.eventHandler[handlerName]; // this works as long as event names are unique return handler; }
...
/**
* @param {BPMNProcess} currentProcess
* @return {Function | Object}
*/
BPMNCallActivity.prototype.getHandler = function(currentProcess) {
var handler, bpmnFilePath;
var callActivityName = this.name;
var mockupHandler = handlerModule.getHandlerFromProcess(callActivityName, currentProcess
);
if (mockupHandler && typeof mockupHandler === "object") {
handler = mockupHandler;
} else {
bpmnFilePath = this.location;
handler = handlerModule.getHandlerFromFile(bpmnFilePath);
}
...
getHandlerFromString = function (moduleString) { var Module = require('module').Module; var handlerModule = new Module(); handlerModule._compile(stripBOM(moduleString)); return handlerModule.exports; }
...
/**
* Change the process handler using a string.
*
* @param {String} name Name of the process
* @param {String} handlerString
*/
ProcessManager.prototype.addHandlerString = function(name, handlerString){
this._processHandlers[name] = handlers.getHandlerFromString(handlerString);
this._processHandlers[name].doneLoadingHandler = this._doneLoadingHandler || this._processHandlers[name].doneLoadingHandler;
this._processHandlers[name].doneSavingHandler = this._doneSavingHandler || this._processHandlers[name].doneSavingHandler;
};
/**
* Change the process handler using an object.
*
...
mapName2HandlerName = function (name) { var cleanName = name.replace(/[:!`~\^@*#¢¬ç?¦\|&;%@"<>\(\){}\[\]\+, \t\n]/g, "_"); if (cleanName.match(/^[0-9]/)) { cleanName = "_" + cleanName; } return cleanName; }
...
* @private
*/
BPMNProcess.prototype._registerActivityEndEvents = function() {
var self = this;
self.on(ACTIVITY_END_EVENT, function(activityName, data) {
var currentToken, owningProcessId, currentProcess, currentFlowObject, activityEndHandlerIsDone;
var handlerName = handler.mapName2HandlerName(activityName) + activityEndHandlerPostfix
;
var trx = self.currentTrx = null;
if(self.transactionLogger){
trx = self.currentTrx = self.transactionLogger.startTransaction(self.processDefinition.name, 'PSTATE', 'TRANSITION
', null, activityName+'Done');
}
if (self.state.hasTokens(activityName)) {
...
BPMNProcessHistory = function (history) { /** @type {Array.<HistoryEntry>} */ this.historyEntries = []; if (history) { this.historyEntries = history.historyEntries.map(function(historyEntry) { var entry = new HistoryEntry(historyEntry.name, historyEntry.type, historyEntry.begin, historyEntry.end); if (historyEntry.subhistory) { entry.subhistory = new BPMNProcessHistory(historyEntry.subhistory); } return entry; }); this.createdAt = history.createdAt; this.finishedAt = history.finishedAt || null; } else { this.createdAt = getTimestamp(); this.finishedAt = null; } }
n/a
HistoryEntry = function (name, type, begin, end) { this.name = name; this.type = type; this.begin = begin || getTimestamp(); this.end = end || null; }
n/a
setDummyTimestampFunction = function () { getTimestamp = function () { return "_dummy_ts_"; }; }
...
* Copyright: E2E Technologies Ltd
*/
"use strict";
var path = require('path');
var bpmn = require('../../lib/public.js');
require("../../lib/history.js").setDummyTimestampFunction();
var mongodb = require('mongodb');
var persistencyUri = 'mongodb://127.0.0.1:27017/ut_flatprocess';
var bpmnFileName = path.join(__dirname, "../resources/projects/simple/taskExampleProcess.bpmn");
var bpmnProcess1, bpmnProcess2;
...
setTimestampFunction = function (getTimestampFunction) { getTimestamp = getTimestampFunction; }
n/a
BPMNIntermediateCatchEvent = function (bpmnId, name, type) { BPMNFlowObject.call(this, bpmnId, name, type); this.isIntermediateCatchEvent = true; }
n/a
BPMNIntermediateThrowEvent = function (bpmnId, name, type) { BPMNFlowObject.call(this, bpmnId, name, type); this.isIntermediateThrowEvent = true; }
n/a
createBPMNIntermediateCatchEvent = function (node) { var getValue = parserUtils.getAttributesValue; return (new BPMNIntermediateCatchEvent( getValue(node, "id"), getValue(node, "name"), node.local )); }
...
} else if (callActivity.isCallActivityName(localName)) {
currentProcessElement = callActivity.createBPMNCallActivity(node, fileName, prefix2NamespaceMap, importNamespace2LocationMap
);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (intermediateEvents.isIntermediateThrowEventName(localName)) {
currentProcessElement = intermediateEvents.createBPMNIntermediateThrowEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (intermediateEvents.isIntermediateCatchEventName(localName)) {
currentProcessElement = intermediateEvents.createBPMNIntermediateCatchEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (events.isMessageEventName(localName)) {
currentProcessElement.isMessageEvent = true;
} else if (subProcess.isSubProcessName(localName)) {
subProcessDefinition = processDefinition.createBPMNProcessDefinition(node, errorQueue);
currentProcessElement = subProcess.createBPMNSubProcess(node, subProcessDefinition);
currentProcessDefinition.addFlowObject(currentProcessElement);
...
createBPMNIntermediateThrowEvent = function (node) { var getValue = parserUtils.getAttributesValue; return (new BPMNIntermediateThrowEvent( getValue(node, "id"), getValue(node, "name"), node.local )); }
...
} else if (gateways.isGatewayName(localName)) {
currentProcessElement = gateways.createBPMNGateway(node, errorQueue);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (callActivity.isCallActivityName(localName)) {
currentProcessElement = callActivity.createBPMNCallActivity(node, fileName, prefix2NamespaceMap, importNamespace2LocationMap
);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (intermediateEvents.isIntermediateThrowEventName(localName)) {
currentProcessElement = intermediateEvents.createBPMNIntermediateThrowEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (intermediateEvents.isIntermediateCatchEventName(localName)) {
currentProcessElement = intermediateEvents.createBPMNIntermediateCatchEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (events.isMessageEventName(localName)) {
currentProcessElement.isMessageEvent = true;
} else if (subProcess.isSubProcessName(localName)) {
...
isIntermediateCatchEventName = function (localName) { return (localName === "intermediateCatchEvent"); }
...
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (callActivity.isCallActivityName(localName)) {
currentProcessElement = callActivity.createBPMNCallActivity(node, fileName, prefix2NamespaceMap, importNamespace2LocationMap
);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (intermediateEvents.isIntermediateThrowEventName(localName)) {
currentProcessElement = intermediateEvents.createBPMNIntermediateThrowEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (intermediateEvents.isIntermediateCatchEventName(localName)) {
currentProcessElement = intermediateEvents.createBPMNIntermediateCatchEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (events.isMessageEventName(localName)) {
currentProcessElement.isMessageEvent = true;
} else if (subProcess.isSubProcessName(localName)) {
subProcessDefinition = processDefinition.createBPMNProcessDefinition(node, errorQueue);
currentProcessElement = subProcess.createBPMNSubProcess(node, subProcessDefinition);
...
isIntermediateThrowEventName = function (localName) { return (localName === "intermediateThrowEvent"); }
...
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (gateways.isGatewayName(localName)) {
currentProcessElement = gateways.createBPMNGateway(node, errorQueue);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (callActivity.isCallActivityName(localName)) {
currentProcessElement = callActivity.createBPMNCallActivity(node, fileName, prefix2NamespaceMap, importNamespace2LocationMap
);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (intermediateEvents.isIntermediateThrowEventName(localName)) {
currentProcessElement = intermediateEvents.createBPMNIntermediateThrowEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (intermediateEvents.isIntermediateCatchEventName(localName)) {
currentProcessElement = intermediateEvents.createBPMNIntermediateCatchEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (events.isMessageEventName(localName)) {
currentProcessElement.isMessageEvent = true;
...
Logger = function (process, options) { this.logLevel = logLevels.error; if (options) { this.logLevel = getLogLevelValue(options.logLevel || this.logLevel); } /** {function(string)} */ this.logAppender = null; // used for example to test log messages this.winstonFileTransport = new (winston.transports.File)({ //level: getLogLevelString(this.logLevel), //TODO: this should work, but it doesn't. Why? level: 'verbose', filename: './process.log', maxsize: 64 * 1024 * 1024, maxFiles: 100, timestamp: function() { return Date.now(); } }); this.winstonConsoleTransport = new (winston.transports.Console)({ //level: getLogLevelString(this.logLevel), //TODO: this should work, but it doesn't. Why? level: 'verbose', colorize: true, json: false }); this.winstonLogger = new (winston.Logger)({ transports: [this.winstonFileTransport, this.winstonConsoleTransport], levels: logLevels, colors: logLevelColors }); this.setProcess(process); }
...
this.persistency = persistency;
this.deferredEvents = [];
this.deferEvents = false; // events must be deferred if the process engine is loading or saving state
this.processClient = new BPMNProcessClient(this);
this.participants = {}; // if the process takes part in a collaboration, we store all participant process in this map
this.properties = {}; // TODO: how do we handle parent data?
this.calledProcesses = {};
this.logger = new log.Logger(this, {logLevel: log.logLevels.error});
if(transactionLog) {
this.transactionLogger = new transactionLog.TransactionLogger();
}
this.currentTrx = null;
this.views = {
startEvent : null,
endEvent : null,
...
ProcessManager = function (options){ var self = this; options = options || {}; self._processCache = {}; self._initialized = true; self._initialising = false; self._initializationError = null; self._definitionsToInitialize = []; self._initialiseCallbacks = []; self._persistency = null; if (options.persistencyOptions) { self._persistency = new Persistency(options.persistencyOptions); self._doneLoadingHandler = options.persistencyOptions.doneLoading; self._doneSavingHandler = options.persistencyOptions.doneSaving; } self._processHandlers = {}; self._processDefinitions = {}; if(!options.handlerFilePath){ options.handlerFilePath = []; } if(!util.isArray(options.handlerFilePath)){ options.handlerFilePath = [options.handlerFilePath]; } options.handlerFilePath.forEach(function(handlerDescriptor){ if(!handlerDescriptor.name || !handlerDescriptor.filePath){ throw new Error("handlerFilePath needs a name and a filePath"); } self.addHandlerFilePath(handlerDescriptor.name, handlerDescriptor.filePath); }); if(!options.handler){ options.handler = []; } if(!util.isArray(options.handler)){ options.handler = [options.handler]; } options.handler.forEach(function(handlerDescriptor){ if(!handlerDescriptor.name || !handlerDescriptor.module){ throw new Error("handler needs a name and a module"); } self.addHandler(handlerDescriptor.name, handlerDescriptor.module); }); if(!options.handlerString){ options.handlerString = []; } if(!util.isArray(options.handlerString)){ options.handlerString = [options.handlerString]; } options.handlerString.forEach(function(handlerString){ if(!handlerString.name || !handlerString.string){ throw new Error("handlerString needs a name and a string"); } self.addHandlerString(handlerString.name, handlerString.string); }); if(!options.bpmnFilePath){ options.bpmnFilePath = []; } if(!util.isArray(options.bpmnFilePath)){ options.bpmnFilePath = [options.bpmnFilePath]; } options.bpmnFilePath.forEach(function(filePath){ self.addBpmnFilePath(filePath); }); if(!options.bpmnXML){ options.bpmnXML = []; } if(!util.isArray(options.bpmnXML)){ options.bpmnXML = [options.bpmnXML]; } options.bpmnXML.forEach(function(bpmnXML){ if(!bpmnXML.name || !bpmnXML.xml){ throw new Error("bpmnXML needs a name and a xml"); } self.addBpmnXML(bpmnXML.xml, bpmnXML.name); }); }
...
bpmnProcess.removeLogTransport(winston.transports.File);
Managing processes
==================
Process managers are used to create multiple processes using the same definitions and find them back later.
var manager = new bpmn.ProcessManager();
manager.addBpmnFilePath("path/to/myProcess.bpmn");
manager.createProcess("myId", function(err, myProcess){
// we start the process
myProcess.triggerEvent("MyStart");
...
BPMNMessageFlow = function (bpmnId, name, type, sourceRef, targetRef) { this.bpmnId = bpmnId; this.name = name; this.type = type; this.sourceRef = sourceRef; this.targetRef = targetRef; this.targetProcessDefinitionId = null; this.sourceProcessDefinitionId = null; }
n/a
createBPMNMessageFlow = function (node) { var getValue = parserUtils.getAttributesValue; return (new BPMNMessageFlow( getValue(node, "id"), getValue(node, "name"), node.local, getValue(node, "sourceRef"), getValue(node, "targetRef") )); }
...
currentCollaborationDefinition = collaborationDefinition.createBPMNCollaborationDefinition(node);
topLevelDefinitions.push(currentCollaborationDefinition);
currentProcessDefinition = null;
}
if (currentCollaborationDefinition) {
if (messageFlows.isMessageFlowName(localName)) {
currentCollaborationElement = messageFlows.createBPMNMessageFlow(node);
currentCollaborationDefinition.addMessageFlow(currentCollaborationElement);
} else if (participant.isParticipantName(localName)) {
currentCollaborationElement = participant.createBPMNParticipant(node);
currentCollaborationDefinition.addParticipant(currentCollaborationElement);
}
}
...
isMessageFlowName = function (localName) { return (localName.toLowerCase().indexOf("messageflow") > -1); }
...
if (collaborationDefinition.isCollaborationDefinitionName(localName)) {
currentCollaborationDefinition = collaborationDefinition.createBPMNCollaborationDefinition(node);
topLevelDefinitions.push(currentCollaborationDefinition);
currentProcessDefinition = null;
}
if (currentCollaborationDefinition) {
if (messageFlows.isMessageFlowName(localName)) {
currentCollaborationElement = messageFlows.createBPMNMessageFlow(node);
currentCollaborationDefinition.addMessageFlow(currentCollaborationElement);
} else if (participant.isParticipantName(localName)) {
currentCollaborationElement = participant.createBPMNParticipant(node);
currentCollaborationDefinition.addParticipant(currentCollaborationElement);
}
}
...
Persistency = function (uri, options) { this.options = options || defaultOptions; this.options.server = this.options.server || defaultOptions.server; if (this.options.logger) { this._trace = this.options.logger.trace || function() {}; } else { this._trace = function() {}; } if (uri) { this.uri = uri; } else { throw new Error("MongoDB: Persistency: requires uri to db"); } }
n/a
parse = function (bpmnXML, errorQueue, mainProcessName, fileName) { var parser = sax.parser(true, {"xmlns": true}); var topLevelDefinitions = []; var processStack = []; /** @type {BPMNProcessDefinition} */ var subProcessDefinition = null; /** @type {BPMNProcessDefinition} */ var currentProcessDefinition = null; /** @type {BPMNFlowObject|BPMNSequenceFlow} */ var currentProcessElement = null; /** @type {BPMNCollaborationDefinition} */ var currentCollaborationDefinition = null; /** @type {BPMNMessageFlow|BPMNParticipant} */ var currentCollaborationElement = null; var prefix2NamespaceMap = {}; var importNamespace2LocationMap = {}; var debuggerInterface = null; if (errorQueue && fileName) { errorQueue.fileName = fileName; } parser.onerror = function (e) { errorQueue.addError("NOPARSE", {}, e.message); parser.resume(); }; parser.onopentag = function (node) { var localName = node.local; var inBPMN2Namespace = node.uri === BPMN2NAMESPACE; addNamespaces(prefix2NamespaceMap, node); if (!debuggerInterface && debug.isDebuggerElement(node) && fileName) { debuggerInterface = debug.createDebuggerInterface(node, fileName); } if (inBPMN2Namespace) { if (collaborationDefinition.isCollaborationDefinitionName(localName)) { currentCollaborationDefinition = collaborationDefinition.createBPMNCollaborationDefinition(node); topLevelDefinitions.push(currentCollaborationDefinition); currentProcessDefinition = null; } if (currentCollaborationDefinition) { if (messageFlows.isMessageFlowName(localName)) { currentCollaborationElement = messageFlows.createBPMNMessageFlow(node); currentCollaborationDefinition.addMessageFlow(currentCollaborationElement); } else if (participant.isParticipantName(localName)) { currentCollaborationElement = participant.createBPMNParticipant(node); currentCollaborationDefinition.addParticipant(currentCollaborationElement); } } if (processDefinition.isProcessName(localName)) { if (processDefinition.isExecutable(node)) { currentProcessDefinition = processDefinition.createBPMNProcessDefinition(node, debuggerInterface); if (!currentProcessDefinition.name && mainProcessName) { currentProcessDefinition.name = mainProcessName; } topLevelDefinitions.push(currentProcessDefinition); currentCollaborationDefinition = null; } else { currentProcessDefinition = null; } } if (localName === "import") { addImport(importNamespace2LocationMap, node); } if (currentProcessDefinition) { if (tasks.isTaskName(localName)) { currentProcessElement = tasks.createBPMNTask(node); currentProcessDefinition.addFlowObject(currentProcessElement); } else if (sequenceFlows.isSequenceFlowName(localName)) { currentProcessElement = sequenceFlows.createBPMNSequenceFlow(node); currentProcessDefinition.addSequenceFlow(currentProcessElement); } else if (startEvents.isStartEventName(localName)) { currentProcessElement = startEvents.createBPMNStartEvent(node); currentProcessDefinition.addFlowObject(currentProcessElement); } else if (boundaryEvents.isBoundaryEventName(localName)) { currentProcessElement = boundaryEvents.createBPMNBoundaryEvent(node); currentProcessDefinition.addFlowObject(currentProcessElement); ...
...
/**
* @param {String} url
* @param {String} fileName
* @constructor
*/
var DebuggerInterface = exports.DebuggerInterface = function(url, fileName) {
this.fileName = fileName;
this.url = urls.parse(url);
};
/**
* @returns {boolean}
*/
DebuggerInterface.prototype.isInDebugger = function() {
return (global.v8debug !== undefined);
...
getAttributesValue = function (node, attributeName) { var value = null, attribute = null; var attributes = node.attributes; if (attributes) { attribute = attributes[attributeName]; value = attribute ? attribute.value : null; } return value; }
...
/**
* @param node
* @param {String} fileName
* @constructor
*/
exports.createDebuggerInterface = function(node, fileName) {
return (new DebuggerInterface(parserUtils.getAttributesValue(node, "href"
;), fileName));
};
/**
* @param node
* @return {Boolean}
*/
exports.isDebuggerElement = function(node) {
...
splitPrefixedName = function (prefixedName) { var result = {prefix: "", localName: ""}; var colon = prefixedName.indexOf(":"); if (colon) { result.prefix = prefixedName.substring(0, colon); result.localName = prefixedName.substring(colon + 1); } else { result.localName = prefixedName; } return result; }
...
* @param {String} baseFileName Name of the current process definition file
* @param {Object} prefix2NamespaceMap
* @param {Object} importNamespace2LocationMap
*/
exports.createBPMNCallActivity = function(node, baseFileName, prefix2NamespaceMap, importNamespace2LocationMap) {
var getValue = parserUtils.getAttributesValue;
var calledElement = getValue(node, "calledElement");
var splitName = parserUtils.splitPrefixedName(calledElement);
var calledElementName = splitName.localName;
var calledElementNamespace = prefix2NamespaceMap[splitName.prefix];
var relativeLocation = importNamespace2LocationMap[calledElementNamespace];
var location = relativeLocation ? path.join(path.dirname(baseFileName), relativeLocation) : "";
return (new BPMNCallActivity(
getValue(node, "id"),
...
BPMNParticipant = function (bpmnId, name, type, processRef) { this.bpmnId = bpmnId; this.name = name; this.type = type; this.processRef = processRef; }
n/a
createBPMNParticipant = function (node) { var getValue = parserUtils.getAttributesValue; return (new BPMNParticipant( getValue(node, "id"), getValue(node, "name"), node.local, getValue(node, "processRef") )); }
...
}
if (currentCollaborationDefinition) {
if (messageFlows.isMessageFlowName(localName)) {
currentCollaborationElement = messageFlows.createBPMNMessageFlow(node);
currentCollaborationDefinition.addMessageFlow(currentCollaborationElement);
} else if (participant.isParticipantName(localName)) {
currentCollaborationElement = participant.createBPMNParticipant(node);
currentCollaborationDefinition.addParticipant(currentCollaborationElement);
}
}
if (processDefinition.isProcessName(localName)) {
if (processDefinition.isExecutable(node)) {
currentProcessDefinition = processDefinition.createBPMNProcessDefinition(node, debuggerInterface);
...
isParticipantName = function (localName) { return (localName === 'participant'); }
...
currentProcessDefinition = null;
}
if (currentCollaborationDefinition) {
if (messageFlows.isMessageFlowName(localName)) {
currentCollaborationElement = messageFlows.createBPMNMessageFlow(node);
currentCollaborationDefinition.addMessageFlow(currentCollaborationElement);
} else if (participant.isParticipantName(localName)) {
currentCollaborationElement = participant.createBPMNParticipant(node);
currentCollaborationDefinition.addParticipant(currentCollaborationElement);
}
}
if (processDefinition.isProcessName(localName)) {
if (processDefinition.isExecutable(node)) {
...
Persistency = function (options) { var isMongoDbUri; var uri = options ? options.uri : null; if (uri) { isMongoDbUri = uri.indexOf('mongodb://') === 0; if (isMongoDbUri) { this.implementation = new MongoDBPersistency(uri, options); } else { this.implementation = new FilePersistency(uri); } } else { throw new Error("Persistency options must contain an uri property."); } }
n/a
createBPMNProcess = function (id, processDefinition, eventHandler, persistency, parentProcess, parentToken, parentHistoryEntry, callback) { var bpmnProcess; if(typeof persistency === 'function' ){ callback = persistency; persistency = null; parentProcess = null; parentToken = null; parentHistoryEntry = null; } else if(typeof parentProcess === 'function' ){ callback = parentProcess; parentProcess = null; parentToken = null; parentHistoryEntry = null; } else if(typeof parentToken === 'function' ){ callback = parentToken; parentToken = null; parentHistoryEntry = null; } else if(typeof parentHistoryEntry === 'function' ){ callback = parentHistoryEntry; parentHistoryEntry = null; } if(!callback){ return; } bpmnProcess = new BPMNProcess(id, processDefinition, eventHandler, persistency, parentProcess, parentToken, parentHistoryEntry ); if (bpmnProcess.isMainProcess()) { // we save all process information - including called processes - in one document bpmnProcess.loadPersistedData(function(err){ if(callback){ callback(err, bpmnProcess); } }); } else { if(callback){ process.nextTick(function(){ // to stay consistent callback(null, bpmnProcess); }); } } }
...
if(!callback) {
throw error;
} else {
callback(error);
}
}
bpmnProcesses.createBPMNProcess(null, processDefinition, handler, function(err, bpmnProcess
){
if(!callback){
return;
}
callback(err, bpmnProcess.processClient);
});
...
BPMNProcessDefinition = function (bpmnId, name, debuggerInterface) { this.bpmnId = bpmnId; this.name = name; this.flowObjects = []; this.sequenceFlows = []; this.messageFlows = []; // Process Elements = Flow objects + connection objects + artifacts // Semantics of these names is described in http://de.wikipedia.org/wiki/Business_Process_Model_and_Notation#Notation this.processElementIndex = null; this.sequenceFlowBySourceIndex = null; this.sequenceFlowByTargetIndex = null; this.messageFlowBySourceIndex = null; this.messageFlowByTargetIndex = null; this.boundaryEventsByAttachmentIndex = null; this.nameMap = null; this.isProcessDefinition = true; /** {Array.<BPMNParticipant>} */ this.collaboratingParticipants = []; if (debuggerInterface) { this.debuggerInterface = debuggerInterface; } }
n/a
createBPMNProcessDefinition = function (node, debuggerInterface) { var getValue = parserUtils.getAttributesValue; return (new BPMNProcessDefinition( getValue(node, "id"), getValue(node, "name"), debuggerInterface )); }
...
currentCollaborationElement = participant.createBPMNParticipant(node);
currentCollaborationDefinition.addParticipant(currentCollaborationElement);
}
}
if (processDefinition.isProcessName(localName)) {
if (processDefinition.isExecutable(node)) {
currentProcessDefinition = processDefinition.createBPMNProcessDefinition(node
, debuggerInterface);
if (!currentProcessDefinition.name && mainProcessName) {
currentProcessDefinition.name = mainProcessName;
}
topLevelDefinitions.push(currentProcessDefinition);
currentCollaborationDefinition = null;
} else {
currentProcessDefinition = null;
...
isExecutable = function (node) { var isExecutable = parserUtils.getAttributesValue(node, "isExecutable"); return (!isExecutable || isExecutable === 'true'); }
...
} else if (participant.isParticipantName(localName)) {
currentCollaborationElement = participant.createBPMNParticipant(node);
currentCollaborationDefinition.addParticipant(currentCollaborationElement);
}
}
if (processDefinition.isProcessName(localName)) {
if (processDefinition.isExecutable(node)) {
currentProcessDefinition = processDefinition.createBPMNProcessDefinition(node, debuggerInterface);
if (!currentProcessDefinition.name && mainProcessName) {
currentProcessDefinition.name = mainProcessName;
}
topLevelDefinitions.push(currentProcessDefinition);
currentCollaborationDefinition = null;
} else {
...
isProcessName = function (localName) { return (localName === 'process'); }
...
currentCollaborationDefinition.addMessageFlow(currentCollaborationElement);
} else if (participant.isParticipantName(localName)) {
currentCollaborationElement = participant.createBPMNParticipant(node);
currentCollaborationDefinition.addParticipant(currentCollaborationElement);
}
}
if (processDefinition.isProcessName(localName)) {
if (processDefinition.isExecutable(node)) {
currentProcessDefinition = processDefinition.createBPMNProcessDefinition(node, debuggerInterface);
if (!currentProcessDefinition.name && mainProcessName) {
currentProcessDefinition.name = mainProcessName;
}
topLevelDefinitions.push(currentProcessDefinition);
currentCollaborationDefinition = null;
...
clearReceivedMessageIds = function () { receivedMessageIds = {}; }
n/a
createServer = function (manager, options, restifyOptions) { var logger, serverOptions, server; var settings = options || {}; settings.createProcessId = settings.createProcessId || uuid.v1; logger = new log.Logger(null, settings); serverOptions = restifyOptions || {}; serverOptions.name = serverOptions.name || "BPMNProcessServer"; // Shimming the log doesn't work as expected: I cannot switch it off for example. // Additionally, the log format is horrible. So for the time being we use our own logging // serverOptions.log = serverOptions.log || bunyan2winston.createLogger(logger.winstonLogger); server = restify.createServer(serverOptions); server.use(restify.queryParser({ mapParams: false })); server.use(restify.bodyParser({ mapParams: false })); server.on('after', function( request, response, route, error) { var handler = options.onServerAfterEvent || onServerAfterEvent; handler(logger, request, response, route, error); }); server.get(getProcessRoute, transactionLog.transactionLoggerMiddleware({ name: function(req){ return 'GET ' + req.params.processName + ' process'; } }), function(req, res, next){ getProcess(manager, req, res, next); }); server.get(getProcessesRoute, transactionLog.transactionLoggerMiddleware({ name: function(req){ return 'GET ' + req.params.processName + ' processes'; } }), function(req, res, next){ getProcesses(manager, req, res, next); }); server.put(sendMessageRoute, transactionLog.transactionLoggerMiddleware({ name: function(req){ return 'PUT ' + req.params.messageName + ' message to ' + req.params.processName + ' process'; } }), function(req, res, next) { sendMessage(manager, logger, req, res, next); } ); // TODO: we need to change these routes. the catch all '/' makes this load order dependent. server.post(createAndStartCollaboratingProcessRoute, transactionLog.transactionLoggerMiddleware({ name: function(req) { return 'POST create and start collaborating processes'; } }), function(req, res, next) { createAndStartCollaboratingProcess(manager, settings, logger, req, res, next); } ); server.post(createProcessRoute, transactionLog.transactionLoggerMiddleware({ name: function(req){ return 'POST create ' + req.params.processName + ' process'; } }), function(req, res, next) { createProcess(manager, settings, logger, req, res, next); } ); server.post(createAndStartProcessRoute, transactionLog.transactionLoggerMiddleware({ name: function(req){ return 'POST create and start ' + req.params.processName + ' process'; } }), function(req, res, next) { createAndStartProcess(manager, settings, logger, req, res, next); } ); return server; }
...
Server
------
The above API can also be called by REST HTTP calls. To do this, you have first to instantiate a server from ta manager. For example
:
// Returns a restify server.
var server = manager.createServer();
server.listen(9009, function() {
console.log('%s listening at %s', server.name, server.url);
});
The server is a node restify server. So all features of this package can be used.
The full signature of `createProcess` is
...
BPMNSequenceFlow = function (bpmnId, name, type, sourceRef, targetRef) { this.bpmnId = bpmnId; this.name = name; this.type = type; this.sourceRef = sourceRef; this.targetRef = targetRef; this.isSequenceFlow = true; }
n/a
createBPMNSequenceFlow = function (node) { var getValue = parserUtils.getAttributesValue; return (new BPMNSequenceFlow( getValue(node, "id"), getValue(node, "name"), node.local, getValue(node, "sourceRef"), getValue(node, "targetRef") )); }
...
}
if (currentProcessDefinition) {
if (tasks.isTaskName(localName)) {
currentProcessElement = tasks.createBPMNTask(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (sequenceFlows.isSequenceFlowName(localName)) {
currentProcessElement = sequenceFlows.createBPMNSequenceFlow(node);
currentProcessDefinition.addSequenceFlow(currentProcessElement);
} else if (startEvents.isStartEventName(localName)) {
currentProcessElement = startEvents.createBPMNStartEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (boundaryEvents.isBoundaryEventName(localName)) {
currentProcessElement = boundaryEvents.createBPMNBoundaryEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
...
isSequenceFlowName = function (localName) { return (localName.toLowerCase().indexOf("sequenceflow") > -1); }
...
addImport(importNamespace2LocationMap, node);
}
if (currentProcessDefinition) {
if (tasks.isTaskName(localName)) {
currentProcessElement = tasks.createBPMNTask(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (sequenceFlows.isSequenceFlowName(localName)) {
currentProcessElement = sequenceFlows.createBPMNSequenceFlow(node);
currentProcessDefinition.addSequenceFlow(currentProcessElement);
} else if (startEvents.isStartEventName(localName)) {
currentProcessElement = startEvents.createBPMNStartEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (boundaryEvents.isBoundaryEventName(localName)) {
currentProcessElement = boundaryEvents.createBPMNBoundaryEvent(node);
...
BPMNStartEvent = function (bpmnId, name, type) { BPMNFlowObject.call(this, bpmnId, name, type); this.isStartEvent = true; }
n/a
createBPMNStartEvent = function (node) { var getValue = parserUtils.getAttributesValue; return (new BPMNStartEvent( getValue(node, "id"), getValue(node, "name"), node.local )); }
...
if (tasks.isTaskName(localName)) {
currentProcessElement = tasks.createBPMNTask(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (sequenceFlows.isSequenceFlowName(localName)) {
currentProcessElement = sequenceFlows.createBPMNSequenceFlow(node);
currentProcessDefinition.addSequenceFlow(currentProcessElement);
} else if (startEvents.isStartEventName(localName)) {
currentProcessElement = startEvents.createBPMNStartEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (boundaryEvents.isBoundaryEventName(localName)) {
currentProcessElement = boundaryEvents.createBPMNBoundaryEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (boundaryEvents.isTimerEventName(localName)) {
currentProcessElement.isTimerEvent = true;
} else if (endEvents.isEndEventName(localName)) {
...
isStartEventName = function (localName) { return (localName.toLowerCase().indexOf("start") > -1); }
...
if (currentProcessDefinition) {
if (tasks.isTaskName(localName)) {
currentProcessElement = tasks.createBPMNTask(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (sequenceFlows.isSequenceFlowName(localName)) {
currentProcessElement = sequenceFlows.createBPMNSequenceFlow(node);
currentProcessDefinition.addSequenceFlow(currentProcessElement);
} else if (startEvents.isStartEventName(localName)) {
currentProcessElement = startEvents.createBPMNStartEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (boundaryEvents.isBoundaryEventName(localName)) {
currentProcessElement = boundaryEvents.createBPMNBoundaryEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (boundaryEvents.isTimerEventName(localName)) {
currentProcessElement.isTimerEvent = true;
...
BPMNProcessState = function (state) { /** @type {Array.<Token>} */ this.tokens = state && state.tokens ? state.tokens : []; }
n/a
CallActivityToken = function (flowObjectName, owningProcessId, calledProcessId) { Token.call(this, flowObjectName, owningProcessId); this.substate = null; this.calledProcessId = calledProcessId; }
n/a
Token = function (flowObjectName, owningProcessId) { this.position = flowObjectName; this.owningProcessId = owningProcessId; }
n/a
BPMNSubProcess = function (bpmnId, name, type, subProcessDefinition) { BPMNActivity.call(this, bpmnId, name, type); this.isSubProcess = true; this.processDefinition = subProcessDefinition; }
n/a
createBPMNSubProcess = function (node, subProcessDefinition) { var getValue = parserUtils.getAttributesValue; return (new BPMNSubProcess( getValue(node, "id"), getValue(node, "name"), node.local, subProcessDefinition )); }
...
} else if (intermediateEvents.isIntermediateCatchEventName(localName)) {
currentProcessElement = intermediateEvents.createBPMNIntermediateCatchEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (events.isMessageEventName(localName)) {
currentProcessElement.isMessageEvent = true;
} else if (subProcess.isSubProcessName(localName)) {
subProcessDefinition = processDefinition.createBPMNProcessDefinition(node, errorQueue);
currentProcessElement = subProcess.createBPMNSubProcess(node, subProcessDefinition
);
currentProcessDefinition.addFlowObject(currentProcessElement);
processStack.push(currentProcessDefinition);
currentProcessDefinition = subProcessDefinition;
}
}
}
};
...
isSubProcessName = function (localName) { return (localName.toLowerCase().indexOf("subprocess") > -1); }
...
currentProcessElement = intermediateEvents.createBPMNIntermediateThrowEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (intermediateEvents.isIntermediateCatchEventName(localName)) {
currentProcessElement = intermediateEvents.createBPMNIntermediateCatchEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (events.isMessageEventName(localName)) {
currentProcessElement.isMessageEvent = true;
} else if (subProcess.isSubProcessName(localName)) {
subProcessDefinition = processDefinition.createBPMNProcessDefinition(node, errorQueue);
currentProcessElement = subProcess.createBPMNSubProcess(node, subProcessDefinition);
currentProcessDefinition.addFlowObject(currentProcessElement);
processStack.push(currentProcessDefinition);
currentProcessDefinition = subProcessDefinition;
}
}
...
BPMNTask = function (bpmnId, name, type) { BPMNActivity.call(this, bpmnId, name, type); this.isWaitTask = type === 'task' || type === 'userTask' || type === 'receiveTask' || type === 'manualTask'; }
n/a
createBPMNTask = function (node) { var getValue = parserUtils.getAttributesValue; return (new BPMNTask( getValue(node, "id"), getValue(node, "name"), node.local )); }
...
if (localName === "import") {
addImport(importNamespace2LocationMap, node);
}
if (currentProcessDefinition) {
if (tasks.isTaskName(localName)) {
currentProcessElement = tasks.createBPMNTask(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (sequenceFlows.isSequenceFlowName(localName)) {
currentProcessElement = sequenceFlows.createBPMNSequenceFlow(node);
currentProcessDefinition.addSequenceFlow(currentProcessElement);
} else if (startEvents.isStartEventName(localName)) {
currentProcessElement = startEvents.createBPMNStartEvent(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
...
isTaskName = function (localName) { return (localName.toLowerCase().indexOf("task") > -1); }
...
}
if (localName === "import") {
addImport(importNamespace2LocationMap, node);
}
if (currentProcessDefinition) {
if (tasks.isTaskName(localName)) {
currentProcessElement = tasks.createBPMNTask(node);
currentProcessDefinition.addFlowObject(currentProcessElement);
} else if (sequenceFlows.isSequenceFlowName(localName)) {
currentProcessElement = sequenceFlows.createBPMNSequenceFlow(node);
currentProcessDefinition.addSequenceFlow(currentProcessElement);
} else if (startEvents.isStartEventName(localName)) {
currentProcessElement = startEvents.createBPMNStartEvent(node);
...
BPMNPendingTimerEvents = function (bpmnProcess) { /** @type {Array.<Timeout>} */ this.pendingTimeouts = {}; this.bpmnProcess = bpmnProcess; this.setTimeoutIds = {}; }
n/a
function HashMap(caseSensitive) { this.values = {}; this.caseSensitive = caseSensitive !== undefined ? caseSensitive : true; this.prefix = '.'; // a char not allowed in JS names this.offset = this.prefix.length; }
n/a
firstToUpper = function (name) { return (name.substring(0,1).toUpperCase() + name.substring(1)); }
n/a
toUpperCamelCase = function (name) { var result = ""; var parts = name.split(/\s+/g); parts.forEach(function(part) { result += firstToUpper(part); }); return result; }
...
*/
function getBPMNDefinitions(bpmnFilePath) {
var errorQueue = errors.createBPMNParseErrorQueue();
var bpmnDefinitions, bpmnXML;
try {
bpmnXML = fs.readFileSync(bpmnFilePath, "utf8");
bpmnDefinitions = parser.parse(bpmnXML, errorQueue, utils.toUpperCamelCase(fileUtils
.removeFileExtension(path.basename(bpmnFilePath))), bpmnFilePath);
} catch (e) {
errorQueue.addError("DF1", null, "Could not parse the BPMN file '" + bpmnFilePath + "'. Error
: '" + e + "'");
}
errorQueue.check();
setCollaborationDefinitions(bpmnDefinitions);
...