All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.activiti.engine.impl.bpmn.helper.ScopeUtil Maven / Gradle / Ivy

The newest version!
/* 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 org.activiti.engine.impl.bpmn.helper;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.persistence.entity.CompensateEventSubscriptionEntity;
import org.activiti.engine.impl.persistence.entity.EventSubscriptionEntity;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.pvm.PvmProcessDefinition;
import org.activiti.engine.impl.pvm.PvmScope;
import org.activiti.engine.impl.pvm.delegate.ActivityBehavior;
import org.activiti.engine.impl.pvm.delegate.ActivityExecution;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.runtime.InterpretableExecution;


/**
 * @author Daniel Meyer
 * @author Nico Rehwaldt
 */
public class ScopeUtil {
 
  /**
   * Find the next scope execution in the parent execution hierarchy
   * That method works different than {@link #findScopeExecutionForScope(org.activiti.engine.impl.persistence.entity.ExecutionEntity, org.activiti.engine.impl.pvm.PvmScope)} 
   * which returns the most outer scope execution.
   * 
   * @param execution the execution from which to start the search
   * @return the next scope execution in the parent execution hierarchy
   */
  public static ActivityExecution findScopeExecution(ActivityExecution execution) {
    
    while(!execution.isScope()) {
      execution = execution.getParent();
    }
    
    if(execution.isConcurrent()) {
      execution = execution.getParent();
    }
    
    return execution;
    
  }
  /**
   * returns the top-most execution sitting in an activity part of the scope defined by 'scopeActivitiy'.
   */
  public static ExecutionEntity findScopeExecutionForScope(ExecutionEntity execution, PvmScope scopeActivity) {
    
    // TODO: this feels hacky!
    
    if (scopeActivity instanceof PvmProcessDefinition) {
      return execution.getProcessInstance();
      
    } else {
      
      ActivityImpl currentActivity = execution.getActivity();      
      ExecutionEntity candiadateExecution = null;
      ExecutionEntity originalExecution = execution;
      
      while (execution != null) {
        currentActivity = execution.getActivity();
        if (scopeActivity.getActivities().contains(currentActivity) /* does not search rec*/ 
                || scopeActivity.equals(currentActivity)) {
          // found a candidate execution; lets still check whether we find an
          // execution which is also sitting in an activity part of this scope
          // higher up the hierarchy
          candiadateExecution = execution;        
        } else if (currentActivity!= null 
                && currentActivity.contains((ActivityImpl)scopeActivity) /*searches rec*/) {
          // now we're too "high", the candidate execution is the one.
          break;
        }
          
        execution = execution.getParent();
      }
      
      // if activity is scope, we need to get the parent at least:
      if(originalExecution == candiadateExecution 
              && originalExecution.getActivity().isScope() 
              && !originalExecution.getActivity().equals(scopeActivity)) {
        candiadateExecution = originalExecution.getParent();
      }      
      
      return candiadateExecution;
    }
  }
  
  public static ActivityImpl findInParentScopesByBehaviorType(ActivityImpl activity, Class behaviorType) {
    while (activity != null) {
      for (ActivityImpl childActivity : activity.getActivities()) {
        if(behaviorType.isAssignableFrom(childActivity.getActivityBehavior().getClass())) {
          return childActivity;          
        }
      }
      activity = activity.getParentActivity();      
    }    
    return null;
  }

  /**
   * we create a separate execution for each compensation handler invocation. 
   */
  public static void throwCompensationEvent(List eventSubscriptions, ActivityExecution execution, boolean async) {

    // first spawn the compensating executions
    for (EventSubscriptionEntity eventSubscription : eventSubscriptions) {
      ExecutionEntity compensatingExecution = null;
      // check whether compensating execution is already created 
      // (which is the case when compensating an embedded subprocess, 
      // where the compensating execution is created when leaving the subprocess 
      // and holds snapshot data).
      if(eventSubscription.getConfiguration() !=null) {
        compensatingExecution = Context.getCommandContext()
          .getExecutionEntityManager()
          .findExecutionById(eventSubscription.getConfiguration());
        // move the compensating execution under this execution:
        compensatingExecution.setParent((InterpretableExecution) execution);        
        compensatingExecution.setEventScope(false);
      } else {
        compensatingExecution = (ExecutionEntity) execution.createExecution();
        eventSubscription.setConfiguration(compensatingExecution.getId());
      }
      compensatingExecution.setConcurrent(true);   
    }
    
    // signal compensation events in reverse order of their 'created' timestamp
    Collections.sort(eventSubscriptions, new Comparator() {
      public int compare(EventSubscriptionEntity o1, EventSubscriptionEntity o2) {
        return o2.getCreated().compareTo(o1.getCreated());
      }
    });
    
    for (CompensateEventSubscriptionEntity compensateEventSubscriptionEntity : eventSubscriptions) {
      compensateEventSubscriptionEntity.eventReceived(null, async);      
    }
  }
  
  /**
   * creates an event scope for the given execution:
   * 
   * create a new event scope execution under the parent of the given 
   * execution and move all event subscriptions to that execution.
   * 
   * this allows us to "remember" the event subscriptions after finishing a 
   * scope
   */
  public static void createEventScopeExecution(ExecutionEntity execution) {

    ExecutionEntity eventScope = ScopeUtil.findScopeExecutionForScope(execution, execution.getActivity().getParent());
    
    List eventSubscriptions = execution.getCompensateEventSubscriptions();
    
    if(!eventSubscriptions.isEmpty()) {
      
      ExecutionEntity eventScopeExecution = eventScope.createExecution();
      eventScopeExecution.setActive(false);      
      eventScopeExecution.setConcurrent(false);
      eventScopeExecution.setEventScope(true);      
      eventScopeExecution.setActivity((ActivityImpl) execution.getActivity());
      
      execution.setConcurrent(false);
      
      // copy local variables to eventScopeExecution by value. This way, 
      // the eventScopeExecution references a 'snapshot' of the local variables      
      Map variables = execution.getVariablesLocal();
      for (Entry variable : variables.entrySet()) {
        eventScopeExecution.setVariableLocal(variable.getKey(), variable.getValue());        
      }
      
      // set event subscriptions to the event scope execution:
      for (CompensateEventSubscriptionEntity eventSubscriptionEntity : eventSubscriptions) {
        eventSubscriptionEntity = eventSubscriptionEntity.moveUnder(eventScopeExecution);        
      }
            
      CompensateEventSubscriptionEntity eventSubscription = CompensateEventSubscriptionEntity.createAndInsert(eventScope);
      eventSubscription.setActivity(execution.getActivity());
      eventSubscription.setConfiguration(eventScopeExecution.getId());
      
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy