/*
* 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.activity.types;
import com.effektif.workflow.api.Configuration;
import com.effektif.workflow.api.WorkflowEngine;
import com.effektif.workflow.api.activities.SubProcess;
import com.effektif.workflow.api.model.Message;
import com.effektif.workflow.api.model.TriggerInstance;
import com.effektif.workflow.api.model.WorkflowId;
import com.effektif.workflow.api.query.OrderDirection;
import com.effektif.workflow.api.query.WorkflowQuery;
import com.effektif.workflow.api.workflow.Binding;
import com.effektif.workflow.api.workflow.ExecutableWorkflow;
import com.effektif.workflow.api.workflow.Variable;
import com.effektif.workflow.impl.WorkflowEngineImpl;
import com.effektif.workflow.impl.WorkflowParser;
import com.effektif.workflow.impl.WorkflowStore;
import com.effektif.workflow.impl.data.TypedValueImpl;
import com.effektif.workflow.impl.workflow.ActivityImpl;
import com.effektif.workflow.impl.workflow.BindingImpl;
import com.effektif.workflow.impl.workflowinstance.ActivityInstanceImpl;
import com.effektif.workflow.impl.workflowinstance.WorkflowInstanceImpl;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Tom Baeyens
*/
public class SubProcessImpl extends AbstractBindableActivityImpl<SubProcess> {
// IDEA Boolean waitTillSubWorkflowEnds; add a configuration property to specify if this is fire-and-forget or wait-till-subworkflow-ends
protected WorkflowId subWorkflowId;
protected String subWorkflowSourceId;
public SubProcessImpl() {
super(SubProcess.class);
}
public SubProcessImpl(Class<SubProcess> activityApiClass) {
super(activityApiClass);
}
@Override
public void parse(ActivityImpl activityImpl, SubProcess subProcess, WorkflowParser parser) {
super.parse(activityImpl, subProcess, parser);
this.subWorkflowId = subProcess.getSubWorkflowId();
this.subWorkflowSourceId = subProcess.getSubWorkflowSourceId();
WorkflowQuery workflowQuery = null;
if (subWorkflowId!=null) {
workflowQuery = new WorkflowQuery().workflowId(subWorkflowId);
} else if (subWorkflowSourceId !=null) {
workflowQuery = new WorkflowQuery().workflowSource(subWorkflowSourceId)
.orderByCreateTime(OrderDirection.desc).limit(1);
}
ExecutableWorkflow subWorkflow = null;
if (workflowQuery!=null) {
WorkflowEngine workflowEngine = parser.configuration.getWorkflowEngine();
List<ExecutableWorkflow> workflows = workflowEngine.findWorkflows(workflowQuery);
if (workflows!=null && !workflows.isEmpty()) {
subWorkflow = workflows.get(0);
}
}
if (subWorkflow != null) {
if (subWorkflowId == null) {
subWorkflowId = subWorkflow.getId();
}
if (subWorkflowSourceId == null) {
subWorkflowSourceId = subWorkflow.getSourceWorkflowId();
}
List<Variable> subWorkflowVariables = subWorkflow.getVariables();
Map<String, Binding> inputBindingsApi = subProcess.getSubWorkflowInputs();
if (subWorkflowVariables != null && inputBindingsApi != null) {
for (Variable subWorkflowVariable : subWorkflowVariables) {
String subWorkflowVariableId = subWorkflowVariable.getId();
Binding inputBindingApi = inputBindingsApi.get(subWorkflowVariableId);
parser.pushContext("inputBindings[" + subWorkflowVariableId + "]", inputBindingApi, null, null);
BindingImpl<?> bindingImpl = parser
.parseBinding(inputBindingApi, subWorkflowVariableId, false, subWorkflowVariable.getType());
if (bindingImpl != null) {
if (inputBindings == null) {
inputBindings = new HashMap<>();
}
inputBindings.put(subWorkflowVariableId, bindingImpl);
}
parser.popContext();
}
}
}
}
@Override
public void execute(ActivityInstanceImpl activityInstance) {
Configuration configuration = activityInstance.getConfiguration();
WorkflowId actualSubWorkflowId = null;
if (this.subWorkflowId != null) {
actualSubWorkflowId = this.subWorkflowId;
}
else if (subWorkflowSourceId != null) {
WorkflowStore workflowStore = configuration.get(WorkflowStore.class);
actualSubWorkflowId = workflowStore.findLatestWorkflowIdBySource(subWorkflowSourceId);
}
if (actualSubWorkflowId != null) {
TriggerInstance triggerInstance = new TriggerInstance()
.sourceWorkflowId(subWorkflowSourceId)
.workflowId(actualSubWorkflowId);
triggerInstance.setCallingWorkflowInstanceId(activityInstance.workflowInstance.id);
triggerInstance.setCallingActivityInstanceId(activityInstance.id);
if (inputBindings != null) {
for (String subWorkflowVariableId: inputBindings.keySet()) {
BindingImpl<?> subWorkflowBinding = inputBindings.get(subWorkflowVariableId);
Object value = activityInstance.getValue(subWorkflowBinding);
triggerInstance.data(subWorkflowVariableId, value);
}
}
startWorkflowInstance(activityInstance, triggerInstance);
} else {
reportError(activityInstance, "Cannot execute sub-process action because no sub-process was configured.");
activityInstance.onwards();
}
}
/**
* Starts the subworkflow instance.
*/
protected void startWorkflowInstance(ActivityInstanceImpl activityInstance, TriggerInstance triggerInstance) {
Configuration configuration = activityInstance.getConfiguration();
WorkflowEngineImpl workflowEngine = configuration.get(WorkflowEngineImpl.class);
WorkflowInstanceImpl calledWorkflowInstance = workflowEngine.startInitialize(triggerInstance);
calledWorkflowInstance.addLockedWorkflowInstance(activityInstance.workflowInstance);
activityInstance.setCalledWorkflowInstanceId(calledWorkflowInstance.getId());
workflowEngine.startExecute(calledWorkflowInstance);
}
public void calledWorkflowInstanceEnded(final ActivityInstanceImpl callingActivityInstance, WorkflowInstanceImpl calledWorkflowInstance) {
mapOutputVariables(callingActivityInstance, calledWorkflowInstance);
calledWorkflowInstance.workflow.getWorkflowEngine()
.send(new Message()
.workflowInstanceId(callingActivityInstance.workflowInstance.getId())
.activityInstanceId(callingActivityInstance.getId()),
callingActivityInstance.workflowInstance);
}
protected void mapOutputVariables(ActivityInstanceImpl callerActivityInstance, WorkflowInstanceImpl calledProcessInstance) {
if (outputBindings!=null) {
for (String subWorkflowVariableId: outputBindings.keySet()) {
String variableId = outputBindings.get(subWorkflowVariableId);
TypedValueImpl typedValue = calledProcessInstance.getTypedValue(subWorkflowVariableId);
callerActivityInstance.setVariableValue(variableId, typedValue);
}
}
}
protected void reportError(ActivityInstanceImpl activityInstance, String message) {
log.warn(message);
}
}