
com.effektif.workflow.impl.workflowinstance.ActivityInstanceImpl Maven / Gradle / Ivy
/*
* Copyright 2014 Effektif GmbH.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.effektif.workflow.impl.workflowinstance;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.effektif.workflow.impl.job.Job;
import org.joda.time.LocalDateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.effektif.workflow.api.WorkflowEngine;
import com.effektif.workflow.api.model.RelativeTime;
import com.effektif.workflow.api.model.TypedValue;
import com.effektif.workflow.api.model.WorkflowInstanceId;
import com.effektif.workflow.api.workflowinstance.ActivityInstance;
import com.effektif.workflow.impl.conditions.ConditionImpl;
import com.effektif.workflow.impl.data.DataTypeImpl;
import com.effektif.workflow.impl.data.TypedValueImpl;
import com.effektif.workflow.impl.data.types.ListTypeImpl;
import com.effektif.workflow.impl.util.Lists;
import com.effektif.workflow.impl.util.Time;
import com.effektif.workflow.impl.workflow.ActivityImpl;
import com.effektif.workflow.impl.workflow.BindingImpl;
import com.effektif.workflow.impl.workflow.InputParameterImpl;
import com.effektif.workflow.impl.workflow.TransitionImpl;
/**
* @author Tom Baeyens
*/
public class ActivityInstanceImpl extends ScopeInstanceImpl {
public static final String STATE_STARTING = "starting";
public static final String STATE_STARTING_MULTI_CONTAINER = "startingMultiParent";
public static final String STATE_STARTING_MULTI_INSTANCE = "startingMultiInstance";
public static final String STATE_PROPAGATE_TO_PARENT = "propagateToParent";
public static final String STATE_JOINING = "joining";
/** @see WorkflowInstanceImpl#isWorkAsync(ActivityInstanceImpl) */
public static final Set START_WORKSTATES = new HashSet<>(Lists.of(
STATE_STARTING,
STATE_STARTING_MULTI_CONTAINER,
STATE_STARTING_MULTI_INSTANCE));
public static final Logger log = LoggerFactory.getLogger(WorkflowEngine.class);
public String id;
public ActivityImpl activity;
public String workState;
public WorkflowInstanceId calledWorkflowInstanceId;
public List transitionsTaken;
public ActivityInstanceImpl() {
}
public ActivityInstanceImpl(ScopeInstanceImpl parent, ActivityImpl activity, String id) {
super(parent, activity);
this.id = id;
this.activity = activity;
}
public ActivityInstance toActivityInstance() {
return toActivityInstance(false);
}
public ActivityInstance toActivityInstance(boolean includeWorkState) {
ActivityInstance activityInstance = new ActivityInstance();
activityInstance.setId(id);
activityInstance.setActivityId(activity.id);
activityInstance.setCalledWorkflowInstanceId(calledWorkflowInstanceId);
toScopeInstance(activityInstance, includeWorkState);
if (includeWorkState) {
activityInstance.setPropertyOpt("workState", workState);
}
return activityInstance;
}
@Override
protected String getActivityInstanceId() {
return id;
}
public void execute() {
if (workflow.workflowEngine.notifyActivityInstanceStarted(this)) {
activity.activityType.execute(this);
}
}
/** Default BPMN logic when an activity ends */
@Override
public void onwards() {
if (log.isDebugEnabled()) {
log.debug("Onwards "+this);
}
// First we end the activity instance.
// Subsequent invocations to end will be ignored.
end();
boolean isTransitionTaken = false;
// Take each outgoing transition 'in parallel'
// Note that process concurrency is not the same as java multithreaded computation
if (activity.hasOutgoingTransitions()) {
for (TransitionImpl transition: activity.outgoingTransitions) {
// Only take a transition if there is no condition or if the condition resolves to true.
ConditionImpl condition = transition.condition;
if (condition!=null ? condition.eval(this) : true) {
isTransitionTaken = true;
takeTransition(transition);
}
}
}
// if there were no outgoing transitions or none of them could be taken,
if (!isTransitionTaken) {
// propagate the execution flow upwards to the parent
propagateToParent();
}
}
public void endAndPropagateToParent() {
end();
propagateToParent();
}
public void end() {
if (end==null) {
if (hasOpenActivityInstances()) {
throw new RuntimeException("Can't end this activity instance. There are open activity instances: " +this);
}
setEnd(Time.now());
workflow.workflowEngine.notifyActivityInstanceEnded(this);
destroyScopeInstance();
setWorkState(null);
}
}
public void propagateToParent() {
setWorkState(STATE_PROPAGATE_TO_PARENT);
workflowInstance.addWork(this);
}
public void setWorkState(String workState) {
// log.debug("Setting workstate of "+this+" from "+this.workState+" to "+workState);
this.workState = workState;
if (updates!=null) {
getUpdates().isWorkStateChanged = true;
if (parent!=null) {
parent.propagateActivityInstanceChange();
}
}
}
public void setJoining() {
setWorkState(STATE_JOINING);
}
public boolean isJoining() {
return STATE_JOINING.equals(workState);
}
public void removeJoining(ActivityInstanceImpl activityInstance) {
activityInstance.setWorkState(null);
}
/** Starts the to (destination) activity in the current (parent) scope.
* This methods will also end the current activity instance.
* This method can be called multiple times in one start() */
public void takeTransition(TransitionImpl transition) {
if (transition.id!=null || activity.activityType.saveTransitionsTaken()) {
addTransitionTaken(transition.id);
}
ActivityInstanceImpl toActivityInstance = null;
ActivityImpl to = transition.to;
if (to!=null) {
end();
if (log.isDebugEnabled()) {
log.debug("Taking transition to "+to);
}
toActivityInstance = parent.createActivityInstance(to);
} else {
log.debug("Dangling transition. Propagating to parent.");
end();
propagateToParent();
}
workflow.workflowEngine.notifyTransitionTaken(this, transition, toActivityInstance);
}
protected void addTransitionTaken(String transitionId) {
if (transitionsTaken==null) {
transitionsTaken = new ArrayList<>();
}
transitionsTaken.add(transitionId);
if (updates!=null) {
getUpdates().isTransitionsTakenChanged = true;
if (parent!=null) {
parent.propagateActivityInstanceChange();
}
}
}
@Override
public ActivityInstanceImpl findActivityInstance(String activityInstanceId) {
if (activityInstanceId == null) {
return null;
}
if (activityInstanceId.equals(this.id)) {
return this;
}
return super.findActivityInstance(activityInstanceId);
}
public ActivityImpl getActivity() {
return activity;
}
public void setActivity(ActivityImpl activityDefinition) {
this.activity = activityDefinition;
}
public String toString() {
String activityTypeName = activity.activityType.getActivityApiClass().getSimpleName();
String activityId = activity.id;
String activityName = activity.activity.getName();
return "("+activityTypeName+"|"+(activityName!=null?activityName+"|":"")+(activityId!=null?activityId+"|":"")+id+")";
}
public void setEnd(LocalDateTime end) {
this.end = end;
if (start!=null && end!=null) {
this.duration = end.toDate().getTime()-start.toDate().getTime();
}
if (updates!=null) {
updates.isEndChanged = true;
if (parent!=null) {
parent.propagateActivityInstanceChange();
}
}
}
@Override
public ActivityInstanceImpl findActivityInstanceByActivityId(String activityDefinitionId) {
if (activityDefinitionId==null) {
return null;
}
if (activityDefinitionId.equals(activity.id)) {
return this;
}
return super.findActivityInstanceByActivityId(activityDefinitionId);
}
@Override
public boolean isWorkflowInstance() {
return false;
}
public void setCalledWorkflowInstanceId(WorkflowInstanceId calledWorkflowInstanceId) {
this.calledWorkflowInstanceId = calledWorkflowInstanceId;
}
public WorkflowInstanceId getCalledWorkflowInstanceId() {
return calledWorkflowInstanceId;
}
@Override
public ActivityInstanceUpdates getUpdates() {
return (ActivityInstanceUpdates) updates;
}
public void trackUpdates(boolean isNew) {
if (updates==null) {
updates = new ActivityInstanceUpdates(isNew);
} else {
updates.reset(isNew);
}
super.trackUpdates(isNew);
}
public boolean hasActivityInstance(String activityInstanceId) {
if (id!=null && id.equals(activityInstanceId)) {
return true;
}
return super.hasActivityInstance(activityInstanceId);
}
public String getId() {
return id;
}
// TODO add the expected type for conversion?
public T getInputValue(String key) {
if (activity==null || activity.activityType==null || activity.activityType.getInputs()==null) {
return null;
}
InputParameterImpl parameter = (InputParameterImpl) activity.activityType.getInputs().get(key);
TypedValueImpl typedValue = getInputTypedValue(parameter);
return (T) (typedValue!=null ? typedValue.value : null);
}
protected TypedValueImpl getInputTypedValue(InputParameterImpl parameter) {
if (parameter!=null) {
if (parameter.binding != null) {
return getTypedValue(parameter.binding);
}
if (parameter.bindings != null) {
DataTypeImpl> listType = null;
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy