ExecutionEntity.java 57.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 22 23 24
/* 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.persistence.entity;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

25 26
import org.activiti.bpmn.model.FlowElement;
import org.activiti.engine.impl.util.ProcessDefinitionUtil;
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
import org.activiti5.engine.ActivitiException;
import org.activiti5.engine.ProcessEngineConfiguration;
import org.activiti5.engine.delegate.event.ActivitiEventType;
import org.activiti5.engine.delegate.event.impl.ActivitiEventBuilder;
import org.activiti5.engine.impl.bpmn.behavior.MultiInstanceActivityBehavior;
import org.activiti5.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
import org.activiti5.engine.impl.bpmn.parser.BpmnParse;
import org.activiti5.engine.impl.bpmn.parser.EventSubscriptionDeclaration;
import org.activiti5.engine.impl.context.Context;
import org.activiti5.engine.impl.db.DbSqlSession;
import org.activiti5.engine.impl.db.HasRevision;
import org.activiti5.engine.impl.db.PersistentObject;
import org.activiti5.engine.impl.interceptor.CommandContext;
import org.activiti5.engine.impl.jobexecutor.AsyncContinuationJobHandler;
import org.activiti5.engine.impl.jobexecutor.TimerDeclarationImpl;
import org.activiti5.engine.impl.pvm.PvmActivity;
import org.activiti5.engine.impl.pvm.PvmException;
import org.activiti5.engine.impl.pvm.PvmExecution;
import org.activiti5.engine.impl.pvm.PvmProcessDefinition;
import org.activiti5.engine.impl.pvm.PvmProcessElement;
import org.activiti5.engine.impl.pvm.PvmProcessInstance;
import org.activiti5.engine.impl.pvm.PvmTransition;
import org.activiti5.engine.impl.pvm.delegate.ActivityExecution;
import org.activiti5.engine.impl.pvm.delegate.ExecutionListenerExecution;
import org.activiti5.engine.impl.pvm.delegate.SignallableActivityBehavior;
import org.activiti5.engine.impl.pvm.process.ActivityImpl;
import org.activiti5.engine.impl.pvm.process.ProcessDefinitionImpl;
import org.activiti5.engine.impl.pvm.process.ScopeImpl;
import org.activiti5.engine.impl.pvm.process.TransitionImpl;
import org.activiti5.engine.impl.pvm.runtime.AtomicOperation;
import org.activiti5.engine.impl.pvm.runtime.InterpretableExecution;
import org.activiti5.engine.impl.pvm.runtime.OutgoingExecution;
import org.activiti5.engine.impl.pvm.runtime.StartingExecution;
import org.activiti5.engine.impl.util.BitMaskUtil;
import org.activiti5.engine.runtime.Execution;
import org.activiti5.engine.runtime.Job;
import org.activiti5.engine.runtime.ProcessInstance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

67

68 69 70 71 72 73 74
/**
 * @author Tom Baeyens
 * @author Daniel Meyer
 * @author Falko Menge
 * @author Saeid Mirzaei
 */

