private static void checkBoundaryEventCompensationHandler()

in jbpm/jbpm-bpmn2/src/main/java/org/jbpm/bpmn2/xml/ProcessHandler.java [712:817]


    private static void checkBoundaryEventCompensationHandler(Association association, Node source, Node target) {
        // check that 
        // - event node is boundary event node
        if (!(source instanceof BoundaryEventNode)) {
            throw new ProcessParsingValidationException("(Compensation) activities may only be associated with Boundary Event Nodes (not with" +
                    source.getClass().getSimpleName() + " nodes [node " + source.getUniqueId() + "].");
        }
        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 ProcessParsingValidationException("An Event [" + eventNode.getUniqueId()
                    + "] 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.getUniqueId())) {
                attachedToNode = node;
                break;
            }
        }
        if (attachedToNode == null) {
            throw new ProcessParsingValidationException("Boundary Event [" + eventNode.getUniqueId()
                    + "] 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 ProcessParsingValidationException("Compensation Boundary Event [" + eventNode.getUniqueId()
                    + "] 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 ProcessParsingValidationException("An Activity ["
                    + ((NodeImpl) target).getUniqueId() +
                    "] 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<org.kie.api.definition.process.Connection>> connectionsMap = targetNode.getOutgoingConnections();
        ConnectionImpl outgoingConnection = null;
        for (String connectionType : connectionsMap.keySet()) {
            List<org.kie.api.definition.process.Connection> connections = connectionsMap.get(connectionType);
            if (connections != null && !connections.isEmpty()) {
                for (org.kie.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 ProcessParsingValidationException("A Compensation Activity ["
                    + targetNode.getUniqueId()
                    + "] may not have any outgoing connection ["
                    + (String) outgoingConnection.getUniqueId() + "]");
        }
    }