/* * Copyright 2014 Effektif GmbH. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * 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 com.effektif.workflow.impl.activity.types; import java.util.List; import java.util.Map; import javax.script.CompiledScript; import org.slf4j.Logger; import com.effektif.workflow.api.activities.ExclusiveGateway; import com.effektif.workflow.impl.WorkflowEngineImpl; import com.effektif.workflow.impl.WorkflowParser; import com.effektif.workflow.impl.activity.AbstractActivityType; import com.effektif.workflow.impl.conditions.ConditionService; import com.effektif.workflow.impl.workflow.ActivityImpl; import com.effektif.workflow.impl.workflow.TransitionImpl; import com.effektif.workflow.impl.workflowinstance.ActivityInstanceImpl; /** * @author Tom Baeyens */ public class ExclusiveGatewayImpl extends AbstractActivityType<ExclusiveGateway> { private static final Logger log = WorkflowEngineImpl.log; ConditionService conditionService; CompiledScript transitionIdExpression; Map<String, CompiledScript> transitionExpressions; public ExclusiveGatewayImpl() { super(ExclusiveGateway.class); } @Override public void parse(ActivityImpl activityImpl, ExclusiveGateway exclusiveGateway, WorkflowParser parser) { super.parse(activityImpl, exclusiveGateway, parser); conditionService = parser.getConfiguration(ConditionService.class); } @Override public void execute(ActivityInstanceImpl activityInstance) { ActivityImpl activity = activityInstance.activity; List<TransitionImpl> outgoingTransitions = activity.outgoingTransitions; TransitionImpl transition = findFirstTransitionThatMeetsCondition(activityInstance, outgoingTransitions); if (transition == null) { if (activity.defaultTransition != null) { transition = activity.defaultTransition; } else if (outgoingTransitions != null && outgoingTransitions.size() == 1) { transition = outgoingTransitions.get(0); } else if (outgoingTransitions != null && outgoingTransitions.size() > 1) { transition = handleUndefinedSelection(activityInstance, outgoingTransitions); } } if (transition != null) { activityInstance.takeTransition(transition); } else { log.debug("No transition selected. Gateway " + activity + " ends flow"); activityInstance.end(); activityInstance.propagateToParent(); } } /** called when this exclusive gateway is 'underspecified' so we have * to guess what's best to do at this point. * * a) there is no outgoing transition with a condition that resolves to true * b) there is no default transition specified * c) and there is more than 1 transition */ protected TransitionImpl handleUndefinedSelection(ActivityInstanceImpl activityInstance, List<TransitionImpl> outgoingTransitions) { return findFirstTransitionWithoutCondition(activityInstance, outgoingTransitions); } protected TransitionImpl findFirstTransitionWithoutCondition(ActivityInstanceImpl activityInstance, List<TransitionImpl> outgoingTransitions) { if (outgoingTransitions != null) { for (TransitionImpl outgoingTransition : outgoingTransitions) { if (outgoingTransition.condition == null) { return outgoingTransition; } } } return null; } protected TransitionImpl findFirstTransitionThatMeetsCondition(ActivityInstanceImpl activityInstance, List<TransitionImpl> outgoingTransitions) { if (outgoingTransitions != null) { for (TransitionImpl outgoingTransition: outgoingTransitions) { // Skip the default transition, which is only used if no others match. boolean defaultTransition = outgoingTransition.equals(activityInstance.activity.defaultTransition); if (defaultTransition) { continue; } // condition must be true and the transition must have a target if (meetsCondition(outgoingTransition, activityInstance)) { log.debug("Excl gw takes transition "+outgoingTransition); return outgoingTransition; } else { log.debug("Excl gw condition "+outgoingTransition.condition+" not met: "+outgoingTransition); } } } return null; } protected boolean meetsCondition(TransitionImpl outgoingTransition, ActivityInstanceImpl activityInstance) { boolean meetsCondition = false; if (outgoingTransition.condition!=null) { meetsCondition = outgoingTransition.condition.eval(activityInstance); } return meetsCondition; } @Override public boolean isFlushSkippable() { return true; } @Override public boolean saveTransitionsTaken() { return true; } }