
com.effektif.workflow.impl.workflowinstance.ScopeInstanceImpl 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 com.effektif.workflow.api.Configuration;
import com.effektif.workflow.api.WorkflowEngine;
import com.effektif.workflow.api.model.DataContainer;
import com.effektif.workflow.api.model.TypedValue;
import com.effektif.workflow.api.model.VariableValues;
import com.effektif.workflow.api.types.ListType;
import com.effektif.workflow.api.workflowinstance.ActivityInstance;
import com.effektif.workflow.api.workflowinstance.ScopeInstance;
import com.effektif.workflow.api.workflowinstance.VariableInstance;
import com.effektif.workflow.impl.data.DataTypeImpl;
import com.effektif.workflow.impl.data.DataTypeService;
import com.effektif.workflow.impl.data.TypedValueImpl;
import com.effektif.workflow.impl.data.types.ListTypeImpl;
import com.effektif.workflow.impl.job.Job;
import com.effektif.workflow.impl.util.Time;
import com.effektif.workflow.impl.workflow.*;
import org.joda.time.LocalDateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import static com.effektif.workflow.impl.workflowinstance.ActivityInstanceImpl.STATE_STARTING;
import static com.effektif.workflow.impl.workflowinstance.ActivityInstanceImpl.STATE_STARTING_MULTI_CONTAINER;
public abstract class ScopeInstanceImpl extends BaseInstanceImpl {
public static final Logger log = LoggerFactory.getLogger(WorkflowEngine.class);
public ScopeImpl scope;
public LocalDateTime start;
public LocalDateTime end;
public Long duration;
public List activityInstances;
public List variableInstances;
/** maps variable.id's to variable instances */
public Map variableInstancesMap;
public String endState;
// As long as the workflow instance is not saved, the updates collection is null.
// That means it's not yet necessary to collect the updates.
public ScopeInstanceUpdates updates;
public ScopeInstanceImpl() {
}
public ScopeInstanceImpl(ScopeInstanceImpl parent, ScopeImpl scope) {
super(parent);
this.scope = scope;
this.start = Time.now();
}
public abstract void setEnd(LocalDateTime end);
public abstract boolean isWorkflowInstance();
protected void toScopeInstance(ScopeInstance scopeInstance, boolean includeWorkState) {
scopeInstance.setStart(start);
scopeInstance.setEnd(end);
scopeInstance.setEndState(endState);
scopeInstance.setDuration(duration);
if (activityInstances!=null && !activityInstances.isEmpty()) {
List activityInstanceApis = new ArrayList<>();
for (ActivityInstanceImpl activityInstanceImpl: this.activityInstances) {
activityInstanceApis.add(activityInstanceImpl.toActivityInstance(includeWorkState));
}
scopeInstance.setActivityInstances(activityInstanceApis);
}
if (variableInstances!=null && !variableInstances.isEmpty()) {
List variableInstanceApis = new ArrayList<>();
for (VariableInstanceImpl variableInstanceImpl: this.variableInstances) {
variableInstanceApis.add(variableInstanceImpl.toVariableInstance());
}
scopeInstance.setVariableInstances(variableInstanceApis);
}
scopeInstance.setProperties(this.properties);
}
public void execute(ActivityImpl activity) {
createActivityInstance(activity);
}
public ActivityInstanceImpl createActivityInstance(ActivityImpl activity) {
String activityInstanceId = workflowInstance.generateNextActivityInstanceId();
ActivityInstanceImpl activityInstance = new ActivityInstanceImpl(this, activity, activityInstanceId);
if (activity.isMultiInstance()) {
activityInstance.setWorkState(STATE_STARTING_MULTI_CONTAINER);
} else {
activityInstance.setWorkState(STATE_STARTING);
}
workflowInstance.addWork(activityInstance);
activityInstance.start = Time.now();
if (updates!=null) {
activityInstance.updates = new ActivityInstanceUpdates(true);
if (parent!=null) {
parent.propagateActivityInstanceChange();
}
}
addActivityInstance(activityInstance);
activityInstance.initializeScopeInstance();
// if (log.isDebugEnabled())
// log.debug("Created "+activityInstance);
return activityInstance;
}
public void initializeScopeInstance() {
initializeVariableInstances();
initializeTimers();
}
/** TODO find where this needs to be called
* i expect it should be called from end() */
public void destroyScopeInstance() {
removeTimerInstanceJobs();
}
public void initializeForEachElement(VariableImpl elementVariableDefinition, Object value) {
VariableInstanceImpl elementVariableInstance = createVariableInstanceLocal(elementVariableDefinition);
elementVariableInstance.setValue(value);
}
public void addActivityInstance(ActivityInstanceImpl activityInstance) {
if (activityInstances==null) {
activityInstances = new ArrayList<>();
}
activityInstance.parent = this;
activityInstances.add(activityInstance);
}
public void initializeVariableInstances() {
if (scope.variables!=null && !scope.variables.isEmpty()) {
for (VariableImpl variable: scope.variables.values()) {
createVariableInstanceLocal(variable);
}
}
}
public VariableInstanceImpl createVariableInstanceLocal(VariableImpl variable) {
String variableInstanceId = workflowInstance.generateNextVariableInstanceId();
VariableInstanceImpl variableInstance = new VariableInstanceImpl(this, variable, variableInstanceId);
variableInstance.configuration = configuration;
variableInstance.workflowInstance = workflowInstance;
variableInstance.type = variable.type;
variableInstance.setValue(variable.defaultValue);
variableInstance.variable = variable;
if (updates!=null) {
variableInstance.updates = new VariableInstanceUpdates(true);
updates.isVariableInstancesChanged = true;
if (parent!=null) {
parent.propagateActivityInstanceChange();
}
}
addVariableInstance(variableInstance);
return variableInstance;
}
public VariableInstanceImpl createVariableInstanceLocal(String variableId, DataTypeImpl dataType) {
VariableImpl variable = new VariableImpl();
variable.id = variableId;
variable.type = dataType;
return createVariableInstanceLocal(variable);
}
public void addVariableInstance(VariableInstanceImpl variableInstance) {
variableInstance.parent = this;
if (variableInstances==null) {
variableInstances = new ArrayList<>();
variableInstancesMap = new HashMap<>();
}
variableInstances.add(variableInstance);
variableInstancesMap.put(variableInstance.variable.id, variableInstance);
}
/** to be used by activity implementations */
public T getValue(BindingImpl binding) {
if (binding==null) {
return null;
}
if (binding.value!=null) {
return binding.value;
}
if (binding.expression!=null) {
return (T) getValue(binding.expression);
}
if (binding.template!=null) {
return (T) binding.template.resolve(this);
}
return null;
}
public Object getValue(ExpressionImpl expression) {
VariableInstanceImpl variableInstance = getVariableInstance(expression);
if (variableInstance==null) {
return null;
}
if (expression.fieldKeys==null) {
return variableInstance.getValue();
}
TypedValueImpl typedValue = getTypedValueField(variableInstance, expression.fieldKeys);
return typedValue!=null ? typedValue.value : null;
}
protected VariableInstanceImpl getVariableInstance(ExpressionImpl expression) {
if (expression==null || expression.variableId==null) {
return null;
}
return findVariableInstance(expression.variableId);
}
/** to be used by activity implementations */
public List getValues(List> bindings) {
if (bindings==null) {
return null;
}
List values = new ArrayList<>();
for (BindingImpl binding: bindings) {
T value = getValue(binding);
if (value!=null) {
if (value instanceof Collection) {
values.addAll((Collection)value);
} else {
values.add(value);
}
}
}
return values;
}
public TypedValueImpl getTypedValue(BindingImpl binding) {
if (binding==null) {
return null;
}
if (binding.value!=null) {
return new TypedValueImpl(binding.type, binding.value);
}
if (binding.expression!=null) {
return getTypedValue(binding.expression);
}
return null;
}
public TypedValueImpl getTypedValue(ExpressionImpl expression) {
VariableInstanceImpl variableInstance = getVariableInstance(expression);
if (variableInstance == null) {
return null;
}
if (expression.fieldKeys==null) {
return variableInstance.getTypedValue();
}
return getTypedValueField(variableInstance, expression.fieldKeys);
}
protected TypedValueImpl getTypedValueField(VariableInstanceImpl variableInstance, List fields) {
return resolveFields(variableInstance.type, variableInstance.getValue(), fields, configuration);
}
public static TypedValueImpl resolveFields(DataTypeImpl> type, Object value, List fields, Configuration configuration) {
TypedValueImpl typedValue = new TypedValueImpl(type, value);
if (fields!=null) {
for (int i=0; i data = variableValues!=null ? variableValues.getData() : null;
if (data!=null) {
for (String variableId: data.keySet()) {
TypedValue value = data.get(variableId);
setVariableValue(variableId, value.getValue());
}
}
}
public void setVariableValue(String variableId, Object value) {
if (variableInstances!=null) {
VariableInstanceImpl variableInstance = getVariableInstanceLocal(variableId);
if (variableInstance!=null) {
setVariableValue(variableInstance, value);
return;
}
}
if (parent!=null) {
parent.setVariableValue(variableId, value);
return;
}
DataTypeService dataTypeService = configuration.get(DataTypeService.class);
Class> valueClass = value!=null ? value.getClass() : null;
DataTypeImpl dataType = dataTypeService.getDataTypeByValue(valueClass);
if (dataType==null) {
throw new RuntimeException("Couldn't determine data type dynamically for value "+value);
}
VariableInstanceImpl variableInstance = createVariableInstanceLocal(variableId, dataType);
setVariableValue(variableInstance, value);
}
public void setVariableValue(VariableInstanceImpl variableInstance, Object value) {
log.debug("Updating variable '"+variableInstance.variable.id+"' to '"+value+"'");
variableInstance.setValue(value);
if (updates!=null) {
updates.isVariableInstancesChanged = true;
if (parent!=null) {
parent.propagateActivityInstanceChange();
}
}
}
public VariableInstanceImpl findVariableInstance(String variableId) {
if (variableInstances!=null) {
VariableInstanceImpl variableInstance = getVariableInstanceLocal(variableId);
if (variableInstance!=null) {
return variableInstance;
}
}
if (parent!=null) {
return parent.findVariableInstance(variableId);
}
return null;
}
/**
* Returns the description of the variable specified by the given binding expression.
*/
public VariableImpl findVariable(BindingImpl binding) {
if (binding == null || binding.expression == null) {
return null;
}
VariableInstanceImpl variableInstance = getVariableInstance(binding.expression);
if (variableInstance == null || variableInstance.getVariable() == null) {
return null;
}
return variableInstance.getVariable();
}
protected VariableInstanceImpl getVariableInstanceLocal(String variableId) {
return variableInstancesMap.get(variableId);
}
public void updateVariableInstancesMap() {
if (variableInstances!=null) {
variableInstancesMap = new HashMap<>();
for (VariableInstanceImpl variableInstance: variableInstances) {
variableInstancesMap.put(variableInstance.variable.id, variableInstance);
}
} else {
variableInstancesMap = null;
}
}
public abstract void endAndPropagateToParent();
public boolean hasOpenActivityInstances() {
if (activityInstances==null) {
return false;
}
for (ActivityInstanceImpl activityInstance: activityInstances) {
if (!activityInstance.isEnded()) {
return true;
}
}
return false;
}
/** scans this activity and the nested activities */
public ActivityInstanceImpl findActivityInstance(String activityInstanceId) {
if (activityInstances!=null) {
for (ActivityInstanceImpl activityInstance: activityInstances) {
ActivityInstanceImpl theOne = activityInstance.findActivityInstance(activityInstanceId);
if (theOne!=null) {
return theOne;
}
}
}
return null;
}
public ActivityInstanceImpl findActivityInstanceByActivityId(String activityDefinitionId) {
if (activityDefinitionId==null) {
return null;
}
if (activityInstances!=null) {
for (ActivityInstanceImpl activityInstance: activityInstances) {
ActivityInstanceImpl theOne = activityInstance.findActivityInstanceByActivityId(activityDefinitionId);
if (theOne!=null) {
return theOne;
}
}
}
return null;
}
// timer instances ///
protected void initializeTimers() {
if (scope.timers!=null) {
for (TimerImpl timer: scope.timers) {
Job job = timer.createJob(this);
job.workflowInstanceId(workflowInstance.getId());
job.activityInstanceId(getActivityInstanceId());
workflowInstance.addJob(job);
// workflow.configuration
// .get(JobStore.class)
// .saveJob(job);
}
}
}
/** the activity instance id if this is an activity instance and
* null if this is a workflow instance.
* This method is overridden by the ActivityInstanceImpl to set the activity instance id */
protected String getActivityInstanceId() {
return null;
}
/** removes the jobs from the workflow instance associated to this particular scope instance */
public void removeTimerInstanceJobs() {
if (workflowInstance != null
&& workflowInstance.jobs != null) {
for (Job job: workflowInstance.jobs) {
boolean isActivityInstanceJob = getActivityInstanceId()==null && job.getActivityInstanceId()==null;
boolean isWorkflowInstanceJob = getActivityInstanceId()!=null && getActivityInstanceId().equals(job.getActivityInstanceId());
if (isActivityInstanceJob || isWorkflowInstanceJob) {
log.debug("Removing job: " + job);
workflowInstance.removeJob(job);
}
}
}
}
// updates ////////////////////////////////////////////////////////////
public boolean hasUpdates() {
// As long as the workflow instance is not saved, the updates collection is null.
// That means it's not yet necessary to collect the updates.
return updates!=null;
}
public ScopeInstanceUpdates getUpdates() {
return updates;
}
public void trackUpdates(boolean isNew) {
if (activityInstances!=null) {
for (ActivityInstanceImpl activityInstance: activityInstances) {
activityInstance.trackUpdates(isNew);
}
}
if (variableInstances!=null) {
for (VariableInstanceImpl variableInstance: variableInstances) {
variableInstance.trackUpdates(isNew);
}
}
}
public void propagateActivityInstanceChange() {
if (updates!=null) {
updates.isActivityInstancesChanged = true;
if (parent != null) {
parent.propagateActivityInstanceChange();
}
}
}
public boolean hasActivityInstances() {
return activityInstances!=null && !activityInstances.isEmpty();
}
public boolean isEnded() {
return end!=null;
}
public boolean hasActivityInstance(String activityInstanceId) {
if (hasActivityInstances()) {
for (ActivityInstanceImpl activityInstance : activityInstances) {
if (activityInstance.hasActivityInstance(activityInstanceId)) {
return true;
}
}
}
return false;
}
public void activityInstanceEnded(ActivityInstanceImpl endedActivityInstance) {
if (!hasOpenActivityInstances()) {
// We also check if there are still joining activities.
// If so, they need to be fired.
// We ensure that we fire each activity max once,
// even if there could be multiple joining activity instances in the activity
List joiningActivityInstances = null;
if (activityInstances!=null) {
for (ActivityInstanceImpl activityInstance: activityInstances) {
if (activityInstance.isJoining()) {
if (joiningActivityInstances==null) {
joiningActivityInstances = new ArrayList<>();
}
joiningActivityInstances.add(activityInstance);
}
}
}
if (joiningActivityInstances!=null && !joiningActivityInstances.isEmpty()) {
Set onwardedActivities = new HashSet<>();
for (ActivityInstanceImpl joiningActivityInstance: joiningActivityInstances) {
if (!onwardedActivities.contains(joiningActivityInstance.activity)) {
onwardedActivities.add(joiningActivityInstance.activity);
joiningActivityInstance.setWorkState(null);
joiningActivityInstance.onwards();
}
}
} else {
onwards();
}
}
}
public void onwards() {
endAndPropagateToParent();
}
public void cancel() {
if (this.end==null) {
this.setEnd(Time.now());
this.endState = ScopeInstance.ENDSTATE_CANCELED;
if (activityInstances!=null) {
for (ActivityInstanceImpl activityInstance: activityInstances) {
activityInstance.cancel();
}
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy