/* * Copyright 2015 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jbpm.simulation.handler; import java.util.ArrayList; import java.util.List; import org.eclipse.bpmn2.Activity; import org.eclipse.bpmn2.BoundaryEvent; import org.eclipse.bpmn2.FlowElement; import org.eclipse.bpmn2.SequenceFlow; import org.jbpm.simulation.PathContext; import org.jbpm.simulation.PathContextManager; import org.jbpm.simulation.util.WrappedBoundaryEvent; public class ActivityElementHandler extends MainElementHandler { public boolean handle(FlowElement element, PathContextManager manager) { List<SequenceFlow> outgoing = new ArrayList<SequenceFlow>(getOutgoing(element)); if (outgoing.isEmpty()) { return false; } PathContext context = manager.getContextFromStack(); List<BoundaryEvent> bEvents = ((Activity) element).getBoundaryEventRefs(); if (bEvents != null && !bEvents.isEmpty()) { boolean cancelActivity = false; for (BoundaryEvent bEvent : bEvents) { if (!context.getPathElements().contains(bEvent)) { manager.addToPath(bEvent, context); List<SequenceFlow> bOut = bEvent.getOutgoing(); outgoing.addAll(bOut); cancelActivity = bEvent.isCancelActivity(); handleSeparatePaths(outgoing, manager, bEvent); handleCombinedPaths(outgoing, manager); if (!cancelActivity) { handleAllPaths(outgoing, manager); } } else { HandlerRegistry.getHandler().handle(element, manager); } } return true; } else { HandlerRegistry.getHandler().handle(element, manager); return false; } } protected void handleSeparatePaths(List<SequenceFlow> outgoing, PathContextManager manager, BoundaryEvent bEvent) { List<PathContext> locked = new ArrayList<PathContext>(); PathContext context = manager.getContextFromStack(); for (SequenceFlow seqFlow : outgoing) { FlowElement target = seqFlow.getTargetRef(); PathContext separatePath = manager.cloneGiven(context); // replace boundary event with a wrapper if sequence flow does not go out if it if (!seqFlow.getSourceRef().equals(bEvent)) { separatePath.removePathElement(bEvent); separatePath.addPathElement(new WrappedBoundaryEvent(bEvent)); } manager.addToPath(seqFlow, separatePath); super.handle(target, manager); separatePath.setLocked(true); locked.add(separatePath); } // unlock for (PathContext ctx : locked) { ctx.setLocked(false); } } protected void handleAllPaths(List<SequenceFlow> outgoing, PathContextManager manager) { PathContext context = manager.getContextFromStack(); context.setCanBeFinished(false); int counter = 0; for (SequenceFlow seqFlow : outgoing) { counter++; FlowElement target = seqFlow.getTargetRef(); if (counter == outgoing.size()) { context.setCanBeFinished(true); } manager.addToPath(seqFlow, context); super.handle(target, manager); } } protected void handleCombinedPaths(List<SequenceFlow> outgoing, PathContextManager manager) { // next cover all combinations of paths if (outgoing.size() > 2) { List<SequenceFlow> copy = new ArrayList<SequenceFlow>(outgoing); List<SequenceFlow> andCombination = null; for (SequenceFlow flow : outgoing) { // first remove one that we currently processing as that is not // a combination copy.remove(flow); for (SequenceFlow copyFlow : copy) { manager.cloneGiven(manager.getContextFromStack()); andCombination = new ArrayList<SequenceFlow>(); andCombination.add(flow); andCombination.add(copyFlow); handleAllPaths(andCombination, manager); } } } } }