75 76
public class ExecutionEntity extends VariableScopeImpl implements ActivityExecution, ExecutionListenerExecution, Execution, PvmExecution, 
	ProcessInstance, InterpretableExecution, PersistentObject, HasRevision {
T
Tijs Rademakers 已提交
77

78
  private static final long serialVersionUID = 1L;
79
  
80
  private static Logger log = LoggerFactory.getLogger(ExecutionEntity.class);
81 82
  
  // Persistent refrenced entities state //////////////////////////////////////
83 84 85
  protected static final int EVENT_SUBSCRIPTIONS_STATE_BIT = 1;
  protected static final int TASKS_STATE_BIT = 2;
  protected static final int JOBS_STATE_BIT = 3;
86 87 88
  
  // current position /////////////////////////////////////////////////////////
  
89
  protected ProcessDefinitionImpl processDefinition;
T
Tijs Rademakers 已提交
90

91 92
  /** current activity */
  protected ActivityImpl activity;
93
  
94 95
  protected FlowElement currentFlowElement;
  
96
  /** current transition.  is null when there is no transition being taken. */
97
  protected TransitionImpl transition = null;
98 99
  
  /** transition that will be taken.  is null when there is no transition being taken. */
100 101
  protected TransitionImpl transitionBeingTaken = null;

102 103
  /** the process instance.  this is the root of the execution tree.  
   * the processInstance of a process instance is a self reference. */
104
  protected ExecutionEntity processInstance;
105
  
106 107
  /** the parent execution */
  protected ExecutionEntity parent;
108
  
109 110
  /** nested executions representing scopes or concurrent paths */
  protected List<ExecutionEntity> executions;
111
  
112 113
  /** super execution, not-null if this execution is part of a subprocess */
  protected ExecutionEntity superExecution;
114 115
  
  /** reference to a subprocessinstance, not-null if currently subprocess is started from this execution */
116
  protected ExecutionEntity subProcessInstance;
117
  
118
  protected StartingExecution startingExecution;
119
  
120 121 122
  /** The tenant identifier (if any) */
  protected String tenantId = ProcessEngineConfiguration.NO_TENANT_ID;
  protected String name;
123
  
124
  protected Date lockTime;
125 126 127 128 129
  
  // state/type of execution ////////////////////////////////////////////////// 
  
  /** indicates if this execution represents an active path of execution.
   * Executions are made inactive in the following situations:
130
   * <ul>
131 132 133 134 135
   *   <li>an execution enters a nested scope</li>
   *   <li>an execution is split up into multiple concurrent executions, then the parent is made inactive.</li>
   *   <li>an execution has arrived in a parallel gateway or join and that join has not yet activated/fired.</li>
   *   <li>an execution is ended.</li>
   * </ul>*/ 
136 137 138 139 140
  protected boolean isActive = true;
  protected boolean isScope = true;
  protected boolean isConcurrent = false;
  protected boolean isEnded = false;
  protected boolean isEventScope = false;
141 142 143
  
  // events ///////////////////////////////////////////////////////////////////
  
144 145 146
  protected String eventName;
  protected PvmProcessElement eventSource;
  protected int executionListenerIndex = 0;
147
  
148
  // associated entities /////////////////////////////////////////////////////
149 150 151
  
  // (we cache associated entities here to minimize db queries) 
  protected List<EventSubscriptionEntity> eventSubscriptions;  
152 153 154 155
  protected List<JobEntity> jobs;
  protected List<TaskEntity> tasks;
  protected List<IdentityLinkEntity> identityLinks;
  protected int cachedEntityState;
156
  
157
  // cascade deletion ////////////////////////////////////////////////////////
158
  
159 160
  protected boolean deleteRoot;
  protected String deleteReason;
161 162 163 164 165 166
  
  // replaced by //////////////////////////////////////////////////////////////
  
  /** when execution structure is pruned during a takeAll, then 
   * the original execution has to be resolved to the replaced execution.
   * @see {@link #takeAll(List, List)} {@link OutgoingExecution} */
167
  protected ExecutionEntity replacedBy;
168 169
  
  // atomic operations ////////////////////////////////////////////////////////
170

171 172 173
  /** next operation.  process execution is in fact runtime interpretation of the process model.
   * each operation is a logical unit of interpretation of the process.  so sequentially processing 
   * the operations drives the interpretation or execution of a process. 
174
   * @see AtomicOperation
175
   * @see #performOperation(AtomicOperation) */
176 177 178 179 180 181 182 183 184 185 186 187 188 189
  protected AtomicOperation nextOperation;
  protected boolean isOperating = false;

  protected int revision = 1;
  protected int suspensionState = SuspensionState.ACTIVE.getStateCode();

  /**
   * persisted reference to the processDefinition.
   * 
   * @see #processDefinition
   * @see #setProcessDefinition(ProcessDefinitionImpl)
   * @see #getProcessDefinition()
   */
  protected String processDefinitionId;
190
  
191 192 193 194
  /**
   * persisted reference to the process definition key.
   */
  protected String processDefinitionKey;
195
  
196 197 198 199
  /**
   * persisted reference to the process definition name.
   */
  protected String processDefinitionName;
200
  
201 202 203 204
  /**
   * persisted reference to the process definition version.
   */
  protected Integer processDefinitionVersion;
205
  
206 207 208 209 210 211
  /**
   * persisted reference to the deployment id.
   */
  protected String deploymentId;

  /**
212 213
   * persisted reference to the current position in the diagram within the
   * {@link #processDefinition}.
214 215 216 217 218 219
   * 
   * @see #activity
   * @see #setActivity(ActivityImpl)
   * @see #getActivity()
   */
  protected String activityId;
220
  
221 222 223 224
  /**
   * The name of the current activity position
   */
  protected String activityName;
225
  
226 227 228 229 230 231
  /**
   * persisted reference to the process instance.
   * 
   * @see #getProcessInstance()
   */
  protected String processInstanceId;
232
  
233 234 235 236 237 238 239 240 241 242 243 244
  /**
   * persisted reference to the business key.
   */
  protected String businessKey;

  /**
   * persisted reference to the parent of this execution.
   * 
   * @see #getParent()
   * @see #setParentId(String)
   */
  protected String parentId;
245
  
246 247 248 249 250 251 252
  /**
   * persisted reference to the super execution of this execution
   * 
   * @See {@link #getSuperExecution()}
   * @see #setSuperExecution(ExecutionEntity)
   */
  protected String superExecutionId;
253
  
254
  protected boolean forcedUpdate;
255
  
256
  protected List<VariableInstanceEntity> queryVariables;
257
  
258 259 260 261
  public ExecutionEntity(ActivityImpl activityImpl) {
    this.startingExecution = new StartingExecution(activityImpl);
  }

262 263 264
  public ExecutionEntity() {
  }

265
  /** creates a new execution. properties processDefinition, processInstance and activity will be initialized. */  
266 267 268 269 270 271
  public ExecutionEntity createExecution() {
    // create the new child execution
    ExecutionEntity createdExecution = newExecution();

    // manage the bidirectional parent-child relation
    ensureExecutionsInitialized();
272
    executions.add(createdExecution); 
273
    createdExecution.setParent(this);
274
    
275 276 277 278
    // initialize the new execution
    createdExecution.setProcessDefinition(getProcessDefinition());
    createdExecution.setProcessInstance(getProcessInstance());
    createdExecution.setActivity(getActivity());
279
    
280 281 282 283 284
    if (log.isDebugEnabled()) {
      log.debug("Child execution {} created with parent ", createdExecution, this);
    }

    if (Context.getProcessEngineConfiguration() != null && Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
285 286 287 288
      Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(
        ActivitiEventBuilder.createEntityEvent(ActivitiEventType.ENTITY_CREATED, createdExecution));
      Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(
              ActivitiEventBuilder.createEntityEvent(ActivitiEventType.ENTITY_INITIALIZED, createdExecution));
289 290 291 292 293 294 295
    }

    return createdExecution;
  }

  public PvmProcessInstance createSubProcessInstance(PvmProcessDefinition processDefinition) {
    ExecutionEntity subProcessInstance = newExecution();
296
    
297 298 299
    // manage bidirectional super-subprocess relation
    subProcessInstance.setSuperExecution(this);
    this.setSubProcessInstance(subProcessInstance);
300
    
301 302 303 304
    // Initialize the new execution
    subProcessInstance.setProcessDefinition((ProcessDefinitionImpl) processDefinition);
    subProcessInstance.setProcessInstance(subProcessInstance);

305 306
    Context.getCommandContext().getHistoryManager()
      .recordSubProcessInstanceStart(this, subProcessInstance);
307 308

    if (Context.getProcessEngineConfiguration() != null && Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
309 310
      Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(
        ActivitiEventBuilder.createEntityEvent(ActivitiEventType.ENTITY_CREATED, subProcessInstance));
311 312 313 314 315 316 317
    }
    return subProcessInstance;
  }

  protected ExecutionEntity newExecution() {
    ExecutionEntity newExecution = new ExecutionEntity();
    newExecution.executions = new ArrayList<ExecutionEntity>();
318
    
319 320
    // Inherit tenant id (if any)
    if (getTenantId() != null) {
321
    	newExecution.setTenantId(getTenantId());
322 323
    }

324 325 326 327
    Context
      .getCommandContext()
      .getDbSqlSession()
      .insert(newExecution);
T
Tijs Rademakers 已提交
328

329 330 331
    return newExecution;
  }

332 333
  
  // scopes ///////////////////////////////////////////////////////////////////
T
Tijs Rademakers 已提交
334

335 336 337
  @SuppressWarnings("unchecked")
  public void initialize() {
    log.debug("initializing {}", this);
T
Tijs Rademakers 已提交
338

339 340
    ScopeImpl scope = getScopeObject();
    ensureParentInitialized();
T
Tijs Rademakers 已提交
341

342 343 344 345 346
    // initialize the lists of referenced objects (prevents db queries)
    variableInstances = new HashMap<String, VariableInstanceEntity>();
    eventSubscriptions = new ArrayList<EventSubscriptionEntity>();
    jobs = new ArrayList<JobEntity>();
    tasks = new ArrayList<TaskEntity>();
347 348
    
    // Cached entity-state initialized to null, all bits are zore, indicating NO entities present
349
    cachedEntityState = 0;
350
    
351
    List<TimerDeclarationImpl> timerDeclarations = (List<TimerDeclarationImpl>) scope.getProperty(BpmnParse.PROPERTYNAME_TIMER_DECLARATION);
352
    if (timerDeclarations!=null) {
353 354
      for (TimerDeclarationImpl timerDeclaration : timerDeclarations) {
        TimerEntity timer = timerDeclaration.prepareTimerEntity(this);
355 356 357 358 359 360
        if (timer!=null) {
          Context
            .getCommandContext()
            .getJobEntityManager()
            .schedule(timer);
        }
361
      }
T
Tijs Rademakers 已提交
362
    }
363
    
364 365
    // create event subscriptions for the current scope
    List<EventSubscriptionDeclaration> eventSubscriptionDeclarations = (List<EventSubscriptionDeclaration>) scope.getProperty(BpmnParse.PROPERTYNAME_EVENT_SUBSCRIPTION_DECLARATION);
366 367 368 369
    if(eventSubscriptionDeclarations != null) {
      for (EventSubscriptionDeclaration eventSubscriptionDeclaration : eventSubscriptionDeclarations) {        
        if(!eventSubscriptionDeclaration.isStartEvent()) {
          EventSubscriptionEntity eventSubscriptionEntity = eventSubscriptionDeclaration.prepareEventSubscriptionEntity(this); 
370
          if (getTenantId() != null) {
371
          	eventSubscriptionEntity.setTenantId(getTenantId());
372 373
          }
          eventSubscriptionEntity.insert();
374
        }        
375
      }
T
Tijs Rademakers 已提交
376
    }
377
  }
378
  
379
  public void start() {
380
    if(startingExecution == null && isProcessInstanceType()) {
381
      startingExecution = new StartingExecution(processDefinition.getInitial());
T
Tijs Rademakers 已提交
382
    }
383 384
    performOperation(AtomicOperation.PROCESS_START);
  }
T
Tijs Rademakers 已提交
385

386 387
  public void destroy() {
    log.debug("destroying {}", this);
388
    
389 390
    ensureParentInitialized();
    deleteVariablesInstanceForLeavingScope();
T
Tijs Rademakers 已提交
391

392 393
    setScope(false);
  }
T
Tijs Rademakers 已提交
394

395 396 397
  /** removes an execution. if there are nested executions, those will be ended recursively.
   * if there is a parent, this method removes the bidirectional relation 
   * between parent and this execution. */
398 399 400 401 402 403
  public void end() {
    isActive = false;
    isEnded = true;
    performOperation(AtomicOperation.ACTIVITY_END);
  }

404 405

  // methods that translate to operations /////////////////////////////////////
406 407 408 409 410

  public void signal(String signalName, Object signalData) {
    ensureActivityInitialized();
    SignallableActivityBehavior activityBehavior = (SignallableActivityBehavior) activity.getActivityBehavior();
    try {
411
    	String signalledActivityId = activity.getId();
412
      activityBehavior.signal(this, signalName, signalData);
413
      
414 415
      // If needed, dispatch an event indicating an activity was signalled
      boolean isUserTask = (activityBehavior instanceof UserTaskActivityBehavior)
416 417 418 419 420 421 422
      		|| ((activityBehavior instanceof MultiInstanceActivityBehavior) 
      				&& ((MultiInstanceActivityBehavior) activityBehavior).getInnerActivityBehavior() instanceof UserTaskActivityBehavior);
      
      if(!isUserTask && Context.getProcessEngineConfiguration() != null 
      		&& Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
      	Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(ActivitiEventBuilder.createSignalEvent(
      		ActivitiEventType.ACTIVITY_SIGNALED, signalledActivityId, signalName, signalData, this.id, this.processInstanceId, this.processDefinitionId));
423
      }
424
      
425 426 427
    } catch (RuntimeException e) {
      throw e;
    } catch (Exception e) {
428
      throw new PvmException("couldn't process signal '"+signalName+"' on activity '"+activity.getId()+"': "+e.getMessage(), e);
429 430
    }
  }
431
  
432
  public void take(PvmTransition transition) {
433
  	take(transition, true);
434
  }
435
  
436
  /**
437 438 439
   * @param fireActivityCompletionEvent This method can be called from other places
   * (like {@link #takeAll(List, List)}), where the event is already fired.
   * In that case, false is passed an no second event is fired.
440 441
   */
  public void take(PvmTransition transition, boolean fireActivityCompletionEvent) {
442 443 444 445 446 447
 
  	if (fireActivityCompletionEvent) {
	  	fireActivityCompletedEvent();
  	}
  	
    if (this.transition!=null) {
448 449
      throw new PvmException("already taking a transition");
    }
450
    if (transition==null) {
451 452
      throw new PvmException("transition is null");
    }
453
    setActivity((ActivityImpl)transition.getSource());
454 455 456
    setTransition((TransitionImpl) transition);
    performOperation(AtomicOperation.TRANSITION_NOTIFY_LISTENER_END);
  }
457
  
458 459 460 461 462 463 464 465 466
  public void executeActivity(PvmActivity activity) {
    setActivity((ActivityImpl) activity);
    performOperation(AtomicOperation.ACTIVITY_START);
  }

  public List<ActivityExecution> findInactiveConcurrentExecutions(PvmActivity activity) {
    List<ActivityExecution> inactiveConcurrentExecutionsInActivity = new ArrayList<ActivityExecution>();
    List<ActivityExecution> otherConcurrentExecutions = new ArrayList<ActivityExecution>();
    if (isConcurrent()) {
467 468 469
      List< ? extends ActivityExecution> concurrentExecutions = getParent().getAllChildExecutions();
      for (ActivityExecution concurrentExecution: concurrentExecutions) {
        if (concurrentExecution.getActivity()==activity) {
470 471 472
          if (!concurrentExecution.isActive()) {
            inactiveConcurrentExecutionsInActivity.add(concurrentExecution);
          }
T
Tijs Rademakers 已提交
473
        } else {
474
          otherConcurrentExecutions.add(concurrentExecution);
T
Tijs Rademakers 已提交
475
        }
476 477 478 479 480 481 482
      }
    } else {
      if (!isActive()) {
        inactiveConcurrentExecutionsInActivity.add(this);
      } else {
        otherConcurrentExecutions.add(this);
      }
T
Tijs Rademakers 已提交
483
    }
484 485 486
    if (log.isDebugEnabled()) {
      log.debug("inactive concurrent executions in '{}': {}", activity, inactiveConcurrentExecutionsInActivity);
      log.debug("other concurrent executions: {}", otherConcurrentExecutions);
T
Tijs Rademakers 已提交
487
    }
488 489
    return inactiveConcurrentExecutionsInActivity;
  }
490
  
491 492 493 494 495 496 497 498
  protected List<ExecutionEntity> getAllChildExecutions() {
    List<ExecutionEntity> childExecutions = new ArrayList<ExecutionEntity>();
    for (ExecutionEntity childExecution : getExecutions()) {
      childExecutions.add(childExecution);
      childExecutions.addAll(childExecution.getAllChildExecutions());
    }
    return childExecutions;
  }
499
  
500 501
  @SuppressWarnings({ "unchecked", "rawtypes" })
  public void takeAll(List<PvmTransition> transitions, List<ActivityExecution> recyclableExecutions) {
T
Tijs Rademakers 已提交
502

503 504
  	fireActivityCompletedEvent();
  	
505
    transitions = new ArrayList<PvmTransition>(transitions);
506 507 508 509 510
    recyclableExecutions = (recyclableExecutions!=null ? new ArrayList<ActivityExecution>(recyclableExecutions) : new ArrayList<ActivityExecution>());
    
    if (recyclableExecutions.size()>1) {
      for (ActivityExecution recyclableExecution: recyclableExecutions) {
        if (((ExecutionEntity)recyclableExecution).isScope()) {
511
          throw new PvmException("joining scope executions is not allowed");
T
Tijs Rademakers 已提交
512
        }
513
      }
T
Tijs Rademakers 已提交
514 515
    }

516 517 518
    ExecutionEntity concurrentRoot = ((isConcurrent && !isScope) ? getParent() : this);
    List<ExecutionEntity> concurrentActiveExecutions = new ArrayList<ExecutionEntity>();
    List<ExecutionEntity> concurrentInActiveExecutions = new ArrayList<ExecutionEntity>();
519
    for (ExecutionEntity execution: concurrentRoot.getExecutions()) {
520 521 522 523 524
      if (execution.isActive()) {
        concurrentActiveExecutions.add(execution);
      } else {
        concurrentInActiveExecutions.add(execution);
      }
T
Tijs Rademakers 已提交
525 526
    }

527 528 529
    if (log.isDebugEnabled()) {
      log.debug("transitions to take concurrent: {}", transitions);
      log.debug("active concurrent executions: {}", concurrentActiveExecutions);
T
Tijs Rademakers 已提交
530 531
    }

532 533 534 535
    if ( (transitions.size()==1)
         && (concurrentActiveExecutions.isEmpty())
         && allExecutionsInSameActivity(concurrentInActiveExecutions)
       ) {
T
Tijs Rademakers 已提交
536

537 538
      List<ExecutionEntity> recyclableExecutionImpls = (List) recyclableExecutions;
      recyclableExecutions.remove(concurrentRoot);
539
      for (ExecutionEntity prunedExecution: recyclableExecutionImpls) {
540
        // End the pruned executions if necessary.
541
        // Some recyclable executions are inactivated (joined executions)
542
        // Others are already ended (end activities)
543
        
544 545 546
        log.debug("pruning execution {}", prunedExecution);
        prunedExecution.remove();
      }
T
Tijs Rademakers 已提交
547

548 549 550 551 552
      log.debug("activating the concurrent root {} as the single path of execution going forward", concurrentRoot);
      concurrentRoot.setActive(true);
      concurrentRoot.setActivity(activity);
      concurrentRoot.setConcurrent(false);
      concurrentRoot.take(transitions.get(0), false);
T
Tijs Rademakers 已提交
553

554
    } else {
555
      
556
      List<OutgoingExecution> outgoingExecutions = new ArrayList<OutgoingExecution>();
T
Tijs Rademakers 已提交
557

558
      recyclableExecutions.remove(concurrentRoot);
559
  
560
      log.debug("recyclable executions for reuse: {}", recyclableExecutions);
561
      
562 563 564
      // first create the concurrent executions
      while (!transitions.isEmpty()) {
        PvmTransition outgoingTransition = transitions.remove(0);
T
Tijs Rademakers 已提交
565

566 567 568
        ExecutionEntity outgoingExecution = null;
        if (recyclableExecutions.isEmpty()) {
          outgoingExecution = concurrentRoot.createExecution();
569 570
          log.debug("new {} with parent {} created to take transition {}", 
                  outgoingExecution, outgoingExecution.getParent(), outgoingTransition);
571 572 573 574
        } else {
          outgoingExecution = (ExecutionEntity) recyclableExecutions.remove(0);
          log.debug("recycled {} to take transition {}", outgoingExecution, outgoingTransition);
        }
575
        
576 577 578 579 580 581 582
        outgoingExecution.setActive(true);
        outgoingExecution.setScope(false);
        outgoingExecution.setConcurrent(true);
        outgoingExecution.setTransitionBeingTaken((TransitionImpl) outgoingTransition);
        outgoingExecutions.add(new OutgoingExecution(outgoingExecution, outgoingTransition, true));
      }

583 584
      // prune the executions that are not recycled 
      for (ActivityExecution prunedExecution: recyclableExecutions) {
585 586 587 588 589
        log.debug("pruning execution {}", prunedExecution);
        prunedExecution.end();
      }

      // then launch all the concurrent executions
590
      for (OutgoingExecution outgoingExecution: outgoingExecutions) {
591 592 593 594 595
        outgoingExecution.take(false);
      }
    }
  }

596 597 598 599 600 601 602 603 604 605 606
	protected void fireActivityCompletedEvent() {
	  if(Context.getProcessEngineConfiguration() != null && Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
    	Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(
    			ActivitiEventBuilder.createActivityEvent(ActivitiEventType.ACTIVITY_COMPLETED, 
    					getActivity() != null ? getActivity().getId() : getActivityId(), 
    					getActivity() != null ? (String) getActivity().getProperties().get("name") : null,
    					getId(),
    					getProcessInstanceId(), 
    					getProcessDefinitionId(), 
    					getActivity() != null ? (String) getActivity().getProperties().get("type") : null,
    					getActivity() != null ? getActivity().getActivityBehavior().getClass().getCanonicalName() : null));
607 608
    }
  }
609
  
610 611 612 613 614 615
  protected boolean allExecutionsInSameActivity(List<ExecutionEntity> executions) {
    if (executions.size() > 1) {
      String activityId = executions.get(0).getActivityId();
      for (ExecutionEntity execution : executions) {
        String otherActivityId = execution.getActivityId();
        if (!execution.isEnded) {
616 617 618
          if ( (activityId == null && otherActivityId != null) 
                  || (activityId != null && otherActivityId == null)
                  || (activityId != null && otherActivityId!= null && !otherActivityId.equals(activityId))) {
619 620 621 622 623 624 625
            return false;
          }
        }
      }
    }
    return true;
  }
626
  
627 628 629 630 631
  public void performOperation(AtomicOperation executionOperation) {
    if (executionOperation.isAsync(this)) {
      scheduleAtomicOperationAsync(executionOperation);
    } else {
      performOperationSync(executionOperation);
632
    }    
633
  }
634
  
635
  protected void performOperationSync(AtomicOperation executionOperation) {
636 637 638
    Context
      .getCommandContext()
      .performOperation(executionOperation, this);
639 640 641 642 643 644 645
  }

  protected void scheduleAtomicOperationAsync(AtomicOperation executionOperation) {
    MessageEntity message = new MessageEntity();
    message.setExecution(this);
    message.setExclusive(getActivity().isExclusive());
    message.setJobHandlerType(AsyncContinuationJobHandler.TYPE);
646
    // At the moment, only AtomicOperationTransitionCreateScope can be performed asynchronously,
647
    // so there is no need to pass it to the handler
648
    
649 650 651 652 653
    GregorianCalendar expireCal = new GregorianCalendar();
    ProcessEngineConfiguration processEngineConfig = Context.getCommandContext().getProcessEngineConfiguration();
    expireCal.setTime(processEngineConfig.getClock().getCurrentTime());
    expireCal.add(Calendar.SECOND, processEngineConfig.getLockTimeAsyncJobWaitTime());
    message.setLockExpirationTime(expireCal.getTime());
654
    
655 656
    // Inherit tenant id (if applicable)
    if (getTenantId() != null) {
657
    	message.setTenantId(getTenantId());
658 659
    }

660 661 662 663
    Context
      .getCommandContext()
      .getJobEntityManager()
      .send(message);
664 665 666
  }

  public boolean isActive(String activityId) {
667
    return findExecution(activityId)!=null;
668 669 670 671 672
  }

  public void inactivate() {
    this.isActive = false;
  }
673 674 675
  
  // executions ///////////////////////////////////////////////////////////////
  
676 677 678 679 680 681 682 683
  /** ensures initialization and returns the non-null executions list */
  public List<ExecutionEntity> getExecutions() {
    ensureExecutionsInitialized();
    return executions;
  }

  @SuppressWarnings({ "unchecked", "rawtypes" })
  protected void ensureExecutionsInitialized() {
684 685 686 687 688
    if (executions==null) {
      this.executions = (List) Context
        .getCommandContext()
        .getExecutionEntityManager()
        .findChildExecutionsByParentExecutionId(id);
689 690 691 692 693 694
    }
  }

  public void setExecutions(List<ExecutionEntity> executions) {
    this.executions = executions;
  }
695
  
696 697
  /** searches for an execution positioned in the given activity */
  public ExecutionEntity findExecution(String activityId) {
698 699 700
    if ( (getActivity()!=null)
         && (getActivity().getId().equals(activityId))
       ) {
701 702 703 704 705 706 707
      return this;
    }
    for (ExecutionEntity nestedExecution : getExecutions()) {
      ExecutionEntity result = nestedExecution.findExecution(activityId);
      if (result != null) {
        return result;
      }
T
Tijs Rademakers 已提交
708
    }
709 710
    return null;
  }
711
  
712 713 714 715 716
  public List<String> findActiveActivityIds() {
    List<String> activeActivityIds = new ArrayList<String>();
    collectActiveActivityIds(activeActivityIds);
    return activeActivityIds;
  }
T
Tijs Rademakers 已提交
717

718 719
  protected void collectActiveActivityIds(List<String> activeActivityIds) {
    ensureActivityInitialized();
720
    if (isActive && activity!=null) {
721
      activeActivityIds.add(activity.getId());
T
Tijs Rademakers 已提交
722
    }
723
    ensureExecutionsInitialized();
724
    for (ExecutionEntity execution: executions) {
725 726 727
      execution.collectActiveActivityIds(activeActivityIds);
    }
  }
T
Tijs Rademakers 已提交
728

729 730 731
  
  // bussiness key ////////////////////////////////////////////////////////////
  
732 733 734
  public String getBusinessKey() {
    return businessKey;
  }
735
  
736 737 738
  public void setBusinessKey(String businessKey) {
    this.businessKey = businessKey;
  }
739
  
740 741 742
  public String getProcessBusinessKey() {
    return getProcessInstance().getBusinessKey();
  }
743 744 745 746
  
  public String getProcessInstanceBusinessKey() {
    return getProcessInstance().getBusinessKey();
  }
T
Tijs Rademakers 已提交
747

748
  // process definition ///////////////////////////////////////////////////////
749 750 751 752 753 754

  /** ensures initialization and returns the process definition. */
  public ProcessDefinitionImpl getProcessDefinition() {
    ensureProcessDefinitionInitialized();
    return processDefinition;
  }
755
  
756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782
  public void setProcessDefinitionId(String processDefinitionId) {
    this.processDefinitionId = processDefinitionId;
  }

  public String getProcessDefinitionId() {
    return processDefinitionId;
  }

  public String getProcessDefinitionKey() {
    return processDefinitionKey;
  }

  public void setProcessDefinitionKey(String processDefinitionKey) {
    this.processDefinitionKey = processDefinitionKey;
  }

  public String getProcessDefinitionName() {
    return processDefinitionName;
  }

  public void setProcessDefinitionName(String processDefinitionName) {
    this.processDefinitionName = processDefinitionName;
  }

  public Integer getProcessDefinitionVersion() {
    return processDefinitionVersion;
  }
T
Tijs Rademakers 已提交
783

784 785 786 787 788 789 790
  public void setProcessDefinitionVersion(Integer processDefinitionVersion) {
    this.processDefinitionVersion = processDefinitionVersion;
  }

  public String getDeploymentId() {
    return deploymentId;
  }
T
Tijs Rademakers 已提交
791

792 793 794
  public void setDeploymentId(String deploymentId) {
    this.deploymentId = deploymentId;
  }
T
Tijs Rademakers 已提交
795

796
  /** for setting the process definition, this setter must be used as subclasses can override */  
797 798
  protected void ensureProcessDefinitionInitialized() {
    if ((processDefinition == null) && (processDefinitionId != null)) {
799 800 801 802
      ProcessDefinitionEntity deployedProcessDefinition = Context
        .getProcessEngineConfiguration()
        .getDeploymentManager()
        .findDeployedProcessDefinitionById(processDefinitionId);
803
      setProcessDefinition(deployedProcessDefinition);
T
Tijs Rademakers 已提交
804
    }
805 806 807 808 809 810
  }

  public void setProcessDefinition(ProcessDefinitionImpl processDefinition) {
    this.processDefinition = processDefinition;
    this.processDefinitionId = processDefinition.getId();
  }
T
Tijs Rademakers 已提交
811

812
  // process instance /////////////////////////////////////////////////////////
T
Tijs Rademakers 已提交
813

814 815 816 817 818
  /** ensures initialization and returns the process instance. */
  public ExecutionEntity getProcessInstance() {
    ensureProcessInstanceInitialized();
    return processInstance;
  }
819
  
820 821
  protected void ensureProcessInstanceInitialized() {
    if ((processInstance == null) && (processInstanceId != null)) {
822 823 824 825
      processInstance = Context
        .getCommandContext()
        .getExecutionEntityManager()
        .findExecutionById(processInstanceId);
T
Tijs Rademakers 已提交
826
    }
827
  }
T
Tijs Rademakers 已提交
828

829 830 831 832
  public void setProcessInstance(InterpretableExecution processInstance) {
    this.processInstance = (ExecutionEntity) processInstance;
    if (processInstance != null) {
      this.processInstanceId = this.processInstance.getId();
T
Tijs Rademakers 已提交
833
    }
834
  }
835
  
836 837 838
  public boolean isProcessInstanceType() {
    return parentId == null;
  }
T
Tijs Rademakers 已提交
839

840
  // activity /////////////////////////////////////////////////////////////////
T
Tijs Rademakers 已提交
841

842 843 844 845 846
  /** ensures initialization and returns the activity */
  public ActivityImpl getActivity() {
    ensureActivityInitialized();
    return activity;
  }
847 848
  
  /** must be called before the activity member field or getActivity() is called */
849 850 851
  protected void ensureActivityInitialized() {
    if ((activity == null) && (activityId != null)) {
      activity = getProcessDefinition().findActivity(activityId);
T
Tijs Rademakers 已提交
852
    }
853
  }
T
Tijs Rademakers 已提交
854

855 856 857 858 859 860 861 862
  public void setActivity(ActivityImpl activity) {
    this.activity = activity;
    if (activity != null) {
      this.activityId = activity.getId();
      this.activityName = (String) activity.getProperty("name");
    } else {
      this.activityId = null;
      this.activityName = null;
T
Tijs Rademakers 已提交
863
    }
864
  }
865 866 867
  
  // parent ///////////////////////////////////////////////////////////////////
  
868 869 870 871 872
  /** ensures initialization and returns the parent */
  public ExecutionEntity getParent() {
    ensureParentInitialized();
    return parent;
  }
T
Tijs Rademakers 已提交
873

874 875
  protected void ensureParentInitialized() {
    if (parent == null && parentId != null) {
876 877 878 879
      parent = Context
        .getCommandContext()
        .getExecutionEntityManager()
        .findExecutionById(parentId);
T
Tijs Rademakers 已提交
880
    }
881
  }
T
Tijs Rademakers 已提交
882

883 884
  public void setParent(InterpretableExecution parent) {
    this.parent = (ExecutionEntity) parent;
T
Tijs Rademakers 已提交
885

886
    if (parent != null) {
887
      this.parentId = ((ExecutionEntity)parent).getId();
888 889
    } else {
      this.parentId = null;
T
Tijs Rademakers 已提交
890
    }
891
  }
892 893 894
  
  // super- and subprocess executions /////////////////////////////////////////
  
895 896 897
  public String getSuperExecutionId() {
    return superExecutionId;
  }
898
  
899 900 901 902
  public ExecutionEntity getSuperExecution() {
    ensureSuperExecutionInitialized();
    return superExecution;
  }
T
Tijs Rademakers 已提交
903

904 905 906 907
  public void setSuperExecution(ExecutionEntity superExecution) {
    this.superExecution = superExecution;
    if (superExecution != null) {
      superExecution.setSubProcessInstance(null);
T
Tijs Rademakers 已提交
908
    }
909
    
910
    if (superExecution != null) {
911
      this.superExecutionId = ((ExecutionEntity)superExecution).getId();
912 913
    } else {
      this.superExecutionId = null;
T
Tijs Rademakers 已提交
914
    }
915
  }
916
  
917 918
  protected void ensureSuperExecutionInitialized() {
    if (superExecution == null && superExecutionId != null) {
919 920 921 922
      superExecution = Context
        .getCommandContext()
        .getExecutionEntityManager()
        .findExecutionById(superExecutionId);
T
Tijs Rademakers 已提交
923
    }
924
  }
925
  
926 927 928 929
  public ExecutionEntity getSubProcessInstance() {
    ensureSubProcessInstanceInitialized();
    return subProcessInstance;
  }
930
  
931 932 933
  public void setSubProcessInstance(InterpretableExecution subProcessInstance) {
    this.subProcessInstance = (ExecutionEntity) subProcessInstance;
  }
T
Tijs Rademakers 已提交
934

935 936
  protected void ensureSubProcessInstanceInitialized() {
    if (subProcessInstance == null) {
937 938 939 940
      subProcessInstance = Context
        .getCommandContext()
        .getExecutionEntityManager()
        .findSubProcessInstanceBySuperExecutionId(id);
T
Tijs Rademakers 已提交
941
    }
942
  }
943 944 945
  
  // scopes ///////////////////////////////////////////////////////////////////
  
946 947 948 949 950 951
  protected ScopeImpl getScopeObject() {
    ScopeImpl scope = null;
    if (isProcessInstanceType()) {
      scope = getProcessDefinition();
    } else {
      scope = getActivity();
T
Tijs Rademakers 已提交
952
    }
953 954
    return scope;
  }
955
  
956 957 958
  public boolean isScope() {
    return isScope;
  }
T
Tijs Rademakers 已提交
959

960 961 962
  public void setScope(boolean isScope) {
    this.isScope = isScope;
  }
963 964
  
  // customized persistence behaviour /////////////////////////////////////////
T
Tijs Rademakers 已提交
965

966 967
  public void remove() {
    ensureParentInitialized();
968
    if (parent!=null) {
969 970
      parent.ensureExecutionsInitialized();
      parent.executions.remove(this);
T
Tijs Rademakers 已提交
971 972
    }

973 974 975
    // delete all the variable instances
    ensureVariableInstancesInitialized();
    deleteVariablesInstanceForLeavingScope();
976
    
977 978
    // delete all the tasks
    removeTasks(null);
979
    
980 981
    // remove all jobs
    removeJobs();
982 983
    
    // remove all event subscriptions for this scope, if the scope has event subscriptions:
984
    removeEventSubscriptions();
985 986
    
    // remove event scopes:            
987
    removeEventScopes();
988
    
989 990
    // remove identity links
    removeIdentityLinks();
991 992 993 994
    
    if(Context.getProcessEngineConfiguration() != null && Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
    	Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(
    			ActivitiEventBuilder.createEntityEvent(ActivitiEventType.ENTITY_DELETED, this));
T
Tijs Rademakers 已提交
995 996
    }

997
    // finally delete this execution
998 999 1000
    Context.getCommandContext()
      .getDbSqlSession()
      .delete(this);
1001
  }
T
Tijs Rademakers 已提交
1002

1003
  public void destroyScope(String reason) {
1004 1005
    
    if(log.isDebugEnabled()) {
1006
      log.debug("performing destroy scope behavior for execution {}", this);
T
Tijs Rademakers 已提交
1007
    }
1008
    
1009 1010 1011
    // remove all child executions and sub process instances:
    List<InterpretableExecution> executions = new ArrayList<InterpretableExecution>(getExecutions());
    for (InterpretableExecution childExecution : executions) {
1012
      if (childExecution.getSubProcessInstance()!=null) {
1013
        childExecution.getSubProcessInstance().deleteCascade(reason);
1014
      }      
1015
      childExecution.deleteCascade(reason);
1016 1017
    } 
    
1018 1019
    removeTasks(reason);
    removeJobs();
1020 1021 1022
    // Daniel thought this would be needed, but it seems not: removeEventSubscriptions();
  } 
    
1023 1024 1025
  private void removeEventScopes() {
    List<InterpretableExecution> childExecutions = new ArrayList<InterpretableExecution>(getExecutions());
    for (InterpretableExecution childExecution : childExecutions) {
1026
      if(childExecution.isEventScope()) {
1027 1028 1029 1030
        log.debug("removing eventScope {}", childExecution);
        childExecution.destroy();
        childExecution.remove();
      }
T
Tijs Rademakers 已提交
1031
    }
1032
  }
T
Tijs Rademakers 已提交
1033

1034 1035 1036
  private void removeEventSubscriptions() {
    for (EventSubscriptionEntity eventSubscription : getEventSubscriptions()) {
      eventSubscription.delete();
T
Tijs Rademakers 已提交
1037
    }
1038
  }
T
Tijs Rademakers 已提交
1039

1040
  private void removeJobs() {
1041
    for (Job job: getJobs()) {
1042
      ((JobEntity) job).delete();
T
Tijs Rademakers 已提交
1043
    }
1044
  }
T
Tijs Rademakers 已提交
1045

1046
  private void removeTasks(String reason) {
1047
    if(reason == null) {
1048
      reason = TaskEntity.DELETE_REASON_DELETED;
T
Tijs Rademakers 已提交
1049
    }
1050
    for (TaskEntity task : getTasks()) {
1051 1052 1053
      if (replacedBy!=null) {
        if(task.getExecution() == null || task.getExecution() != replacedBy) {
          // All tasks should have been moved when "replacedBy" has been set. Just in case tasks where added,
1054 1055 1056
          // wo do an additional check here and move it
          task.setExecution(replacedBy);
          this.replacedBy.addTask(task);
T
Tijs Rademakers 已提交
1057
        }
1058
      } else {
1059 1060 1061
        Context.getCommandContext()
          .getTaskEntityManager()
          .deleteTask(task, reason, false);
1062
      }
T
Tijs Rademakers 已提交
1063
    }
1064
  }
1065
  
1066 1067 1068
  public ExecutionEntity getReplacedBy() {
    return replacedBy;
  }
T
Tijs Rademakers 已提交
1069

1070 1071 1072
  @SuppressWarnings({ "unchecked", "rawtypes" })
  public void setReplacedBy(InterpretableExecution replacedBy) {
    this.replacedBy = (ExecutionEntity) replacedBy;
1073
    
1074 1075
    CommandContext commandContext = Context.getCommandContext();
    DbSqlSession dbSqlSession = commandContext.getDbSqlSession();
T
Tijs Rademakers 已提交
1076

1077
    // update the related tasks
1078
    
1079 1080
    List<TaskEntity> allTasks = new ArrayList<TaskEntity>();
    allTasks.addAll(getTasks());
1081
    
1082 1083
    List<TaskEntity> cachedTasks = dbSqlSession.findInCache(TaskEntity.class);
    for (TaskEntity cachedTask : cachedTasks) {
1084 1085 1086
    	if (cachedTask.getExecutionId().equals(this.getId())) {
    		allTasks.add(cachedTask);
    	}
T
Tijs Rademakers 已提交
1087
    }
1088 1089
    
    for (TaskEntity task: allTasks) {
1090
      task.setExecutionId(replacedBy.getId());
1091 1092
      task.setExecution(this.replacedBy);         
      
1093
      // update the related local task variables
1094 1095 1096 1097
      List<VariableInstanceEntity> variables = (List) commandContext
        .getVariableInstanceEntityManager()
        .findVariableInstancesByTaskId(task.getId());
      
1098 1099 1100
      for (VariableInstanceEntity variable : variables) {
        variable.setExecution(this.replacedBy);
      }
1101
      
1102
      this.replacedBy.addTask(task);
T
Tijs Rademakers 已提交
1103
    }
1104 1105
    
    // All tasks have been moved to 'replacedBy', safe to clear the list 
1106
    this.tasks.clear();
1107
    
1108
    tasks = dbSqlSession.findInCache(TaskEntity.class);
1109
    for (TaskEntity task: tasks) {
1110 1111 1112
      if (id.equals(task.getExecutionId())) {
        task.setExecutionId(replacedBy.getId());
      }
T
Tijs Rademakers 已提交
1113
    }
1114
    
1115 1116
    // update the related jobs
    List<JobEntity> jobs = getJobs();
1117
    for (JobEntity job: jobs) {
1118
      job.setExecution((ExecutionEntity) replacedBy);
T
Tijs Rademakers 已提交
1119
    }
1120
    
1121 1122
    // update the related event subscriptions
    List<EventSubscriptionEntity> eventSubscriptions = getEventSubscriptions();
1123
    for (EventSubscriptionEntity subscriptionEntity: eventSubscriptions) {
1124
      subscriptionEntity.setExecution((ExecutionEntity) replacedBy);
T
Tijs Rademakers 已提交
1125
    }
1126
    
1127
    // update the related process variables
1128 1129 1130 1131 1132
    List<VariableInstanceEntity> variables = (List) commandContext
      .getVariableInstanceEntityManager()
      .findVariableInstancesByExecutionId(id);
    
    for (VariableInstanceEntity variable: variables) {
1133
      variable.setExecutionId(replacedBy.getId());
T
Tijs Rademakers 已提交
1134
    }
1135
    variables = dbSqlSession.findInCache(VariableInstanceEntity.class);
1136
    for (VariableInstanceEntity variable: variables) {
1137 1138 1139
      if (id.equals(variable.getExecutionId())) {
        variable.setExecutionId(replacedBy.getId());
      }
T
Tijs Rademakers 已提交
1140
    }
1141 1142 1143
    
    commandContext.getHistoryManager()
      .recordExecutionReplacedBy(this, replacedBy);
1144
  }
T
Tijs Rademakers 已提交
1145

1146
  // variables ////////////////////////////////////////////////////////////////
T
Tijs Rademakers 已提交
1147

1148 1149 1150 1151 1152 1153 1154 1155
  @Override
  protected void initializeVariableInstanceBackPointer(VariableInstanceEntity variableInstance) {
    variableInstance.setProcessInstanceId(processInstanceId);
    variableInstance.setExecutionId(id);
  }

  @Override
  protected List<VariableInstanceEntity> loadVariableInstances() {
1156 1157 1158 1159
    return Context
      .getCommandContext()
      .getVariableInstanceEntityManager()
      .findVariableInstancesByExecutionId(id);
1160 1161 1162 1163 1164 1165
  }

  @Override
  protected VariableScopeImpl getParentVariableScope() {
    return getParent();
  }
T
Tijs Rademakers 已提交
1166

1167
  /** used to calculate the sourceActivityExecution for method {@link #updateActivityInstanceIdInHistoricVariableUpdate(HistoricDetailVariableInstanceUpdateEntity, ExecutionEntity)} */
1168
  protected ExecutionEntity getSourceActivityExecution() {
1169
    return (activityId!=null ? this : null);
1170
  }
1171
  
1172 1173 1174 1175
  @Override
  protected boolean isActivityIdUsedForDetails() {
    return true;
  }
1176
  
1177
  @Override
1178 1179
  protected VariableInstanceEntity createVariableInstance(String variableName, Object value,
      ExecutionEntity sourceActivityExecution) {
1180
    VariableInstanceEntity result = super.createVariableInstance(variableName, value, sourceActivityExecution);
1181
    
1182
    // Dispatch event, if needed
1183 1184 1185 1186
    if(Context.getProcessEngineConfiguration() != null && Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
  		Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(
  				ActivitiEventBuilder.createVariableEvent(ActivitiEventType.VARIABLE_CREATED, variableName, value, result.getType(), result.getTaskId(), 
  						result.getExecutionId(), getProcessInstanceId(), getProcessDefinitionId()));
1187 1188 1189
    }
    return result;
  }
1190
  
1191
  @Override
1192 1193
  protected void updateVariableInstance(VariableInstanceEntity variableInstance, Object value,
      ExecutionEntity sourceActivityExecution) {
1194
    super.updateVariableInstance(variableInstance, value, sourceActivityExecution);
1195
    
1196
    // Dispatch event, if needed
1197 1198 1199 1200
    if(Context.getProcessEngineConfiguration() != null && Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
    	Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(
    			ActivitiEventBuilder.createVariableEvent(ActivitiEventType.VARIABLE_UPDATED, variableInstance.getName(), value, variableInstance.getType(), 
    					variableInstance.getTaskId(), variableInstance.getExecutionId(), getProcessInstanceId(), getProcessDefinitionId()));
1201 1202
    }
  }
1203
  
1204 1205 1206
  @Override
  protected VariableInstanceEntity getSpecificVariable(String variableName) {

1207
  	CommandContext commandContext = Context.getCommandContext();
1208 1209 1210
    if (commandContext == null) {
      throw new ActivitiException("lazy loading outside command context");
    }
1211 1212 1213 1214
    VariableInstanceEntity variableInstance = commandContext
    	.getVariableInstanceEntityManager()
    	.findVariableInstanceByExecutionAndName(id, variableName);
    
1215 1216
    return variableInstance;
  }
1217
  
1218 1219
  @Override
  protected List<VariableInstanceEntity> getSpecificVariables(Collection<String> variableNames) {
1220
  	CommandContext commandContext = Context.getCommandContext();
1221 1222 1223
    if (commandContext == null) {
      throw new ActivitiException("lazy loading outside command context");
    }
1224 1225 1226
    return commandContext
    	.getVariableInstanceEntityManager()
    	.findVariableInstancesByExecutionAndNames(id, variableNames);
1227
  }
1228 1229
  
  // persistent state /////////////////////////////////////////////////////////
1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250

  public Object getPersistentState() {
    Map<String, Object> persistentState = new HashMap<String, Object>();
    persistentState.put("processDefinitionId", this.processDefinitionId);
    persistentState.put("businessKey", this.businessKey);
    persistentState.put("activityId", this.activityId);
    persistentState.put("isActive", this.isActive);
    persistentState.put("isConcurrent", this.isConcurrent);
    persistentState.put("isScope", this.isScope);
    persistentState.put("isEventScope", this.isEventScope);
    persistentState.put("parentId", parentId);
    persistentState.put("name", name);
    persistentState.put("lockTime", lockTime);
    persistentState.put("superExecution", this.superExecutionId);
    if (forcedUpdate) {
      persistentState.put("forcedUpdate", Boolean.TRUE);
    }
    persistentState.put("suspensionState", this.suspensionState);
    persistentState.put("cachedEntityState", this.cachedEntityState);
    return persistentState;
  }
1251
  
1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273
  // The current flow element, will be filled during operation execution

  public FlowElement getCurrentFlowElement() {
    if (currentFlowElement == null) {
      String processDefinitionId = getProcessDefinitionId();
      if (processDefinitionId != null) {
        org.activiti.bpmn.model.Process process = ProcessDefinitionUtil.getProcess(processDefinitionId);
        currentFlowElement = process.getFlowElement(getCurrentActivityId(), true);
      }
    }
    return currentFlowElement;
  }

  public void setCurrentFlowElement(FlowElement currentFlowElement) {
    this.currentFlowElement = currentFlowElement;
    if (currentFlowElement != null) {
      this.activityId = currentFlowElement.getId();
    } else {
      this.activityId = null;
    }
  }
  
1274
  public void insert() {
1275 1276 1277 1278
    Context
      .getCommandContext()
      .getDbSqlSession()
      .insert(this);
1279
  }
1280
  
1281 1282 1283 1284 1285
  public void deleteCascade(String deleteReason) {
    this.deleteReason = deleteReason;
    this.deleteRoot = true;
    performOperation(AtomicOperation.DELETE_CASCADE);
  }
1286
  
1287
  public int getRevisionNext() {
1288
    return revision+1;
1289
  }
1290
  
1291 1292 1293
  public void forceUpdate() {
    this.forcedUpdate = true;
  }
1294 1295 1296
  
  // toString /////////////////////////////////////////////////////////////////
  
1297 1298
  public String toString() {
    if (isProcessInstanceType()) {
1299
      return "ProcessInstance["+getToStringIdentity()+"]";
1300
    } else {
1301
      return (isConcurrent? "Concurrent" : "")+(isScope ? "Scope" : "")+"Execution["+getToStringIdentity()+"]";
1302 1303 1304 1305 1306 1307
    }
  }

  protected String getToStringIdentity() {
    return id;
  }
1308
  
1309
  // event subscription support //////////////////////////////////////////////
1310
  
1311
  public List<EventSubscriptionEntity> getEventSubscriptionsInternal() {
1312
    ensureEventSubscriptionsInitialized();   
1313 1314
    return eventSubscriptions;
  }
1315
  
1316 1317 1318
  public List<EventSubscriptionEntity> getEventSubscriptions() {
    return new ArrayList<EventSubscriptionEntity>(getEventSubscriptionsInternal());
  }
1319
  
1320 1321 1322 1323
  public List<CompensateEventSubscriptionEntity> getCompensateEventSubscriptions() {
    List<EventSubscriptionEntity> eventSubscriptions = getEventSubscriptionsInternal();
    List<CompensateEventSubscriptionEntity> result = new ArrayList<CompensateEventSubscriptionEntity>(eventSubscriptions.size());
    for (EventSubscriptionEntity eventSubscriptionEntity : eventSubscriptions) {
1324
      if(eventSubscriptionEntity instanceof CompensateEventSubscriptionEntity) {
1325 1326 1327 1328 1329
        result.add((CompensateEventSubscriptionEntity) eventSubscriptionEntity);
      }
    }
    return result;
  }
1330
  
1331 1332 1333 1334
  public List<CompensateEventSubscriptionEntity> getCompensateEventSubscriptions(String activityId) {
    List<EventSubscriptionEntity> eventSubscriptions = getEventSubscriptionsInternal();
    List<CompensateEventSubscriptionEntity> result = new ArrayList<CompensateEventSubscriptionEntity>(eventSubscriptions.size());
    for (EventSubscriptionEntity eventSubscriptionEntity : eventSubscriptions) {
1335 1336
      if(eventSubscriptionEntity instanceof CompensateEventSubscriptionEntity) {
        if(activityId.equals(eventSubscriptionEntity.getActivityId())) {
1337 1338 1339 1340 1341 1342 1343 1344 1345
          result.add((CompensateEventSubscriptionEntity) eventSubscriptionEntity);
        }
      }
    }
    return result;
  }

  protected void ensureEventSubscriptionsInitialized() {
    if (eventSubscriptions == null) {
1346 1347 1348
      eventSubscriptions = Context.getCommandContext()
        .getEventSubscriptionEntityManager()
        .findEventSubscriptionsByExecution(id);
1349 1350
    }
  }
1351
  
1352 1353
  public void addEventSubscription(EventSubscriptionEntity eventSubscriptionEntity) {
    getEventSubscriptionsInternal().add(eventSubscriptionEntity);
1354
    
1355 1356 1357 1358 1359
  }

  public void removeEventSubscription(EventSubscriptionEntity eventSubscriptionEntity) {
    getEventSubscriptionsInternal().remove(eventSubscriptionEntity);
  }
1360 1361 1362
  
  // referenced job entities //////////////////////////////////////////////////
  
1363 1364
  @SuppressWarnings({ "unchecked", "rawtypes" })
  protected void ensureJobsInitialized() {
1365 1366 1367 1368 1369
    if(jobs == null) {    
      jobs = (List)Context.getCommandContext()
        .getJobEntityManager()
        .findJobsByExecutionId(id);
    }    
1370
  }
1371
  
1372 1373 1374 1375
  protected List<JobEntity> getJobsInternal() {
    ensureJobsInitialized();
    return jobs;
  }
1376
  
1377 1378 1379
  public List<JobEntity> getJobs() {
    return new ArrayList<JobEntity>(getJobsInternal());
  }
1380
  
1381 1382 1383
  public void addJob(JobEntity jobEntity) {
    getJobsInternal().add(jobEntity);
  }
1384
  
1385 1386 1387
  public void removeJob(JobEntity job) {
    getJobsInternal().remove(job);
  }
1388 1389 1390
  
  // referenced task entities ///////////////////////////////////////////////////
  
1391 1392
  @SuppressWarnings({ "unchecked", "rawtypes" })
  protected void ensureTasksInitialized() {
1393 1394 1395 1396 1397
    if(tasks == null) {    
      tasks = (List)Context.getCommandContext()
        .getTaskEntityManager()
        .findTasksByExecutionId(id);      
    }    
1398
  }
T
Tijs Rademakers 已提交
1399

1400 1401 1402 1403
  protected List<TaskEntity> getTasksInternal() {
    ensureTasksInitialized();
    return tasks;
  }
1404
  
1405 1406 1407
  public List<TaskEntity> getTasks() {
    return new ArrayList<TaskEntity>(getTasksInternal());
  }
1408
  
1409 1410 1411
  public void addTask(TaskEntity taskEntity) {
    getTasksInternal().add(taskEntity);
  }
1412
  
1413 1414 1415
  public void removeTask(TaskEntity task) {
    getTasksInternal().remove(task);
  }
1416 1417
    
  // identity links ///////////////////////////////////////////////////////////
T
Tijs Rademakers 已提交
1418

1419 1420
  public List<IdentityLinkEntity> getIdentityLinks() {
    if (identityLinks == null) {
1421 1422 1423 1424
      identityLinks = Context
        .getCommandContext()
        .getIdentityLinkEntityManager()
        .findIdentityLinksByProcessInstanceId(id);
T
Tijs Rademakers 已提交
1425
    }
1426
    
1427 1428
    return identityLinks;
  }
T
Tijs Rademakers 已提交
1429

1430 1431 1432 1433 1434 1435 1436 1437 1438 1439
  public IdentityLinkEntity addIdentityLink(String userId, String groupId, String type) {
    IdentityLinkEntity identityLinkEntity = new IdentityLinkEntity();
    getIdentityLinks().add(identityLinkEntity);
    identityLinkEntity.setProcessInstance(this);
    identityLinkEntity.setUserId(userId);
    identityLinkEntity.setGroupId(groupId);
    identityLinkEntity.setType(type);
    identityLinkEntity.insert();
    return identityLinkEntity;
  }
1440 1441 1442 1443
  
  /** 
   * Adds an IdentityLink for this user with the specified type, 
   * but only if the user is not associated with this instance yet.
1444 1445 1446 1447 1448 1449
   **/
  public IdentityLinkEntity involveUser(String userId, String type) {
    for (IdentityLinkEntity identityLink : getIdentityLinks()) {
      if (identityLink.isUser() && identityLink.getUserId().equals(userId)) {
        return identityLink;
      }
T
Tijs Rademakers 已提交
1450
    }
1451 1452
    return addIdentityLink(userId, null, type);
  }
1453
  
1454
  public void removeIdentityLinks() {
1455 1456 1457 1458 1459 1460 1461 1462 1463
    Context
      .getCommandContext()
      .getIdentityLinkEntityManager()
      .deleteIdentityLinksByProcInstance(id);
  }
  
  // getters and setters //////////////////////////////////////////////////////
  
  
1464 1465
  public void setCachedEntityState(int cachedEntityState) {
    this.cachedEntityState = cachedEntityState;
1466 1467
    
    // Check for flags that are down. These lists can be safely initialized as empty, preventing
1468
    // additional queries that end up in an empty list anyway
1469
    if(jobs == null && !BitMaskUtil.isBitOn(cachedEntityState, JOBS_STATE_BIT)) {
1470
      jobs = new ArrayList<JobEntity>();
T
Tijs Rademakers 已提交
1471
    }
1472
    if(tasks == null && !BitMaskUtil.isBitOn(cachedEntityState, TASKS_STATE_BIT)) {
1473
      tasks = new ArrayList<TaskEntity>();
T
Tijs Rademakers 已提交
1474
    }
1475
    if(eventSubscriptions == null && !BitMaskUtil.isBitOn(cachedEntityState, EVENT_SUBSCRIPTIONS_STATE_BIT)) {
1476
      eventSubscriptions = new ArrayList<EventSubscriptionEntity>();
T
Tijs Rademakers 已提交
1477
    }
1478
  }
1479
    
1480 1481
  public int getCachedEntityState() {
    cachedEntityState = 0;
1482 1483
    
    // Only mark a flag as false when the list is not-null and empty. If null, we can't be sure there are no entries in it since
1484 1485
    // the list hasn't been initialized/queried yet.
    cachedEntityState = BitMaskUtil.setBit(cachedEntityState, TASKS_STATE_BIT, (tasks == null || !tasks.isEmpty()));
1486 1487
    cachedEntityState = BitMaskUtil.setBit(cachedEntityState, EVENT_SUBSCRIPTIONS_STATE_BIT, (eventSubscriptions == null || !eventSubscriptions
            .isEmpty()));
1488
    cachedEntityState = BitMaskUtil.setBit(cachedEntityState, JOBS_STATE_BIT, (jobs == null || !jobs.isEmpty()));
1489
    
1490 1491
    return cachedEntityState;
  }
1492
  
1493 1494 1495
  public String getProcessInstanceId() {
    return processInstanceId;
  }
1496 1497 1498
  public String getRootProcessInstanceId() {
    return processInstanceId;
  }
1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519
  public String getParentId() {
    return parentId;
  }
  public void setParentId(String parentId) {
    this.parentId = parentId;
  }
  public String getId() {
    return id;
  }
  public void setId(String id) {
    this.id = id;
  }
  public int getRevision() {
    return revision;
  }
  public void setRevision(int revision) {
    this.revision = revision;
  }
  public String getActivityId() {
    return activityId;
  }
1520
  
1521 1522 1523 1524 1525 1526
  public TransitionImpl getTransition() {
    return transition;
  }
  public void setTransition(TransitionImpl transition) {
    this.transition = transition;
    if (replacedBy != null) {
1527
    	replacedBy.setTransition(transition);
1528 1529 1530 1531 1532 1533 1534 1535
    }
  }
  public TransitionImpl getTransitionBeingTaken() {
    return transitionBeingTaken;
  }
  public void setTransitionBeingTaken(TransitionImpl transitionBeingTaken) {
    this.transitionBeingTaken = transitionBeingTaken;
    if (replacedBy != null) {
1536
    	replacedBy.setTransitionBeingTaken(transitionBeingTaken);
T
Tijs Rademakers 已提交
1537
    }
1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580
  }
  public Integer getExecutionListenerIndex() {
    return executionListenerIndex;
  }
  public void setExecutionListenerIndex(Integer executionListenerIndex) {
    this.executionListenerIndex = executionListenerIndex;
  }
  public boolean isConcurrent() {
    return isConcurrent;
  }
  public void setConcurrent(boolean isConcurrent) {
    this.isConcurrent = isConcurrent;
  }
  public boolean isActive() {
    return isActive;
  }
  public void setActive(boolean isActive) {
    this.isActive = isActive;
  }
  public boolean isEnded() {
    return isEnded;
  }
  public String getEventName() {
    return eventName;
  }
  public void setEventName(String eventName) {
    this.eventName = eventName;
  }
  public PvmProcessElement getEventSource() {
    return eventSource;
  }
  public void setEventSource(PvmProcessElement eventSource) {
    this.eventSource = eventSource;
  }
  public String getDeleteReason() {
    return deleteReason;
  }
  public void setDeleteReason(String deleteReason) {
    this.deleteReason = deleteReason;
  }
  public boolean isDeleteRoot() {
    return deleteRoot;
  }
1581
    
1582 1583 1584
  public int getSuspensionState() {
    return suspensionState;
  }
1585
    
1586 1587 1588
  public void setSuspensionState(int suspensionState) {
    this.suspensionState = suspensionState;
  }
1589
  
1590 1591 1592
  public boolean isSuspended() {
    return suspensionState == SuspensionState.SUSPENDED.getStateCode();
  }
T
Tijs Rademakers 已提交
1593

1594 1595 1596
  public boolean isEventScope() {
    return isEventScope;
  }
T
Tijs Rademakers 已提交
1597

1598 1599 1600
  public void setEventScope(boolean isEventScope) {
    this.isEventScope = isEventScope;
  }
1601
  
1602 1603 1604
  public StartingExecution getStartingExecution() {
    return startingExecution;
  }
1605
  
1606 1607 1608
  public void disposeStartingExecution() {
    startingExecution = null;
  }
1609
  
1610 1611 1612
  public String getCurrentActivityId() {
    return activityId;
  }
1613
  
1614 1615 1616
  public String getCurrentActivityName() {
    return activityName;
  }
T
Tijs Rademakers 已提交
1617

1618 1619 1620 1621
  @Override
  public String getName() {
    return this.name;
  }
1622
  
1623 1624 1625
  public void setName(String name) {
    this.name = name;
  }
1626
  
1627
  public String getTenantId() {
1628 1629 1630 1631 1632 1633 1634 1635
		return tenantId;
	}
  
	public void setTenantId(String tenantId) {
		this.tenantId = tenantId;
	}

	public Date getLockTime() {
1636 1637
    return lockTime;
  }
T
Tijs Rademakers 已提交
1638

1639 1640 1641
  public void setLockTime(Date lockTime) {
    this.lockTime = lockTime;
  }
T
Tijs Rademakers 已提交
1642

1643 1644 1645
  public Map<String, Object> getProcessVariables() {
    Map<String, Object> variables = new HashMap<String, Object>();
    if (queryVariables != null) {
1646
      for (VariableInstanceEntity variableInstance: queryVariables) {
1647 1648
        if (variableInstance.getId() != null && variableInstance.getTaskId() == null) {
          variables.put(variableInstance.getName(), variableInstance.getValue());
T
Tijs Rademakers 已提交
1649
        }
1650
      }
T
Tijs Rademakers 已提交
1651
    }
1652 1653
    return variables;
  }
1654
  
1655 1656 1657
  public List<VariableInstanceEntity> getQueryVariables() {
    if (queryVariables == null && Context.getCommandContext() != null) {
      queryVariables = new VariableInitializingList();
T
Tijs Rademakers 已提交
1658
    }
1659 1660
    return queryVariables;
  }
1661
  
1662 1663 1664
  public void setQueryVariables(List<VariableInstanceEntity> queryVariables) {
    this.queryVariables = queryVariables;
  }
1665
  
1666 1667 1668 1669
  public String updateProcessBusinessKey(String bzKey) {
    if (isProcessInstanceType() && bzKey != null) {
      setBusinessKey(bzKey);
      Context.getCommandContext().getHistoryManager().updateProcessBusinessKeyInHistory(this);
1670
      
1671
      if (Context.getProcessEngineConfiguration() != null && Context.getProcessEngineConfiguration().getEventDispatcher().isEnabled()) {
1672 1673
      	Context.getProcessEngineConfiguration().getEventDispatcher().dispatchEvent(
      			ActivitiEventBuilder.createEntityEvent(ActivitiEventType.ENTITY_UPDATED, this));
1674
      }
1675
      
1676
      return bzKey;
T
Tijs Rademakers 已提交
1677
    }
1678 1679
    return null;
  }
1680
  
1681
  public void deleteIdentityLink(String userId, String groupId, String type) {
1682 1683
    List<IdentityLinkEntity> identityLinks = Context.getCommandContext().getIdentityLinkEntityManager()
            .findIdentityLinkByProcessInstanceUserGroupAndType(id, userId, groupId, type);
T
Tijs Rademakers 已提交
1684

1685 1686 1687
    for (IdentityLinkEntity identityLink : identityLinks) {
      Context.getCommandContext().getIdentityLinkEntityManager().deleteIdentityLink(identityLink, true);
    }
T
Tijs Rademakers 已提交
1688

1689
    getIdentityLinks().removeAll(identityLinks);
T
Tijs Rademakers 已提交
1690

1691
  }
1692
  
1693
}