package sushi.bpmn.decomposition; import java.util.HashSet; import java.util.List; import java.util.Set; import sushi.bpmn.element.AbstractBPMNElement; import sushi.bpmn.element.BPMNAndGateway; import sushi.bpmn.element.BPMNEventBasedGateway; import sushi.bpmn.element.BPMNEventBasedGatewayType; import sushi.bpmn.element.BPMNXORGateway; import sushi.event.collection.SushiTree; /** * This class searches for bond components in the given tree and tries to assign {@link IPattern} as the {@link BondComponent#setType(IPattern)}. * @author micha * */ public class PatternUtil { /** * Searches in the given tree for bond components and try to assign {@link IPattern} to the components. * @param processDecompositionTree */ public static void determinePatternForTreeComponents(SushiTree<AbstractBPMNElement> processDecompositionTree){ for(AbstractBPMNElement element : processDecompositionTree.getElements()){ if(element instanceof BondComponent){ BondComponent bond = (BondComponent) element; List<AbstractBPMNElement> bondChildren = processDecompositionTree.getChildren(bond); determinePatternForComponent(bond, bondChildren, processDecompositionTree); } else if(element instanceof PolygonComponent){ ((PolygonComponent) element).setType(IPattern.SEQUENCE); } else if(element instanceof SubProcessComponent){ ((SubProcessComponent) element).setType(IPattern.SUBPROCESS); } } } private static void determinePatternForComponent(BondComponent bond, List<AbstractBPMNElement> bondChildren, SushiTree<AbstractBPMNElement> processDecompositionTree) { AbstractBPMNElement sourceElement = bond.getSourceElement(); AbstractBPMNElement sinkElement = bond.getSinkElement(); //Detection of different patterns if( (sourceElement instanceof BPMNAndGateway || (sourceElement instanceof BPMNEventBasedGateway && ((BPMNEventBasedGateway)sourceElement).getType().equals(BPMNEventBasedGatewayType.Parallel))) && sourceElement.getPredecessors().size() == 1){ bond.setType(IPattern.AND); } else if( (sourceElement instanceof BPMNXORGateway || (sourceElement instanceof BPMNEventBasedGateway && ((BPMNEventBasedGateway)sourceElement).getType().equals(BPMNEventBasedGatewayType.Exclusive))) && sourceElement.getPredecessors().size() == 1 || sinkElement instanceof BPMNXORGateway && sinkElement.getSuccessors().size() == 1){ bond.setType(IPattern.XOR); } else if(sourceElement instanceof BPMNXORGateway && isCyclic(bond, processDecompositionTree)){ bond.setType(IPattern.LOOP); } } private static boolean isCyclic(BondComponent bond, SushiTree<AbstractBPMNElement> processDecompositionTree){ Set<AbstractBPMNElement> bondChildren = processDecompositionTree.getLeafs(bond); AbstractBPMNElement sourceElement = bond.getSourceElement(); Set<AbstractBPMNElement> visitedElements = new HashSet<AbstractBPMNElement>(); visitSuccessors(sourceElement, bondChildren, visitedElements); return visitedElements.contains(sourceElement); } /** * Adds all indirect successors of the startElement to visitedElements, if the element is contained in elements. * @param startElement * @param elements * @param visitedElements */ private static void visitSuccessors(AbstractBPMNElement startElement, Set<AbstractBPMNElement> elements, Set<AbstractBPMNElement> visitedElements) { if(elements.contains(startElement) && !visitedElements.contains(startElement)){ visitedElements.add(startElement); for(AbstractBPMNElement successor : startElement.getSuccessors()){ visitSuccessors(successor, elements, visitedElements); } } } }