use of io.automatiko.engine.workflow.process.core.node.CompositeContextNode in project automatiko-engine by automatiko-io.
the class ProcessHandler method checkBoundaryEventCompensationHandler.
/**
* This logic belongs in {@link ExecutableProcessValidator} -- except that
* {@link Association}s are a jbpm-bpmn2 class, and
* {@link ExecutableProcessValidator} is a jbpm-flow class..
* </p>
* Maybe we should have a BPMNProcessValidator class?
*
* @param association The association to check.
* @param source The source of the association.
* @param target The target of the association.
*/
private static void checkBoundaryEventCompensationHandler(Association association, Node source, Node target) {
// - event node is boundary event node
if (!(source instanceof BoundaryEventNode)) {
throw new IllegalArgumentException("(Compensation) activities may only be associated with Boundary Event Nodes (not with" + source.getClass().getSimpleName() + " nodes [node " + ((String) source.getMetaData().get("UniqueId")) + "].");
}
BoundaryEventNode eventNode = (BoundaryEventNode) source;
// - event node has compensationEvent
List<EventFilter> eventFilters = eventNode.getEventFilters();
boolean compensationCheckPassed = false;
if (eventFilters != null) {
for (EventFilter filter : eventFilters) {
if (filter instanceof EventTypeFilter) {
String type = ((EventTypeFilter) filter).getType();
if (type != null && type.equals("Compensation")) {
compensationCheckPassed = true;
}
}
}
}
if (!compensationCheckPassed) {
throw new IllegalArgumentException("An Event [" + ((String) eventNode.getMetaData("UniqueId")) + "] linked from an association [" + association.getId() + "] must be a (Boundary) Compensation Event.");
}
// - boundary event node is attached to the correct type of node?
/**
* Tasks: business: RuleSetNode manual: WorkItemNode receive: WorkItemNode
* script: ActionNode send: WorkItemNode service: WorkItemNode task:
* WorkItemNode user: HumanTaskNode
*/
String attachedToId = eventNode.getAttachedToNodeId();
Node attachedToNode = null;
for (Node node : eventNode.getParentContainer().getNodes()) {
if (attachedToId.equals(node.getMetaData().get("UniqueId"))) {
attachedToNode = node;
break;
}
}
if (attachedToNode == null) {
throw new IllegalArgumentException("Boundary Event [" + ((String) eventNode.getMetaData("UniqueId")) + "] is not attached to a node [" + attachedToId + "] that can be found.");
}
if (!(attachedToNode instanceof RuleSetNode || attachedToNode instanceof WorkItemNode || attachedToNode instanceof ActionNode || attachedToNode instanceof HumanTaskNode || attachedToNode instanceof CompositeNode || attachedToNode instanceof SubProcessNode)) {
throw new IllegalArgumentException("Compensation Boundary Event [" + ((String) eventNode.getMetaData("UniqueId")) + "] must be attached to a task or sub-process.");
}
// - associated node is a task or subProcess
compensationCheckPassed = false;
if (target instanceof WorkItemNode || target instanceof HumanTaskNode || target instanceof CompositeContextNode || target instanceof SubProcessNode) {
compensationCheckPassed = true;
} else if (target instanceof ActionNode) {
Object nodeTypeObj = ((ActionNode) target).getMetaData("NodeType");
if (nodeTypeObj != null && nodeTypeObj.equals("ScriptTask")) {
compensationCheckPassed = true;
}
}
if (!compensationCheckPassed) {
throw new IllegalArgumentException("An Activity [" + ((String) ((NodeImpl) target).getMetaData("UniqueId")) + "] associated with a Boundary Compensation Event must be a Task or a (non-Event) Sub-Process");
}
// - associated node does not have outgoingConnections of it's own
compensationCheckPassed = true;
NodeImpl targetNode = (NodeImpl) target;
Map<String, List<io.automatiko.engine.api.definition.process.Connection>> connectionsMap = targetNode.getOutgoingConnections();
ConnectionImpl outgoingConnection = null;
for (String connectionType : connectionsMap.keySet()) {
List<io.automatiko.engine.api.definition.process.Connection> connections = connectionsMap.get(connectionType);
if (connections != null && !connections.isEmpty()) {
for (io.automatiko.engine.api.definition.process.Connection connection : connections) {
Object hiddenObj = connection.getMetaData().get("hidden");
if (hiddenObj != null && ((Boolean) hiddenObj)) {
continue;
}
outgoingConnection = (ConnectionImpl) connection;
compensationCheckPassed = false;
break;
}
}
}
if (!compensationCheckPassed) {
throw new IllegalArgumentException("A Compensation Activity [" + ((String) targetNode.getMetaData("UniqueId")) + "] may not have any outgoing connection [" + (String) outgoingConnection.getMetaData("UniqueId") + "]");
}
}
use of io.automatiko.engine.workflow.process.core.node.CompositeContextNode in project automatiko-engine by automatiko-io.
the class CompensationTest method createNestedCompensationEventSubProcessProcess.
private ExecutableProcess createNestedCompensationEventSubProcessProcess(String processId, String[] workItemNames, final List<String> eventList) throws Exception {
ExecutableProcess process = new ExecutableProcess();
process.setAutoComplete(true);
process.setId(processId);
process.setName("CESP Process");
process.setMetaData("Compensation", true);
NodeCreator<StartNode> startNodeCreator = new NodeCreator<StartNode>(process, StartNode.class);
NodeCreator<WorkItemNode> workItemNodeCreator = new NodeCreator<WorkItemNode>(process, WorkItemNode.class);
NodeCreator<CompositeContextNode> compNodeCreator = new NodeCreator<CompositeContextNode>(process, CompositeContextNode.class);
NodeCreator<EndNode> endNodeCreator = new NodeCreator<EndNode>(process, EndNode.class);
// outer process
CompositeContextNode compositeNode = compNodeCreator.createNode("sub0");
{
StartNode startNode = startNodeCreator.createNode("start0");
WorkItemNode workItemNode = workItemNodeCreator.createNode("work0-pre");
workItemNode.getWork().setName(workItemNames[0]);
connect(startNode, workItemNode);
connect(workItemNode, compositeNode);
EndNode endNode = endNodeCreator.createNode("end0");
connect(compositeNode, endNode);
}
// 1rst level nested subprocess (contains compensation visibility scope)
CompositeContextNode compensationScopeContainerNode = compositeNode;
{
startNodeCreator.setNodeContainer(compositeNode);
workItemNodeCreator.setNodeContainer(compositeNode);
compNodeCreator.setNodeContainer(compositeNode);
endNodeCreator.setNodeContainer(compositeNode);
StartNode startNode = startNodeCreator.createNode("start1");
CompositeContextNode subCompNode = compNodeCreator.createNode("sub1");
connect(startNode, subCompNode);
WorkItemNode workItemNode = workItemNodeCreator.createNode("work1-post");
workItemNode.getWork().setName(workItemNames[2]);
connect(subCompNode, workItemNode);
EndNode endNode = endNodeCreator.createNode("end1");
connect(workItemNode, endNode);
compositeNode = subCompNode;
}
// 2nd level nested subprocess
{
startNodeCreator.setNodeContainer(compositeNode);
workItemNodeCreator.setNodeContainer(compositeNode);
endNodeCreator.setNodeContainer(compositeNode);
StartNode startNode = startNodeCreator.createNode("start2");
WorkItemNode workItemNode = workItemNodeCreator.createNode("work2");
workItemNode.getWork().setName(workItemNames[1]);
connect(startNode, workItemNode);
EndNode endNode = endNodeCreator.createNode("end2");
connect(workItemNode, endNode);
}
// 3nd level nested event subprocess in 2nd level subprocess
{
NodeCreator<EventSubProcessNode> espNodeCreator = new NodeCreator<EventSubProcessNode>(compositeNode, EventSubProcessNode.class);
EventSubProcessNode espNode = espNodeCreator.createNode("eventSub2");
startNodeCreator.setNodeContainer(espNode);
endNodeCreator.setNodeContainer(espNode);
NodeCreator<ActionNode> actionNodeCreator = new NodeCreator<ActionNode>(espNode, ActionNode.class);
EventTypeFilter eventFilter = new NonAcceptingEventTypeFilter();
eventFilter.setType("Compensation");
espNode.addEvent(eventFilter);
addCompensationScope(espNode, compensationScopeContainerNode, (String) compositeNode.getMetaData("UniqueId"));
StartNode startNode = startNodeCreator.createNode("start3*");
ActionNode actionNode = actionNodeCreator.createNode("action3*");
actionNode.setName("Execute");
ProcessAction action = new ConsequenceAction("java", null);
action.setMetaData("Action", new Action() {
public void execute(ProcessContext context) throws Exception {
eventList.add("Executed action");
}
});
actionNode.setAction(action);
connect(startNode, actionNode);
EndNode endNode = endNodeCreator.createNode("end3*");
connect(actionNode, endNode);
}
return process;
}
use of io.automatiko.engine.workflow.process.core.node.CompositeContextNode in project automatiko-engine by automatiko-io.
the class AssociationHandler method start.
public Object start(final String uri, final String localName, final Attributes attrs, final ExtensibleXmlParser parser) throws SAXException {
parser.startElementBuilder(localName, attrs);
Association association = new Association();
association.setId(attrs.getValue("id"));
association.setSourceRef(attrs.getValue("sourceRef"));
association.setTargetRef(attrs.getValue("targetRef"));
String direction = attrs.getValue("associationDirection");
if (direction != null) {
boolean acceptableDirection = false;
direction = direction.toLowerCase();
String[] possibleDirections = { "none", "one", "both" };
for (String acceptable : possibleDirections) {
if (acceptable.equals(direction)) {
acceptableDirection = true;
break;
}
}
if (!acceptableDirection) {
throw new IllegalArgumentException("Unknown direction '" + direction + "' used in Association " + association.getId());
}
}
association.setDirection(direction);
/**
* BPMN2 spec, p. 66: "At this point, BPMN provides three standard Artifacts:
* Associations, Groups, and Text Annotations. ... When an Artifact is defined
* it is contained within a Collaboration or a FlowElementsContainer (a Process
* or Choreography)."
*
* (In other words: associations must be defined within a process, not outside)
*/
List<Association> associations = null;
NodeContainer nodeContainer = (NodeContainer) parser.getParent();
if (nodeContainer instanceof Process) {
ExecutableProcess process = (ExecutableProcess) nodeContainer;
associations = (List<Association>) process.getMetaData(ASSOCIATIONS);
if (associations == null) {
associations = new ArrayList<>();
process.setMetaData(ASSOCIATIONS, associations);
}
} else if (nodeContainer instanceof CompositeNode) {
CompositeContextNode compositeNode = (CompositeContextNode) nodeContainer;
associations = (List<Association>) compositeNode.getMetaData(ASSOCIATIONS);
if (associations == null) {
associations = new ArrayList<>();
compositeNode.setMetaData(ProcessHandler.ASSOCIATIONS, associations);
}
} else {
associations = new ArrayList<>();
}
associations.add(association);
return association;
}
use of io.automatiko.engine.workflow.process.core.node.CompositeContextNode in project automatiko-engine by automatiko-io.
the class CompensationTest method createCompensationEventSubProcessProcess.
private ExecutableProcess createCompensationEventSubProcessProcess(String processId, String[] workItemNames, final List<String> eventList) throws Exception {
ExecutableProcess process = new ExecutableProcess();
process.setAutoComplete(true);
process.setId(processId);
process.setName("CESP Process");
process.setMetaData("Compensation", true);
NodeCreator<StartNode> startNodeCreator = new NodeCreator<StartNode>(process, StartNode.class);
NodeCreator<WorkItemNode> workItemNodeCreator = new NodeCreator<WorkItemNode>(process, WorkItemNode.class);
NodeCreator<CompositeContextNode> compNodeCreator = new NodeCreator<CompositeContextNode>(process, CompositeContextNode.class);
NodeCreator<EndNode> endNodeCreator = new NodeCreator<EndNode>(process, EndNode.class);
// outer process
StartNode startNode = startNodeCreator.createNode("start0");
WorkItemNode workItemNode = workItemNodeCreator.createNode("work0-pre");
workItemNode.getWork().setName(workItemNames[0]);
connect(startNode, workItemNode);
CompositeNode compositeNode = compNodeCreator.createNode("sub0");
connect(workItemNode, compositeNode);
workItemNode = workItemNodeCreator.createNode("work0-post");
workItemNode.getWork().setName(workItemNames[2]);
connect(compositeNode, workItemNode);
EndNode endNode = endNodeCreator.createNode("end0");
connect(workItemNode, endNode);
// 1rst level nested subprocess
startNodeCreator.setNodeContainer(compositeNode);
workItemNodeCreator.setNodeContainer(compositeNode);
endNodeCreator.setNodeContainer(compositeNode);
startNode = startNodeCreator.createNode("start1");
workItemNode = workItemNodeCreator.createNode("work1");
workItemNode.getWork().setName(workItemNames[1]);
connect(startNode, workItemNode);
endNode = endNodeCreator.createNode("end1");
connect(workItemNode, endNode);
// 2nd level nested event subprocess in 1rst level subprocess
NodeCreator<EventSubProcessNode> espNodeCreator = new NodeCreator<EventSubProcessNode>(compositeNode, EventSubProcessNode.class);
EventSubProcessNode espNode = espNodeCreator.createNode("eventSub1");
EventTypeFilter eventFilter = new NonAcceptingEventTypeFilter();
eventFilter.setType("Compensation");
espNode.addEvent(eventFilter);
addCompensationScope(espNode, process, (String) compositeNode.getMetaData("UniqueId"));
startNodeCreator.setNodeContainer(espNode);
endNodeCreator.setNodeContainer(espNode);
NodeCreator<ActionNode> actionNodeCreator = new NodeCreator<ActionNode>(espNode, ActionNode.class);
startNode = startNodeCreator.createNode("start1*");
ActionNode actionNode = actionNodeCreator.createNode("action1*");
actionNode.setName("Execute");
ProcessAction action = new ConsequenceAction("java", null);
action.setMetaData("Action", new Action() {
public void execute(ProcessContext context) throws Exception {
eventList.add("Executed action");
}
});
actionNode.setAction(action);
connect(startNode, actionNode);
endNode = endNodeCreator.createNode("end1*");
connect(actionNode, endNode);
return process;
}
use of io.automatiko.engine.workflow.process.core.node.CompositeContextNode in project automatiko-engine by automatiko-io.
the class CompensationTest method createNestedCompensationBoundaryEventProcess.
private ExecutableProcess createNestedCompensationBoundaryEventProcess(String processId, String[] workItemNames, final List<String> eventList) throws Exception {
ExecutableProcess process = new ExecutableProcess();
process.setAutoComplete(true);
process.setId(processId);
process.setName("CESP Process");
process.setMetaData("Compensation", true);
List<Variable> variables = new ArrayList<Variable>();
Variable variable = new Variable();
variable.setName("event");
ObjectDataType personDataType = new ObjectDataType(java.lang.String.class);
variable.setType(personDataType);
variables.add(variable);
process.getVariableScope().setVariables(variables);
NodeCreator<StartNode> startNodeCreator = new NodeCreator<StartNode>(process, StartNode.class);
NodeCreator<EndNode> endNodeCreator = new NodeCreator<EndNode>(process, EndNode.class);
NodeCreator<CompositeContextNode> compNodeCreator = new NodeCreator<CompositeContextNode>(process, CompositeContextNode.class);
// process level
CompositeContextNode compositeNode = compNodeCreator.createNode("sub0");
{
StartNode startNode = startNodeCreator.createNode("start0");
connect(startNode, compositeNode);
EndNode endNode = endNodeCreator.createNode("end0");
connect(compositeNode, endNode);
}
// 1rst level nested subprocess (contains compensation visibility scope)
{
startNodeCreator.setNodeContainer(compositeNode);
compNodeCreator.setNodeContainer(compositeNode);
endNodeCreator.setNodeContainer(compositeNode);
StartNode startNode = startNodeCreator.createNode("start1");
CompositeContextNode subCompNode = compNodeCreator.createNode("sub1");
connect(startNode, subCompNode);
EndNode endNode = endNodeCreator.createNode("end1");
connect(subCompNode, endNode);
compositeNode = subCompNode;
}
// 2nd level nested subprocess (contains compensation visibility scope)
NodeCreator<WorkItemNode> workItemNodeCreator = new NodeCreator<WorkItemNode>(compositeNode, WorkItemNode.class);
{
startNodeCreator.setNodeContainer(compositeNode);
compNodeCreator.setNodeContainer(compositeNode);
endNodeCreator.setNodeContainer(compositeNode);
StartNode startNode = startNodeCreator.createNode("start2");
CompositeContextNode subCompNode = compNodeCreator.createNode("sub2");
connect(startNode, subCompNode);
WorkItemNode workItemNode = workItemNodeCreator.createNode("work2");
workItemNode.getWork().setName(workItemNames[2]);
connect(subCompNode, workItemNode);
EndNode endNode = endNodeCreator.createNode("end2");
connect(workItemNode, endNode);
createBoundaryEventCompensationHandler(compositeNode, workItemNode, eventList, "2");
compositeNode = subCompNode;
}
// Fill 3rd level with process with compensation
{
startNodeCreator.setNodeContainer(compositeNode);
workItemNodeCreator.setNodeContainer(compositeNode);
endNodeCreator.setNodeContainer(compositeNode);
StartNode startNode = startNodeCreator.createNode("start");
Node lastNode = startNode;
WorkItemNode[] workItemNodes = new WorkItemNode[3];
for (int i = 0; i < 2; ++i) {
workItemNodes[i] = workItemNodeCreator.createNode("work-comp-" + (i + 1));
workItemNodes[i].getWork().setName(workItemNames[i]);
connect(lastNode, workItemNodes[i]);
lastNode = workItemNodes[i];
}
EndNode endNode = endNodeCreator.createNode("end");
connect(workItemNodes[1], endNode);
// Compensation (boundary event) handlers
for (int i = 0; i < 2; ++i) {
createBoundaryEventCompensationHandler(compositeNode, workItemNodes[i], eventList, "" + i + 1);
}
}
return process;
}
Aggregations