Search in sources :

Example 1 with DataObjectType

use of de.hpi.bpt.scylla.model.process.node.DataObjectType in project scylla by bptlab.

the class ProcessModelParser method parseProcess.

private ProcessModel parseProcess(Element process, Namespace bpmnNamespace, boolean hasParentModel, CommonProcessElements commonProcessElements) throws ScyllaValidationException {
    if (!hasParentModel && process.getChildren("startEvent", bpmnNamespace).size() == 0) {
        throw new ScyllaValidationException("No start event in the top process.");
    }
    String processId = process.getAttributeValue("id");
    String processName = process.getAttributeValue("name");
    Graph<Integer> graph = new Graph<Integer>();
    Map<Integer, String> identifiers = new HashMap<Integer, String>();
    Map<String, Integer> identifiersToNodeIds = new HashMap<String, Integer>();
    Map<Integer, String> displayNames = new HashMap<Integer, String>();
    // node id must be key of any of the following
    Map<Integer, ProcessModel> subProcesses = new HashMap<Integer, ProcessModel>();
    Map<Integer, String> calledElementsOfCallActivities = new HashMap<Integer, String>();
    Map<Integer, TaskType> tasks = new HashMap<Integer, TaskType>();
    Map<Integer, GatewayType> gateways = new HashMap<Integer, GatewayType>();
    Map<Integer, EventType> eventTypes = new HashMap<Integer, EventType>();
    // optional
    Map<Integer, Map<String, String>> nodeAttributes = new HashMap<Integer, Map<String, String>>();
    Map<Integer, String> conditionExpressions = new HashMap<Integer, String>();
    Map<Integer, Set<String>> resourceReferences = new HashMap<Integer, Set<String>>();
    Map<Integer, Map<EventDefinitionType, Map<String, String>>> eventDefinitions = new HashMap<Integer, Map<EventDefinitionType, Map<String, String>>>();
    Map<Integer, Boolean> cancelActivities = new HashMap<Integer, Boolean>();
    Map<Integer, List<Integer>> referencesToBoundaryEvents = new HashMap<Integer, List<Integer>>();
    Map<Integer, BatchActivity> batchActivities = new HashMap<Integer, BatchActivity>();
    // TODO support more than standard data objects (i.e. support input, output)
    Graph<Integer> dataObjectsGraph = new Graph<Integer>();
    Map<Integer, String> dataObjectReferences = new HashMap<Integer, String>();
    Map<Integer, DataObjectType> dataObjectTypes = new HashMap<Integer, DataObjectType>();
    // TODO parse loop / multi instance elements
    Map<Integer, Element> boundaryEvents = new HashMap<Integer, Element>();
    Map<Integer, Element> sequenceFlows = new HashMap<Integer, Element>();
    // not only tasks anymore, also events
    Map<Integer, List<Element>> tasksWithDataInputAssociations = new HashMap<Integer, List<Element>>();
    // not only tasks anymore, also events
    Map<Integer, List<Element>> tasksWithDataOutputAssociations = new HashMap<Integer, List<Element>>();
    int nodeId = 1;
    for (Element el : process.getChildren()) {
        String elementName = el.getName();
        if (isKnownElement(elementName)) {
            String identifier = el.getAttributeValue("id");
            identifiers.put(nodeId, identifier);
            identifiersToNodeIds.put(identifier, nodeId);
            String displayName = el.getAttributeValue("name");
            if (displayName != null && !displayName.isEmpty()) {
                displayNames.put(nodeId, displayName);
            }
            if (elementName.equals("sequenceFlow")) {
                // just store them for now, use later to build graph
                sequenceFlows.put(nodeId, el);
                // store expressions after gateway conditions
                Element conditionExpression = el.getChild("conditionExpression", bpmnNamespace);
                if (conditionExpression != null) {
                    conditionExpressions.put(nodeId, conditionExpression.getText());
                }
            } else if (elementName.equals("subProcess")) {
                batchActivities = parseExtensions(el, bpmnNamespace, nodeId, batchActivities);
                ProcessModel subProcessModel = parseProcess(el, bpmnNamespace, true, commonProcessElements);
                subProcesses.put(nodeId, subProcessModel);
            } else if (elementName.equals("callActivity")) {
                String calledElement = el.getAttributeValue("calledElement");
                if (calledElement != null) {
                    calledElementsOfCallActivities.put(nodeId, calledElement);
                }
            } else if (elementName.equals("task") || elementName.endsWith("Task")) {
                batchActivities = parseExtensions(el, bpmnNamespace, nodeId, batchActivities);
                tasks.put(nodeId, TaskType.getEnum(el.getName()));
                if (elementName.equals("userTask") || elementName.equals("manualTask")) {
                    String[] resourceElementNames = new String[] { "resourceRole", "performer", "humanPerformer", "potentialOwner" };
                    for (String ren : resourceElementNames) {
                        Element elem = el.getChild(ren, bpmnNamespace);
                        if (elem != null) {
                            String resourceRefOrAssignmentExpression = null;
                            Element resourceRefElement = elem.getChild("resourceRef", bpmnNamespace);
                            if (resourceRefElement != null) {
                                resourceRefOrAssignmentExpression = resourceRefElement.getText();
                            }
                            Element resourceAssignmentExpressionElement = elem.getChild("resourceAssignmentExpression", bpmnNamespace);
                            if (resourceAssignmentExpressionElement != null) {
                                resourceRefOrAssignmentExpression = resourceAssignmentExpressionElement.getText();
                            }
                            if (resourceRefOrAssignmentExpression != null) {
                                if (!resourceReferences.containsKey(nodeId)) {
                                    resourceReferences.put(nodeId, new TreeSet<String>());
                                }
                                resourceReferences.get(nodeId).add(resourceRefOrAssignmentExpression);
                                break;
                            }
                        }
                    }
                }
                List<Element> dataInElements = el.getChildren("dataInputAssociation", bpmnNamespace);
                if (!dataInElements.isEmpty()) {
                    tasksWithDataInputAssociations.put(nodeId, dataInElements);
                }
                List<Element> dataOutElements = el.getChildren("dataOutputAssociation", bpmnNamespace);
                if (!dataOutElements.isEmpty()) {
                    tasksWithDataOutputAssociations.put(nodeId, dataOutElements);
                }
            } else if (elementName.endsWith("Gateway") || elementName.equals("gateway")) {
                gateways.put(nodeId, GatewayType.getEnum(el.getName()));
                Map<String, String> gatewayAttributes = new HashMap<String, String>();
                String defaultFlow = el.getAttributeValue("default");
                if (defaultFlow != null) {
                    gatewayAttributes.put("default", defaultFlow);
                }
                String gatewayDirection = el.getAttributeValue("gatewayDirection");
                if (gatewayDirection != null) {
                    gatewayAttributes.put("gatewayDirection", gatewayDirection);
                }
                nodeAttributes.put(nodeId, gatewayAttributes);
            } else if (elementName.endsWith("Event") || elementName.equals("event")) {
                eventTypes.put(nodeId, EventType.getEnum(el.getName()));
                Map<EventDefinitionType, Map<String, String>> eventDefinitionsOfElement = new HashMap<EventDefinitionType, Map<String, String>>();
                for (EventDefinitionType edt : EventDefinitionType.values()) {
                    Element edElem = el.getChild(edt.toString(), bpmnNamespace);
                    if (edElem != null) {
                        Map<String, String> eventAttributes = new HashMap<String, String>();
                        if (edt == EventDefinitionType.CANCEL) {
                        // TODO transaction subprocesses only
                        } else if (edt == EventDefinitionType.COMPENSATION) {
                            String activityRef = edElem.getAttributeValue("activityRef");
                            if (activityRef != null) {
                                eventAttributes.put("activityRef", activityRef);
                            }
                            String waitForCompletion = edElem.getAttributeValue("waitForCompletion");
                            if (waitForCompletion != null) {
                                eventAttributes.put("waitForCompletion", waitForCompletion);
                            }
                        } else if (edt == EventDefinitionType.CONDITIONAL) {
                            Element conditionElement = edElem.getChild("condition", bpmnNamespace);
                            if (conditionElement != null) {
                                eventAttributes.put("condition", conditionElement.getText());
                            }
                        } else if (edt == EventDefinitionType.ERROR) {
                            String errorRef = edElem.getAttributeValue("errorRef");
                            if (errorRef != null) {
                                if (!commonProcessElements.getErrors().containsKey(errorRef)) {
                                    throw new ScyllaValidationException("Referenced object of error event " + identifier + " is unknown: " + errorRef);
                                }
                                eventAttributes.put("errorRef", errorRef);
                            } else {
                                throw new ScyllaValidationException("Error event " + identifier + " has no reference to an error.");
                            }
                        } else if (edt == EventDefinitionType.ESCALATION) {
                            String escalationRef = edElem.getAttributeValue("escalationRef");
                            if (escalationRef != null) {
                                if (!commonProcessElements.getEscalations().containsKey(escalationRef)) {
                                    throw new ScyllaValidationException("Referenced object of escalation event " + identifier + " is unknown: " + escalationRef);
                                }
                                eventAttributes.put("escalationRef", escalationRef);
                            } else {
                                throw new ScyllaValidationException("Escalation event " + identifier + " has no reference to an escalation.");
                            }
                        } else if (edt == EventDefinitionType.LINK) {
                            String name = edElem.getAttributeValue("name");
                            if (name != null) {
                                eventAttributes.put("name", name);
                            }
                            List<Element> sourceElements = edElem.getChildren("source", bpmnNamespace);
                            int i = 0;
                            for (Element sourceElement : sourceElements) {
                                eventAttributes.put("source" + ++i, sourceElement.getText());
                            }
                            Element targetElement = edElem.getChild("target", bpmnNamespace);
                            if (targetElement != null) {
                                eventAttributes.put("target", targetElement.getText());
                            }
                        } else if (edt == EventDefinitionType.MESSAGE) {
                            String messageRef = edElem.getAttributeValue("messageRef");
                            if (messageRef != null) {
                                if (!commonProcessElements.getMessages().containsKey(messageRef)) {
                                    throw new ScyllaValidationException("Referenced object of message event " + identifier + " is unknown: " + messageRef);
                                }
                                eventAttributes.put("messageRef", messageRef);
                            }
                            Element operationElement = edElem.getChild("operationRef", bpmnNamespace);
                            if (operationElement != null) {
                                eventAttributes.put("operationRef", operationElement.getText());
                            }
                        } else if (edt == EventDefinitionType.SIGNAL) {
                            String signalRef = edElem.getAttributeValue("signalRef");
                            if (signalRef != null) {
                                eventAttributes.put("signalRef", signalRef);
                            }
                        } else if (edt == EventDefinitionType.TIMER) {
                            Element timeDateElement = edElem.getChild("timeDate", bpmnNamespace);
                            // this is the reponsibility of the plug-ins
                            if (timeDateElement != null) {
                                eventAttributes.put("timeDate", timeDateElement.getText());
                            }
                            Element timeCycleElement = edElem.getChild("timeCycle", bpmnNamespace);
                            if (timeCycleElement != null) {
                                eventAttributes.put("timeCycle", timeCycleElement.getText());
                            }
                            Element timeDurationElement = edElem.getChild("timeDuration", bpmnNamespace);
                            if (timeDurationElement != null) {
                                eventAttributes.put("timeDuration", timeDurationElement.getText());
                            }
                            // time attributes are mutually exclusive
                            if (eventAttributes.size() > 1) {
                                throw new ScyllaValidationException("Timer event " + identifier + " is invalid. Time definitions are mutually exclusive.");
                            }
                        }
                        eventDefinitionsOfElement.put(edt, eventAttributes);
                    }
                    eventDefinitions.put(nodeId, eventDefinitionsOfElement);
                    if (elementName.equals("boundaryEvent")) {
                        // just store them for now, use later to create references to boundary events
                        boundaryEvents.put(nodeId, el);
                    }
                }
                List<Element> dataInElements = el.getChildren("dataInputAssociation", bpmnNamespace);
                if (!dataInElements.isEmpty()) {
                    tasksWithDataInputAssociations.put(nodeId, dataInElements);
                }
                List<Element> dataOutElements = el.getChildren("dataOutputAssociation", bpmnNamespace);
                if (!dataOutElements.isEmpty()) {
                    tasksWithDataOutputAssociations.put(nodeId, dataOutElements);
                }
            } else if (elementName.equals("dataObjectReference")) {
                String dataObjectRef = el.getAttributeValue("dataObjectRef");
                dataObjectReferences.put(nodeId, dataObjectRef);
            } else if (elementName.equals("ioSpecification")) {
                Element input = el.getChild("dataInput", bpmnNamespace);
                if (input != null) {
                    // remove the ioSpecification element
                    identifiersToNodeIds.remove(identifier);
                    // override the values with the inner input element
                    identifier = input.getAttributeValue("id");
                    identifiers.put(nodeId, identifier);
                    identifiersToNodeIds.put(identifier, nodeId);
                    displayName = input.getAttributeValue("name");
                    if (displayName != null && !displayName.isEmpty()) {
                        displayNames.put(nodeId, displayName);
                    }
                    dataObjectTypes.put(nodeId, DataObjectType.INPUT);
                }
            } else if (elementName.equals("dataObject")) {
                dataObjectTypes.put(nodeId, DataObjectType.DEFAULT);
            } else {
                DebugLogger.log("Element " + el.getName() + " of process model is expected to be known, but not supported.");
            }
            nodeId++;
        } else {
            DebugLogger.log("Element " + el.getName() + " of process model not supported.");
        }
    }
    // create resource references
    for (Element laneSet : process.getChildren("laneSet", bpmnNamespace)) {
        for (Element lane : laneSet.getChildren("lane", bpmnNamespace)) {
            String resourceName = lane.getAttributeValue("name");
            for (Element flowNodeRef : lane.getChildren("flowNodeRef", bpmnNamespace)) {
                String elementId = flowNodeRef.getText();
                Integer nId = identifiersToNodeIds.get(elementId);
                if (!resourceReferences.containsKey(nId)) {
                    resourceReferences.put(nId, new TreeSet<String>());
                }
                resourceReferences.get(nId).add(resourceName);
            }
        }
    }
    for (Integer nId : boundaryEvents.keySet()) {
        Element boundaryEvent = boundaryEvents.get(nId);
        // interrupting or not?
        // initially true, because at least "Camunda Modeler" does not set the cancelActivity value if it is an interrupting activity
        boolean cancelActivity;
        if (boundaryEvent.getAttributeValue("cancelActivity") != null) {
            cancelActivity = Boolean.valueOf(boundaryEvent.getAttributeValue("cancelActivity"));
        } else {
            cancelActivity = true;
        }
        cancelActivities.put(nId, cancelActivity);
        // attached to?
        String attachedTo = boundaryEvent.getAttributeValue("attachedToRef");
        int nodeIdOfAttachedTo = identifiersToNodeIds.get(attachedTo);
        if (!referencesToBoundaryEvents.containsKey(nodeIdOfAttachedTo)) {
            referencesToBoundaryEvents.put(nodeIdOfAttachedTo, new ArrayList<Integer>());
        }
        referencesToBoundaryEvents.get(nodeIdOfAttachedTo).add(nId);
    }
    // System.out.println("-----------NORMALFLOW-------------");
    for (Integer nId : sequenceFlows.keySet()) {
        Element sequenceFlow = sequenceFlows.get(nId);
        String sourceRef = sequenceFlow.getAttributeValue("sourceRef");
        String targetRef = sequenceFlow.getAttributeValue("targetRef");
        int sourceId = identifiersToNodeIds.get(sourceRef);
        int targetId = identifiersToNodeIds.get(targetRef);
        graph.addEdge(sourceId, nId);
        // System.out.println(identifiers.get(sourceId)+" -> "+identifiers.get(nId)+" -> "+identifiers.get(targetId));
        graph.addEdge(nId, targetId);
    }
    // System.out.println("-----------DATAFLOWOUT-------------");
    for (Integer nId : tasksWithDataInputAssociations.keySet()) {
        List<Element> dataInputAssociations = tasksWithDataInputAssociations.get(nId);
        for (Element elem : dataInputAssociations) {
            String sourceRef = elem.getChild("sourceRef", bpmnNamespace).getText();
            if (identifiersToNodeIds.containsKey(sourceRef)) {
                int dataObjectNodeId = identifiersToNodeIds.get(sourceRef);
                // System.out.println(identifiers.get(dataObjectNodeId)+" -> "+identifiers.get(nId));
                dataObjectsGraph.addEdge(dataObjectNodeId, nId);
            /*Map<Integer, Node<Integer>> nodes = dataObjectsGraph.getNodes();
                    Node<Integer> currentNode = nodes.get(nId);
                    currentNode.setId(identifiers.get(nId));   
                    currentNode = nodes.get(dataObjectNodeId);
                    currentNode.setId(identifiers.get(dataObjectNodeId));*/
            }
        // String targetRef = elem.getChild("targetRef", bpmnNamespace).getText();
        }
    }
    // System.out.println("-----------DATAFLOWIN-------------");
    for (Integer nId : tasksWithDataOutputAssociations.keySet()) {
        List<Element> dataOutputAssociations = tasksWithDataOutputAssociations.get(nId);
        for (Element elem : dataOutputAssociations) {
            // String sourceRef = elem.getChild("sourceRef", bpmnNamespace).getText();
            String targetRef = elem.getChild("targetRef", bpmnNamespace).getText();
            if (identifiersToNodeIds.containsKey(targetRef)) {
                int dataObjectNodeId = identifiersToNodeIds.get(targetRef);
                // System.out.println(identifiers.get(nId)+" -> "+identifiers.get(dataObjectNodeId));
                dataObjectsGraph.addEdge(nId, dataObjectNodeId);
            /*Map<Integer, Node<Integer>> nodes = dataObjectsGraph.getNodes();
                    Node<Integer> currentNode = nodes.get(nId);
                    currentNode.setId(identifiers.get(nId));   
                    currentNode = nodes.get(dataObjectNodeId);
                    currentNode.setId(identifiers.get(dataObjectNodeId));*/
            }
        }
    }
    ProcessModel processModel = new ProcessModel(processId, process, graph, identifiers, identifiersToNodeIds, displayNames, subProcesses, calledElementsOfCallActivities, tasks, gateways, eventTypes);
    processModel.setName(processName);
    processModel.setNodeAttributes(nodeAttributes);
    processModel.setConditionExpressions(conditionExpressions);
    processModel.setResourceReferences(resourceReferences);
    processModel.setEventDefinitions(eventDefinitions);
    processModel.setCancelActivities(cancelActivities);
    processModel.setReferencesToBoundaryEvents(referencesToBoundaryEvents);
    processModel.setDataObjectsGraph(dataObjectsGraph);
    processModel.setDataObjectTypes(dataObjectTypes);
    processModel.setDataObjectReferences(dataObjectReferences);
    processModel.setBatchActivities(batchActivities);
    batchActivities.forEach((key, value) -> value.setProcessModel(processModel));
    for (Integer subProcessId : subProcesses.keySet()) {
        ProcessModel subProcessModel = subProcesses.get(subProcessId);
        subProcessModel.setNodeIdInParent(subProcessId);
        subProcessModel.setParent(processModel);
    }
    // System.out.println(dataObjectsGraph);
    return processModel;
}
Also used : ProcessModel(de.hpi.bpt.scylla.model.process.ProcessModel) EventType(de.hpi.bpt.scylla.model.process.node.EventType) Element(org.jdom2.Element) GatewayType(de.hpi.bpt.scylla.model.process.node.GatewayType) ScyllaValidationException(de.hpi.bpt.scylla.exception.ScyllaValidationException) TaskType(de.hpi.bpt.scylla.model.process.node.TaskType) DataObjectType(de.hpi.bpt.scylla.model.process.node.DataObjectType) EventDefinitionType(de.hpi.bpt.scylla.model.process.node.EventDefinitionType) Graph(de.hpi.bpt.scylla.model.process.graph.Graph)

Aggregations

ScyllaValidationException (de.hpi.bpt.scylla.exception.ScyllaValidationException)1 ProcessModel (de.hpi.bpt.scylla.model.process.ProcessModel)1 Graph (de.hpi.bpt.scylla.model.process.graph.Graph)1 DataObjectType (de.hpi.bpt.scylla.model.process.node.DataObjectType)1 EventDefinitionType (de.hpi.bpt.scylla.model.process.node.EventDefinitionType)1 EventType (de.hpi.bpt.scylla.model.process.node.EventType)1 GatewayType (de.hpi.bpt.scylla.model.process.node.GatewayType)1 TaskType (de.hpi.bpt.scylla.model.process.node.TaskType)1 Element (org.jdom2.Element)1