/* 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.persistence.entity;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.activiti.engine.impl.EventSubscriptionQueryImpl;
import org.activiti.engine.impl.HistoricActivityInstanceQueryImpl;
import org.activiti.engine.impl.JobQueryImpl;
import org.activiti.engine.impl.TaskQueryImpl;
import org.activiti.engine.impl.bpmn.parser.BpmnParse;
import org.activiti.engine.impl.bpmn.parser.SignalEventDefinition;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.db.DbSqlSession;
import org.activiti.engine.impl.db.PersistentObject;
import org.activiti.engine.impl.event.CompensationEventHandler;
import org.activiti.engine.impl.history.handler.ActivityInstanceEndHandler;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.jobexecutor.AsyncContinuationJobHandler;
import org.activiti.engine.impl.jobexecutor.TimerDeclarationImpl;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.PvmException;
import org.activiti.engine.impl.pvm.PvmExecution;
import org.activiti.engine.impl.pvm.PvmProcessDefinition;
import org.activiti.engine.impl.pvm.PvmProcessElement;
import org.activiti.engine.impl.pvm.PvmProcessInstance;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.delegate.ActivityExecution;
import org.activiti.engine.impl.pvm.delegate.ExecutionListenerExecution;
import org.activiti.engine.impl.pvm.delegate.SignallableActivityBehavior;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.ProcessDefinitionImpl;
import org.activiti.engine.impl.pvm.process.ScopeImpl;
import org.activiti.engine.impl.pvm.process.TransitionImpl;
import org.activiti.engine.impl.pvm.runtime.AtomicOperation;
import org.activiti.engine.impl.pvm.runtime.InterpretableExecution;
import org.activiti.engine.impl.pvm.runtime.OutgoingExecution;
import org.activiti.engine.impl.pvm.runtime.StartingExecution;
import org.activiti.engine.impl.variable.VariableDeclaration;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.Job;
import org.activiti.engine.runtime.ProcessInstance;
/**
* @author Tom Baeyens
*/
public class ExecutionEntity extends VariableScopeImpl implements ActivityExecution, ExecutionListenerExecution, Execution, PvmExecution, ProcessInstance, InterpretableExecution, PersistentObject {
private static final long serialVersionUID = 1L;
private static Logger log = Logger.getLogger(ExecutionEntity.class.getName());
// current position /////////////////////////////////////////////////////////
protected ProcessDefinitionImpl processDefinition;
/** current activity */
protected ActivityImpl activity;
/** current transition. is null when there is no transition being taken. */
protected TransitionImpl transition = null;
/** transition that will be taken. is null when there is no transition being taken. */
protected TransitionImpl transitionBeingTaken = null;
/** the process instance. this is the root of the execution tree.
* the processInstance of a process instance is a self reference. */
protected ExecutionEntity processInstance;
/** the parent execution */
protected ExecutionEntity parent;
/** nested executions representing scopes or concurrent paths */
protected List<ExecutionEntity> executions;
/** super execution, not-null if this execution is part of a subprocess */
protected ExecutionEntity superExecution;
/** reference to a subprocessinstance, not-null if currently subprocess is started from this execution */
protected ExecutionEntity subProcessInstance;
protected StartingExecution startingExecution;
// state/type of execution //////////////////////////////////////////////////
/** indicates if this execution represents an active path of execution.
* Executions are made inactive in the following situations:
* <ul>
* <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>*/
protected boolean isActive = true;
protected boolean isScope = true;
protected boolean isConcurrent = false;
protected boolean isEnded = false;
protected boolean isEventScope = false;
// events ///////////////////////////////////////////////////////////////////
protected String eventName;
protected PvmProcessElement eventSource;
protected int executionListenerIndex = 0;
protected List<CompensateEventSubscriptionEntity> compensateEventSubscriptions;
// cascade deletion ////////////////////////////////////////////////////////
protected boolean deleteRoot;
protected String deleteReason;
// 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} */
protected ExecutionEntity replacedBy;
// atomic operations ////////////////////////////////////////////////////////
/** 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.
* @see AtomicOperation
* @see #performOperation(AtomicOperation) */
protected AtomicOperation nextOperation;
protected boolean isOperating = false;
protected String id = null;
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;
/**
* persisted reference to the current position in the diagram within the
* {@link #processDefinition}.
*
* @see #activity
* @see #setActivity(ActivityImpl)
* @see #getActivity()
*/
protected String activityId;
/**
* persisted reference to the process instance.
*
* @see #getProcessInstance()
*/
protected String processInstanceId;
/**
* persisted reference to the business key.
*/
protected String businessKey;
/**
* persisted reference to the parent of this execution.
*
* @see #getParent()
* @see #setParent(ExecutionEntity)
*/
protected String parentId;
/**
* persisted reference to the super execution of this execution
*
* @See {@link #getSuperExecution()}
* @see #setSuperExecution(ExecutionEntity)
*/
protected String superExecutionId;
protected boolean forcedUpdate;
public ExecutionEntity() {
}
public ExecutionEntity(ActivityImpl activityImpl) {
this.startingExecution = new StartingExecution(activityImpl);
}
/** creates a new execution. properties processDefinition, processInstance and activity will be initialized. */
public ExecutionEntity createExecution() {
// create the new child execution
ExecutionEntity createdExecution = newExecution();
// manage the bidirectional parent-child relation
ensureExecutionsInitialized();
executions.add(createdExecution);
createdExecution.setParent(this);
// initialize the new execution
createdExecution.setProcessDefinition(getProcessDefinition());
createdExecution.setProcessInstance(getProcessInstance());
createdExecution.setActivity(getActivity());
if (log.isLoggable(Level.FINE)) {
log.fine("Child execution "+createdExecution+" created with parent "+this);
}
return createdExecution;
}
public PvmProcessInstance createSubProcessInstance(PvmProcessDefinition processDefinition) {
ExecutionEntity subProcessInstance = newExecution();
// manage bidirectional super-subprocess relation
subProcessInstance.setSuperExecution(this);
this.setSubProcessInstance(subProcessInstance);
// Initialize the new execution
subProcessInstance.setProcessDefinition((ProcessDefinitionImpl) processDefinition);
subProcessInstance.setProcessInstance(subProcessInstance);
CommandContext commandContext = Context.getCommandContext();
int historyLevel = Context.getProcessEngineConfiguration().getHistoryLevel();
if (historyLevel>=ProcessEngineConfigurationImpl.HISTORYLEVEL_ACTIVITY) {
DbSqlSession dbSqlSession = commandContext.getSession(DbSqlSession.class);
HistoricProcessInstanceEntity historicProcessInstance = new HistoricProcessInstanceEntity((ExecutionEntity) subProcessInstance);
dbSqlSession.insert(historicProcessInstance);
}
return subProcessInstance;
}
protected ExecutionEntity newExecution() {
ExecutionEntity newExecution = new ExecutionEntity();
newExecution.executions = new ArrayList<ExecutionEntity>();
Context
.getCommandContext()
.getDbSqlSession()
.insert(newExecution);
return newExecution;
}
// scopes ///////////////////////////////////////////////////////////////////
@SuppressWarnings("unchecked")
public void initialize() {
log.fine("initializing "+this);
ScopeImpl scope = getScope();
ensureParentInitialized();
List<VariableDeclaration> variableDeclarations = (List<VariableDeclaration>) scope.getProperty(BpmnParse.PROPERTYNAME_VARIABLE_DECLARATIONS);
if (variableDeclarations!=null) {
for (VariableDeclaration variableDeclaration : variableDeclarations) {
variableDeclaration.initialize(this, parent);
}
}
List<TimerDeclarationImpl> timerDeclarations = (List<TimerDeclarationImpl>) scope.getProperty(BpmnParse.PROPERTYNAME_TIMER_DECLARATION);
if (timerDeclarations!=null) {
for (TimerDeclarationImpl timerDeclaration : timerDeclarations) {
TimerEntity timer = timerDeclaration.prepareTimerEntity(this);
Context
.getCommandContext()
.getJobManager()
.schedule(timer);
}
}
List<SignalEventDefinition> signalDefinitions = (List<SignalEventDefinition>) scope.getProperty(BpmnParse.PROPERTYNAME_SIGNAL_DEFINITION_NAME);
if(signalDefinitions != null) {
for (SignalEventDefinition signalDefinition : signalDefinitions) {
SignalEventSubscriptionEntity signalEventSubscriptionEntity = new SignalEventSubscriptionEntity(this);
signalEventSubscriptionEntity.setEventName(signalDefinition.getSignalName());
if(signalDefinition.getActivityId() != null) {
ActivityImpl activity = getActivity().findActivity(signalDefinition.getActivityId());
signalEventSubscriptionEntity.setActivity(activity);
}
Context
.getCommandContext()
.getEventSubscriptionManager()
.insert(signalEventSubscriptionEntity);
}
}
}
public void start() {
if(startingExecution == null && isProcessInstance()) {
startingExecution = new StartingExecution(processDefinition.getInitial());
}
performOperation(AtomicOperation.PROCESS_START);
}
public void destroy() {
log.fine("destroying "+this);
ensureParentInitialized();
removeVariablesLocal();
removeVariables();
setScope(false);
}
/** 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. */
public void end() {
isActive = false;
isEnded = true;
performOperation(AtomicOperation.ACTIVITY_END);
}
// methods that translate to operations /////////////////////////////////////
public void signal(String signalName, Object signalData) {
ensureActivityInitialized();
SignallableActivityBehavior activityBehavior = (SignallableActivityBehavior) activity.getActivityBehavior();
try {
activityBehavior.signal(this, signalName, signalData);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new PvmException("couldn't process signal '"+signalName+"' on activity '"+activity.getId()+"': "+e.getMessage(), e);
}
}
public void take(PvmTransition transition) {
if (this.transition!=null) {
throw new PvmException("already taking a transition");
}
if (transition==null) {
throw new PvmException("transition is null");
}
setActivity((ActivityImpl)transition.getSource());
setTransition((TransitionImpl) transition);
performOperation(AtomicOperation.TRANSITION_NOTIFY_LISTENER_END);
}
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()) {
List< ? extends ActivityExecution> concurrentExecutions = getParent().getAllChildExecutions();
for (ActivityExecution concurrentExecution: concurrentExecutions) {
if (concurrentExecution.getActivity()==activity) {
if (!concurrentExecution.isActive()) {
inactiveConcurrentExecutionsInActivity.add(concurrentExecution);
}
} else {
otherConcurrentExecutions.add(concurrentExecution);
}
}
} else {
if (!isActive()) {
inactiveConcurrentExecutionsInActivity.add(this);
} else {
otherConcurrentExecutions.add(this);
}
}
if (log.isLoggable(Level.FINE)) {
log.fine("inactive concurrent executions in '"+activity+"': "+inactiveConcurrentExecutionsInActivity);
log.fine("other concurrent executions: "+otherConcurrentExecutions);
}
return inactiveConcurrentExecutionsInActivity;
}
protected List<ExecutionEntity> getAllChildExecutions() {
List<ExecutionEntity> childExecutions = new ArrayList<ExecutionEntity>();
for (ExecutionEntity childExecution : getExecutions()) {
childExecutions.add(childExecution);
childExecutions.addAll(childExecution.getAllChildExecutions());
}
return childExecutions;
}
@SuppressWarnings("unchecked")
public void takeAll(List<PvmTransition> transitions, List<ActivityExecution> recyclableExecutions) {
transitions = new ArrayList<PvmTransition>(transitions);
recyclableExecutions = (recyclableExecutions!=null ? new ArrayList<ActivityExecution>(recyclableExecutions) : new ArrayList<ActivityExecution>());
if (recyclableExecutions.size()>1) {
for (ActivityExecution recyclableExecution: recyclableExecutions) {
if (((ExecutionEntity)recyclableExecution).isScope()) {
throw new PvmException("joining scope executions is not allowed");
}
}
}
ExecutionEntity concurrentRoot = ((isConcurrent && !isScope) ? getParent() : this);
List<ExecutionEntity> concurrentActiveExecutions = new ArrayList<ExecutionEntity>();
List<ExecutionEntity> concurrentInActiveExecutions = new ArrayList<ExecutionEntity>();
for (ExecutionEntity execution: concurrentRoot.getExecutions()) {
if (execution.isActive()) {
concurrentActiveExecutions.add(execution);
} else {
concurrentInActiveExecutions.add(execution);
}
}
if (log.isLoggable(Level.FINE)) {
log.fine("transitions to take concurrent: " + transitions);
log.fine("active concurrent executions: " + concurrentActiveExecutions);
}
if ( (transitions.size()==1)
&& (concurrentActiveExecutions.isEmpty())
&& allExecutionsInSameActivity(concurrentInActiveExecutions)
) {
List<ExecutionEntity> recyclableExecutionImpls = (List) recyclableExecutions;
recyclableExecutions.remove(concurrentRoot);
for (ExecutionEntity prunedExecution: recyclableExecutionImpls) {
// End the pruned executions if necessary.
// Some recyclable executions are inactivated (joined executions)
// Others are already ended (end activities)
if (!prunedExecution.isEnded()) {
log.fine("pruning execution " + prunedExecution);
prunedExecution.remove();
}
}
log.fine("activating the concurrent root "+concurrentRoot+" as the single path of execution going forward");
concurrentRoot.setActive(true);
concurrentRoot.setActivity(activity);
concurrentRoot.setConcurrent(false);
concurrentRoot.take(transitions.get(0));
} else {
List<OutgoingExecution> outgoingExecutions = new ArrayList<OutgoingExecution>();
recyclableExecutions.remove(concurrentRoot);
log.fine("recyclable executions for reuse: " + recyclableExecutions);
// first create the concurrent executions
while (!transitions.isEmpty()) {
PvmTransition outgoingTransition = transitions.remove(0);
ExecutionEntity outgoingExecution = null;
if (recyclableExecutions.isEmpty()) {
outgoingExecution = concurrentRoot.createExecution();
log.fine("new "+outgoingExecution+" with parent "
+ outgoingExecution.getParent()+" created to take transition "+outgoingTransition);
} else {
outgoingExecution = (ExecutionEntity) recyclableExecutions.remove(0);
log.fine("recycled "+outgoingExecution+" to take transition "+outgoingTransition);
}
outgoingExecution.setActive(true);
outgoingExecution.setScope(false);
outgoingExecution.setConcurrent(true);
outgoingExecution.setTransitionBeingTaken((TransitionImpl) outgoingTransition);
outgoingExecutions.add(new OutgoingExecution(outgoingExecution, outgoingTransition, true));
}
// prune the executions that are not recycled
for (ActivityExecution prunedExecution: recyclableExecutions) {
log.fine("pruning execution "+prunedExecution);
prunedExecution.end();
}
// then launch all the concurrent executions
for (OutgoingExecution outgoingExecution: outgoingExecutions) {
outgoingExecution.take();
}
}
}
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) {
if ( (activityId == null && otherActivityId != null)
|| (activityId != null && otherActivityId == null)
|| (activityId != null && otherActivityId!= null && !otherActivityId.equals(activityId))) {
return false;
}
}
}
}
return true;
}
public void performOperation(AtomicOperation executionOperation) {
if(executionOperation.isAsync(this)) {
scheduleAtomicOperationAsync(executionOperation);
} else {
performOperationSync(executionOperation);
}
}
protected void performOperationSync(AtomicOperation executionOperation) {
Context
.getCommandContext()
.performOperation(executionOperation, this);
}
protected void scheduleAtomicOperationAsync(AtomicOperation executionOperation) {
MessageEntity message = new MessageEntity();
message.setExecution(this);
message.setExclusive(getActivity().isExclusive());
message.setJobHandlerType(AsyncContinuationJobHandler.TYPE);
// At the moment, only AtomicOperationTransitionCreateScope can be performed asynchronously,
// so there is no need to pass it to the handler
Context
.getCommandContext()
.getJobManager()
.send(message);
}
public boolean isActive(String activityId) {
return findExecution(activityId)!=null;
}
public void inactivate() {
this.isActive = false;
}
// executions ///////////////////////////////////////////////////////////////
/** ensures initialization and returns the non-null executions list */
public List<ExecutionEntity> getExecutions() {
ensureExecutionsInitialized();
return executions;
}
@SuppressWarnings("unchecked")
protected void ensureExecutionsInitialized() {
if (executions==null) {
this.executions = (List) Context
.getCommandContext()
.getExecutionManager()
.findChildExecutionsByParentExecutionId(id);
}
}
public void setExecutions(List<ExecutionEntity> executions) {
this.executions = executions;
}
/** searches for an execution positioned in the given activity */
public ExecutionEntity findExecution(String activityId) {
if ( (getActivity()!=null)
&& (getActivity().getId().equals(activityId))
) {
return this;
}
for (ExecutionEntity nestedExecution : getExecutions()) {
ExecutionEntity result = nestedExecution.findExecution(activityId);
if (result != null) {
return result;
}
}
return null;
}
public List<String> findActiveActivityIds() {
List<String> activeActivityIds = new ArrayList<String>();
collectActiveActivityIds(activeActivityIds);
return activeActivityIds;
}
protected void collectActiveActivityIds(List<String> activeActivityIds) {
ensureActivityInitialized();
if (isActive && activity!=null) {
activeActivityIds.add(activity.getId());
}
ensureExecutionsInitialized();
for (ExecutionEntity execution: executions) {
execution.collectActiveActivityIds(activeActivityIds);
}
}
// bussiness key ////////////////////////////////////////////////////////////
public String getBusinessKey() {
return businessKey;
}
public void setBusinessKey(String businessKey) {
this.businessKey = businessKey;
}
public String getProcessBusinessKey() {
return getProcessInstance().getBusinessKey();
}
// process definition ///////////////////////////////////////////////////////
/** ensures initialization and returns the process definition. */
public ProcessDefinitionImpl getProcessDefinition() {
ensureProcessDefinitionInitialized();
return processDefinition;
}
public void setProcessDefinitionId(String processDefinitionId) {
this.processDefinitionId = processDefinitionId;
}
public String getProcessDefinitionId() {
return processDefinitionId;
}
/** for setting the process definition, this setter must be used as subclasses can override */
protected void ensureProcessDefinitionInitialized() {
if ((processDefinition == null) && (processDefinitionId != null)) {
ProcessDefinitionEntity deployedProcessDefinition = Context
.getProcessEngineConfiguration()
.getDeploymentCache()
.findDeployedProcessDefinitionById(processDefinitionId);
setProcessDefinition(deployedProcessDefinition);
}
}
public void setProcessDefinition(ProcessDefinitionImpl processDefinition) {
this.processDefinition = processDefinition;
this.processDefinitionId = processDefinition.getId();
}
// process instance /////////////////////////////////////////////////////////
/** ensures initialization and returns the process instance. */
public ExecutionEntity getProcessInstance() {
ensureProcessInstanceInitialized();
return processInstance;
}
protected void ensureProcessInstanceInitialized() {
if ((processInstance == null) && (processInstanceId != null)) {
processInstance = Context
.getCommandContext()
.getExecutionManager()
.findExecutionById(processInstanceId);
}
}
public void setProcessInstance(InterpretableExecution processInstance) {
this.processInstance = (ExecutionEntity) processInstance;
if (processInstance != null) {
this.processInstanceId = this.processInstance.getId();
}
}
public boolean isProcessInstance() {
return parentId == null;
}
// activity /////////////////////////////////////////////////////////////////
/** ensures initialization and returns the activity */
public ActivityImpl getActivity() {
ensureActivityInitialized();
return activity;
}
/** must be called before the activity member field or getActivity() is called */
protected void ensureActivityInitialized() {
if ((activity == null) && (activityId != null)) {
activity = getProcessDefinition().findActivity(activityId);
}
}
public void setActivity(ActivityImpl activity) {
this.activity = activity;
if (activity != null) {
this.activityId = activity.getId();
} else {
this.activityId = null;
}
}
// parent ///////////////////////////////////////////////////////////////////
/** ensures initialization and returns the parent */
public ExecutionEntity getParent() {
ensureParentInitialized();
return parent;
}
protected void ensureParentInitialized() {
if (parent == null && parentId != null) {
parent = Context
.getCommandContext()
.getExecutionManager()
.findExecutionById(parentId);
}
}
public void setParent(InterpretableExecution parent) {
this.parent = (ExecutionEntity) parent;
if (parent != null) {
this.parentId = ((ExecutionEntity)parent).getId();
} else {
this.parentId = null;
}
}
// super- and subprocess executions /////////////////////////////////////////
public String getSuperExecutionId() {
return superExecutionId;
}
public ExecutionEntity getSuperExecution() {
ensureSuperExecutionInitialized();
return superExecution;
}
public void setSuperExecution(ExecutionEntity superExecution) {
this.superExecution = superExecution;
if (superExecution != null) {
superExecution.setSubProcessInstance(null);
}
if (superExecution != null) {
this.superExecutionId = ((ExecutionEntity)superExecution).getId();
} else {
this.superExecutionId = null;
}
}
protected void ensureSuperExecutionInitialized() {
if (superExecution == null && superExecutionId != null) {
superExecution = Context
.getCommandContext()
.getExecutionManager()
.findExecutionById(superExecutionId);
}
}
public ExecutionEntity getSubProcessInstance() {
ensureSubProcessInstanceInitialized();
return subProcessInstance;
}
public void setSubProcessInstance(InterpretableExecution subProcessInstance) {
this.subProcessInstance = (ExecutionEntity) subProcessInstance;
}
protected void ensureSubProcessInstanceInitialized() {
if (subProcessInstance == null) {
subProcessInstance = Context
.getCommandContext()
.getExecutionManager()
.findSubProcessInstanceBySuperExecutionId(id);
}
}
// scopes ///////////////////////////////////////////////////////////////////
protected ScopeImpl getScope() {
ScopeImpl scope = null;
if (isProcessInstance()) {
scope = getProcessDefinition();
} else {
scope = getActivity();
}
return scope;
}
public boolean isScope() {
return isScope;
}
public void setScope(boolean isScope) {
this.isScope = isScope;
}
// customized persistence behaviour /////////////////////////////////////////
@SuppressWarnings("unchecked")
public void remove() {
ensureParentInitialized();
if (parent!=null) {
parent.ensureExecutionsInitialized();
parent.executions.remove(this);
}
// delete all the variable instances
ensureVariableInstancesInitialized();
removeVariablesLocal();
// delete all the tasks
CommandContext commandContext = Context.getCommandContext();
List<TaskEntity> tasks = commandContext
.getTaskManager()
.findTasksByExecutionId(id);
for (TaskEntity task : tasks) {
if (replacedBy!=null) {
task.setExecution(replacedBy);
} else {
commandContext
.getTaskManager()
.deleteTask(task, TaskEntity.DELETE_REASON_DELETED, false);
}
}
// Delete all jobs
List<Job> jobs = commandContext
.getJobManager()
.findJobsByExecutionId(id);
for (Job job: jobs) {
if (replacedBy!=null) {
((JobEntity)job).setExecution((ExecutionEntity) replacedBy);
} else {
((JobEntity)job).delete();
}
}
// delete event subscriptions for this scope:
List<SignalEventSubscriptionEntity> eventSubscriptions = commandContext.getEventSubscriptionManager()
.findSignalEventSubscriptionsByExecution(id);
for (EventSubscriptionEntity eventSubscription : eventSubscriptions) {
if (replacedBy!=null) {
eventSubscription.setExecution(replacedBy);
} else {
eventSubscription.delete();
}
}
for (CompensateEventSubscriptionEntity compensateEventSubscription : getCompensateEventSubscriptions()) {
if (replacedBy!=null) {
compensateEventSubscription.setExecution(replacedBy);
} else {
removeCompensateEventSubscription(compensateEventSubscription);
compensateEventSubscription.delete();
}
}
// remove event scopes:
List<InterpretableExecution> childExecutions = new ArrayList<InterpretableExecution>(getExecutions());
for (InterpretableExecution childExecution : childExecutions) {
if(childExecution.isEventScope()) {
log.fine("removing eventScope "+childExecution);
childExecution.destroy();
childExecution.remove();
}
}
// then delete execution
commandContext
.getDbSqlSession()
.delete(ExecutionEntity.class, id);
}
public ExecutionEntity getReplacedBy() {
return replacedBy;
}
@SuppressWarnings("unchecked")
public void setReplacedBy(InterpretableExecution replacedBy) {
this.replacedBy = (ExecutionEntity) replacedBy;
CommandContext commandContext = Context.getCommandContext();
DbSqlSession dbSqlSession = commandContext.getDbSqlSession();
// update the related tasks
List<TaskEntity> tasks = (List) new TaskQueryImpl(commandContext)
.executionId(id)
.list();
for (TaskEntity task: tasks) {
task.setExecutionId(replacedBy.getId());
}
tasks = dbSqlSession.findInCache(TaskEntity.class);
for (TaskEntity task: tasks) {
if (id.equals(task.getExecutionId())) {
task.setExecutionId(replacedBy.getId());
}
}
// update the related jobs
List<JobEntity> jobs = (List) new JobQueryImpl(commandContext)
.executionId(id)
.list();
for (JobEntity job: jobs) {
job.setExecutionId(replacedBy.getId());
}
jobs = dbSqlSession.findInCache(JobEntity.class);
for (JobEntity job: jobs) {
if (id.equals(job.getExecutionId())) {
job.setExecutionId(replacedBy.getId());
}
}
// update the related event subscriptions
List<EventSubscriptionEntity> eventSubscriptions = (List) new EventSubscriptionQueryImpl(commandContext)
.executionId(id)
.list();
for (EventSubscriptionEntity subscriptionEntity: eventSubscriptions) {
subscriptionEntity.setExecutionId(replacedBy.getId());
}
eventSubscriptions = dbSqlSession.findInCache(EventSubscriptionEntity.class);
for (EventSubscriptionEntity eventSubscription: eventSubscriptions) {
if (id.equals(eventSubscription.getExecutionId())) {
eventSubscription.setExecutionId(replacedBy.getId());
}
}
// update the related process variables
List<VariableInstanceEntity> variables = (List) commandContext
.getVariableInstanceManager()
.findVariableInstancesByExecutionId(id);
for (VariableInstanceEntity variable: variables) {
variable.setExecutionId(replacedBy.getId());
}
variables = dbSqlSession.findInCache(VariableInstanceEntity.class);
for (VariableInstanceEntity variable: variables) {
if (id.equals(variable.getExecutionId())) {
variable.setExecutionId(replacedBy.getId());
}
}
// update the cached historic activity instances that are open
List<HistoricActivityInstanceEntity> cachedHistoricActivityInstances = dbSqlSession.findInCache(HistoricActivityInstanceEntity.class);
for (HistoricActivityInstanceEntity cachedHistoricActivityInstance: cachedHistoricActivityInstances) {
if ( (cachedHistoricActivityInstance.getEndTime()==null)
&& (id.equals(cachedHistoricActivityInstance.getExecutionId()))
) {
cachedHistoricActivityInstance.setExecutionId(replacedBy.getId());
}
}
// update the persisted historic activity instances that are open
if (Context.getProcessEngineConfiguration().getHistoryLevel()>ProcessEngineConfigurationImpl.HISTORYLEVEL_NONE) {
List<HistoricActivityInstanceEntity> historicActivityInstances = (List) new HistoricActivityInstanceQueryImpl(commandContext)
.executionId(id)
.unfinished()
.list();
for (HistoricActivityInstanceEntity historicActivityInstance: historicActivityInstances) {
historicActivityInstance.setExecutionId(replacedBy.getId());
}
}
}
// variables ////////////////////////////////////////////////////////////////
@Override
protected void initializeVariableInstanceBackPointer(VariableInstanceEntity variableInstance) {
variableInstance.setProcessInstanceId(processInstanceId);
variableInstance.setExecutionId(id);
}
@Override
protected List<VariableInstanceEntity> loadVariableInstances() {
return Context
.getCommandContext()
.getVariableInstanceManager()
.findVariableInstancesByExecutionId(id);
}
@Override
protected VariableScopeImpl getParentVariableScope() {
return getParent();
}
@Override
protected void initializeActivityInstanceId(HistoricVariableUpdateEntity historicVariableUpdate) {
int historyLevel = Context.getProcessEngineConfiguration().getHistoryLevel();
if (historyLevel >= ProcessEngineConfigurationImpl.HISTORYLEVEL_FULL) {
HistoricActivityInstanceEntity historicActivityInstance = ActivityInstanceEndHandler.findActivityInstance(this);
if (historicActivityInstance!=null) {
historicVariableUpdate.setActivityInstanceId(historicActivityInstance.getId());
}
}
}
// persistent state /////////////////////////////////////////////////////////
public Object getPersistentState() {
Map<String, Object> persistentState = new HashMap<String, Object>();
persistentState.put("processDefinitionId", this.processDefinitionId);
persistentState.put("businessKey", 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("superExecution", this.superExecutionId);
if (forcedUpdate) {
persistentState.put("forcedUpdate", Boolean.TRUE);
}
persistentState.put("suspensionState", this.suspensionState);
return persistentState;
}
public void insert() {
Context
.getCommandContext()
.getDbSqlSession()
.insert(this);
}
public void deleteCascade(String deleteReason) {
this.deleteReason = deleteReason;
this.deleteRoot = true;
performOperation(AtomicOperation.DELETE_CASCADE);
}
public int getRevisionNext() {
return revision+1;
}
public void forceUpdate() {
this.forcedUpdate = true;
}
// toString /////////////////////////////////////////////////////////////////
public String toString() {
if (isProcessInstance()) {
return "ProcessInstance["+getToStringIdentity()+"]";
} else {
return (isConcurrent? "Concurrent" : "")+(isScope ? "Scope" : "")+"Execution["+getToStringIdentity()+"]";
}
}
protected String getToStringIdentity() {
return id;
}
// compensate event subscription support ////////////////////////////////////
public List<CompensateEventSubscriptionEntity> getCompensateEventSubscriptions(String activityId) {
ensureCompensateEventSubscriptionsInitialized();
ArrayList<CompensateEventSubscriptionEntity> result = new ArrayList<CompensateEventSubscriptionEntity>();
for (CompensateEventSubscriptionEntity eventSubscriptionEntity : compensateEventSubscriptions) {
if(eventSubscriptionEntity.getActivityId().equals(activityId)) {
result.add(eventSubscriptionEntity);
}
}
return result;
}
public List<CompensateEventSubscriptionEntity> getCompensateEventSubscriptions() {
ensureCompensateEventSubscriptionsInitialized();
return new ArrayList<CompensateEventSubscriptionEntity>(compensateEventSubscriptions);
}
@SuppressWarnings({ "unchecked" })
protected void ensureCompensateEventSubscriptionsInitialized() {
if(compensateEventSubscriptions == null) {
compensateEventSubscriptions = (List)Context.getCommandContext()
.getEventSubscriptionManager()
.findEventSubscriptions(id, CompensationEventHandler.EVENT_HANDLER_TYPE);
}
}
public void addCompensateEventSubscription(CompensateEventSubscriptionEntity eventSubscriptionEntity) {
ensureCompensateEventSubscriptionsInitialized();
compensateEventSubscriptions.add(eventSubscriptionEntity);
}
public void removeCompensateEventSubscription(CompensateEventSubscriptionEntity eventSubscriptionEntity) {
ensureCompensateEventSubscriptionsInitialized();
compensateEventSubscriptions.remove(eventSubscriptionEntity);
}
// getters and setters //////////////////////////////////////////////////////
public String getProcessInstanceId() {
return processInstanceId;
}
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;
}
public TransitionImpl getTransition() {
return transition;
}
public void setTransition(TransitionImpl transition) {
this.transition = transition;
}
public TransitionImpl getTransitionBeingTaken() {
return transitionBeingTaken;
}
public void setTransitionBeingTaken(TransitionImpl transitionBeingTaken) {
this.transitionBeingTaken = transitionBeingTaken;
}
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;
}
public int getSuspensionState() {
return suspensionState;
}
public void setSuspensionState(int suspensionState) {
this.suspensionState = suspensionState;
}
public boolean isSuspended() {
return suspensionState == SuspensionState.SUSPENDED.getStateCode();
}
public boolean isEventScope() {
return isEventScope;
}
public void setEventScope(boolean isEventScope) {
this.isEventScope = isEventScope;
}
public StartingExecution getStartingExecution() {
return startingExecution;
}
public void disposeStartingExecution() {
startingExecution = null;
}
}