ScopeUtil.java 8.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/* 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.activiti5.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;

22
import org.activiti.engine.impl.delegate.ActivityBehavior;
23 24 25 26 27 28 29 30 31 32
import org.activiti5.engine.impl.context.Context;
import org.activiti5.engine.impl.persistence.entity.CompensateEventSubscriptionEntity;
import org.activiti5.engine.impl.persistence.entity.EventSubscriptionEntity;
import org.activiti5.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti5.engine.impl.pvm.PvmProcessDefinition;
import org.activiti5.engine.impl.pvm.PvmScope;
import org.activiti5.engine.impl.pvm.delegate.ActivityExecution;
import org.activiti5.engine.impl.pvm.process.ActivityImpl;
import org.activiti5.engine.impl.pvm.runtime.InterpretableExecution;

33

34 35 36 37 38
/**
 * @author Daniel Meyer
 * @author Nico Rehwaldt
 */
public class ScopeUtil {
39
 
40
  /**
41 42 43
   * Find the next scope execution in the parent execution hierarchy
   * That method works different than {@link #findScopeExecutionForScope(org.activiti5.engine.impl.persistence.entity.ExecutionEntity, org.activiti5.engine.impl.pvm.PvmScope)} 
   * which returns the most outer scope execution.
44
   * 
45
   * @param execution the execution from which to start the search
46 47 48
   * @return the next scope execution in the parent execution hierarchy
   */
  public static ActivityExecution findScopeExecution(ActivityExecution execution) {
49 50
    
    while(!execution.isScope()) {
51 52
      execution = execution.getParent();
    }
53 54
    
    if(execution.isConcurrent()) {
55 56
      execution = execution.getParent();
    }
57
    
58
    return execution;
59
    
60 61
  }
  /**
62
   * returns the top-most execution sitting in an activity part of the scope defined by 'scopeActivitiy'.
63 64
   */
  public static ExecutionEntity findScopeExecutionForScope(ExecutionEntity execution, PvmScope scopeActivity) {
65
    
66
    // TODO: this feels hacky!
67
    
68 69
    if (scopeActivity instanceof PvmProcessDefinition) {
      return execution.getProcessInstance();
70
      
71
    } else {
72 73
      
      ActivityImpl currentActivity = execution.getActivity();      
74 75
      ExecutionEntity candiadateExecution = null;
      ExecutionEntity originalExecution = execution;
76
      
77 78
      while (execution != null) {
        currentActivity = execution.getActivity();
79 80 81 82 83 84 85 86
        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*/) {
87 88
          // now we're too "high", the candidate execution is the one.
          break;
T
Tijs Rademakers 已提交
89
        }
90
          
91 92
        execution = execution.getParent();
      }
93
      
94
      // if activity is scope, we need to get the parent at least:
95 96 97
      if(originalExecution == candiadateExecution 
              && originalExecution.getActivity().isScope() 
              && !originalExecution.getActivity().equals(scopeActivity)) {
98
        candiadateExecution = originalExecution.getParent();
99 100
      }      
      
101
      return candiadateExecution;
102
    }
103
  }
104
  
105 106 107
  public static ActivityImpl findInParentScopesByBehaviorType(ActivityImpl activity, Class<? extends ActivityBehavior> behaviorType) {
    while (activity != null) {
      for (ActivityImpl childActivity : activity.getActivities()) {
108 109
        if(behaviorType.isAssignableFrom(childActivity.getActivityBehavior().getClass())) {
          return childActivity;          
110
        }
111
      }
112 113
      activity = activity.getParentActivity();      
    }    
114 115 116 117
    return null;
  }

  /**
118
   * we create a separate execution for each compensation handler invocation. 
119 120 121 122 123 124
   */
  public static void throwCompensationEvent(List<CompensateEventSubscriptionEntity> eventSubscriptions, ActivityExecution execution, boolean async) {

    // first spawn the compensating executions
    for (EventSubscriptionEntity eventSubscription : eventSubscriptions) {
      ExecutionEntity compensatingExecution = null;
125 126 127 128 129 130 131 132
      // 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());
133
        // move the compensating execution under this execution:
134
        compensatingExecution.setParent((InterpretableExecution) execution);        
135 136 137 138 139
        compensatingExecution.setEventScope(false);
      } else {
        compensatingExecution = (ExecutionEntity) execution.createExecution();
        eventSubscription.setConfiguration(compensatingExecution.getId());
      }
140
      compensatingExecution.setConcurrent(true);   
141
    }
142
    
143
    // signal compensation events in reverse order of their 'created' timestamp
144 145 146 147 148
    Collections.sort(eventSubscriptions, new Comparator<EventSubscriptionEntity>() {
      public int compare(EventSubscriptionEntity o1, EventSubscriptionEntity o2) {
        return o2.getCreated().compareTo(o1.getCreated());
      }
    });
149
    
150
    for (CompensateEventSubscriptionEntity compensateEventSubscriptionEntity : eventSubscriptions) {
151
      compensateEventSubscriptionEntity.eventReceived(null, async);      
152
    }
153
  }
154
  
155 156 157
  /**
   * creates an event scope for the given execution:
   * 
158 159
   * create a new event scope execution under the parent of the given 
   * execution and move all event subscriptions to that execution.
160
   * 
161 162
   * this allows us to "remember" the event subscriptions after finishing a 
   * scope
163 164
   */
  public static void createEventScopeExecution(ExecutionEntity execution) {
T
Tijs Rademakers 已提交
165

166
    ExecutionEntity eventScope = ScopeUtil.findScopeExecutionForScope(execution, execution.getActivity().getParent());
167
    
168
    List<CompensateEventSubscriptionEntity> eventSubscriptions = execution.getCompensateEventSubscriptions();
169 170 171
    
    if(!eventSubscriptions.isEmpty()) {
      
172
      ExecutionEntity eventScopeExecution = eventScope.createExecution();
173
      eventScopeExecution.setActive(false);      
174
      eventScopeExecution.setConcurrent(false);
175
      eventScopeExecution.setEventScope(true);      
176
      eventScopeExecution.setActivity((ActivityImpl) execution.getActivity());
177
      
178
      execution.setConcurrent(false);
179 180 181
      
      // copy local variables to eventScopeExecution by value. This way, 
      // the eventScopeExecution references a 'snapshot' of the local variables      
182 183
      Map<String, Object> variables = execution.getVariablesLocal();
      for (Entry<String, Object> variable : variables.entrySet()) {
184
        eventScopeExecution.setVariableLocal(variable.getKey(), variable.getValue());        
185
      }
186
      
187 188
      // set event subscriptions to the event scope execution:
      for (CompensateEventSubscriptionEntity eventSubscriptionEntity : eventSubscriptions) {
189
        eventSubscriptionEntity = eventSubscriptionEntity.moveUnder(eventScopeExecution);        
190
      }
191
            
192 193 194
      CompensateEventSubscriptionEntity eventSubscription = CompensateEventSubscriptionEntity.createAndInsert(eventScope);
      eventSubscription.setActivity(execution.getActivity());
      eventSubscription.setConfiguration(eventScopeExecution.getId());
195
      
196
    }
197
  }
198 199

}