/**
* Copyright 2010 JBoss Inc
*
* 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.drools.osworkflow.instance;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.drools.definition.process.Node;
import org.drools.osworkflow.core.OSWorkflowProcess;
import org.drools.osworkflow.instance.node.StepNodeInstance;
import org.drools.process.core.context.variable.VariableScope;
import org.drools.process.instance.ProcessInstance;
import org.drools.process.instance.context.variable.VariableScopeInstance;
import org.drools.workflow.instance.NodeInstance;
import org.drools.workflow.instance.impl.WorkflowProcessInstanceImpl;
import com.opensymphony.module.propertyset.PropertySet;
import com.opensymphony.module.propertyset.map.MapPropertySet;
import com.opensymphony.workflow.Condition;
import com.opensymphony.workflow.FunctionProvider;
import com.opensymphony.workflow.StoreException;
import com.opensymphony.workflow.TypeResolver;
import com.opensymphony.workflow.WorkflowContext;
import com.opensymphony.workflow.WorkflowException;
import com.opensymphony.workflow.loader.AbstractDescriptor;
import com.opensymphony.workflow.loader.ActionDescriptor;
import com.opensymphony.workflow.loader.ConditionDescriptor;
import com.opensymphony.workflow.loader.ConditionalResultDescriptor;
import com.opensymphony.workflow.loader.ConditionsDescriptor;
import com.opensymphony.workflow.loader.FunctionDescriptor;
import com.opensymphony.workflow.loader.ResultDescriptor;
import com.opensymphony.workflow.query.WorkflowExpressionQuery;
import com.opensymphony.workflow.query.WorkflowQuery;
import com.opensymphony.workflow.spi.Step;
import com.opensymphony.workflow.spi.WorkflowEntry;
import com.opensymphony.workflow.spi.WorkflowStore;
public class OSWorkflowProcessInstance extends WorkflowProcessInstanceImpl implements WorkflowEntry {
private static final long serialVersionUID = 510l;
private List<Step> history = new ArrayList<Step>();
public OSWorkflowProcess getOSWorkflowProcess() {
return (OSWorkflowProcess) getProcess();
}
protected void internalStart() {
Map<String, Object> transientVars = new HashMap<String, Object>();
for (ActionDescriptor action: getOSWorkflowProcess().getInitialActions()) {
// if (action.getAutoExecute()) {
executeAction(action, 0, transientVars);
// }
}
}
public void doInitialAction(int actionId, Map inputs) {
Map<String, Object> transientVars = new HashMap<String, Object>();
transientVars.put("context", new DummyWorkflowContext());
ActionDescriptor initialAction = getOSWorkflowProcess().getInitialAction(actionId);
if (initialAction == null) {
throw new IllegalArgumentException(
"Unknown initial action id " + actionId);
}
executeAction(initialAction, 0, transientVars);
}
public void doAction(int actionId, Map inputs) {
for (org.drools.runtime.process.NodeInstance nodeInstance: getNodeInstances()) {
StepNodeInstance stepNodeInstance = (StepNodeInstance) nodeInstance;
if (stepNodeInstance.isAvailableAction(actionId)) {
stepNodeInstance.doAction(actionId, inputs);
break;
}
}
checkImplicitFinish();
}
protected void executeAction(ActionDescriptor action, int currentStepId, Map<String, Object> transientVars) {
List<FunctionDescriptor> preFunctions = action.getPreFunctions();
if (preFunctions != null) {
for (FunctionDescriptor preFunction: preFunctions) {
executeFunction(preFunction, transientVars);
}
}
boolean executed = false;
List<ConditionalResultDescriptor> conditionalResults = action.getConditionalResults();
if (conditionalResults != null) {
for (ConditionalResultDescriptor conditionalResult: conditionalResults) {
if (passesConditions(null, conditionalResult.getConditions(), currentStepId)) {
executeResult(conditionalResult, transientVars);
}
}
}
if (!executed) {
executeResult(action.getUnconditionalResult(), transientVars);
}
List<FunctionDescriptor> postFunctions = action.getPostFunctions();
if (postFunctions != null) {
for (FunctionDescriptor postFunction: postFunctions) {
executeFunction(postFunction, transientVars);
}
}
if (action.isFinish()) {
setState(ProcessInstance.STATE_COMPLETED);
}
}
protected void executeResult(ResultDescriptor result, Map<String, Object> transientVars) {
List<FunctionDescriptor> preFunctions = result.getPreFunctions();
if (preFunctions != null) {
for (FunctionDescriptor preFunction: preFunctions) {
executeFunction(preFunction, transientVars);
}
}
int nodeId = 0;
String type = null;
if (result.getSplit() != 0) {
nodeId = result.getSplit();
type = org.drools.workflow.core.Node.CONNECTION_DEFAULT_TYPE;
} else if (result.getJoin() != 0) {
nodeId = result.getJoin();
type = org.drools.workflow.core.Node.CONNECTION_DEFAULT_TYPE;
} else {
nodeId = result.getStep();
type = result.getStatus();
}
Node node = getNodeContainer().getNode(nodeId);
if (node == null) {
throw new IllegalArgumentException(
"Unknown node id " + nodeId);
}
NodeInstance nodeInstance = getNodeInstance(node);
if (result.getOwner() != null && nodeInstance instanceof StepNodeInstance) {
((StepNodeInstance) nodeInstance).setOwner(result.getOwner());
}
nodeInstance.trigger(null, type);
List<FunctionDescriptor> postFunctions = result.getPostFunctions();
if (postFunctions != null) {
for (FunctionDescriptor postFunction: postFunctions) {
executeFunction(postFunction, transientVars);
}
}
}
public void executeFunction(FunctionDescriptor function, Map<String, Object> transientVars) {
Map<String, Object> params = createParams(function.getArgs());
try {
FunctionProvider provider = TypeResolver.getResolver().getFunction(function.getType(), params);
if (provider == null) {
throw new WorkflowException("Could not load FunctionProvider class");
}
MapPropertySet ps = new MapPropertySet();
ps.setMap(new HashMap());
provider.execute(transientVars, params, ps);
} catch (WorkflowException e) {
throw new RuntimeException("WorkflowException when executing function", e);
}
}
protected boolean passesCondition(ConditionDescriptor conditionDesc, int currentStepId) {
try {
String type = conditionDesc.getType();
Map<String, Object> params = createParams(conditionDesc.getArgs());
if (currentStepId != -1) {
Object stepId = params.get("stepId");
if ((stepId != null) && stepId.equals("-1")) {
params.put("stepId", String.valueOf(currentStepId));
}
}
Condition condition = TypeResolver.getResolver().getCondition(type, params);
if (condition == null) {
throw new WorkflowException("Could not load condition");
}
try {
Map<String, Object> transientVars = new HashMap<String, Object>();
transientVars.put("entry", this);
transientVars.put("context", new DummyWorkflowContext());
transientVars.put("store", new DummyWorkflowStore());
PropertySet ps = new MapPropertySet();
boolean passed = condition.passesCondition(transientVars, params, ps);
if (conditionDesc.isNegate()) {
passed = !passed;
}
return passed;
} catch (Exception e) {
if (e instanceof WorkflowException) {
throw (WorkflowException) e;
}
throw new WorkflowException("Unknown exception encountered when checking condition " + condition, e);
}
} catch (WorkflowException e) {
throw new RuntimeException("WorkflowException when checking conditions", e);
}
}
public boolean passesConditions(String conditionType, List<AbstractDescriptor> conditions, int currentStepId) {
if ((conditions == null) || (conditions.size() == 0)) {
return true;
}
boolean and = "AND".equals(conditionType);
boolean or = !and;
for (AbstractDescriptor descriptor: conditions) {
boolean result;
if (descriptor instanceof ConditionsDescriptor) {
ConditionsDescriptor conditionsDescriptor = (ConditionsDescriptor) descriptor;
result = passesConditions(conditionsDescriptor.getType(), conditionsDescriptor.getConditions(), currentStepId);
} else {
result = passesCondition((ConditionDescriptor) descriptor, currentStepId);
}
if (and && !result) {
return false;
} else if (or && result) {
return true;
}
}
if (and) {
return true;
} else if (or) {
return false;
} else {
return false;
}
}
protected Map<String, Object> createParams(Map<String, Object> params) {
Map<String, Object> result = new HashMap<String, Object>(params);
for (String paramName : result.keySet()) {
VariableScopeInstance variableScopeInstance = (VariableScopeInstance)
getContextInstance(VariableScope.VARIABLE_SCOPE);
Object value = variableScopeInstance.getVariable(paramName);
if (value != null) {
result.put(paramName, value);
}
}
return result;
}
public List<Step> getCurrentSteps() {
List<Step> result = new ArrayList<Step>();
for (org.drools.runtime.process.NodeInstance nodeInstance: getNodeInstances()) {
if (nodeInstance instanceof StepNodeInstance) {
result.add((StepNodeInstance) nodeInstance);
}
}
return result;
}
public void removeNodeInstance(final NodeInstance nodeInstance) {
super.removeNodeInstance(nodeInstance);
if (nodeInstance instanceof StepNodeInstance) {
history.add(0, (StepNodeInstance) nodeInstance);
}
}
private void checkImplicitFinish() {
boolean finished = true;
for (org.drools.runtime.process.NodeInstance nodeInstance: getNodeInstances()) {
if (nodeInstance instanceof StepNodeInstance) {
if (!((StepNodeInstance) nodeInstance).getAvailableActions().isEmpty()) {
finished = false;
break;
}
}
}
if (finished) {
setState(ProcessInstance.STATE_COMPLETED);
}
}
public List<Step> getHistorySteps() {
return history;
}
public String getWorkflowName() {
return getProcess().getName();
}
public boolean isInitialized() {
return true;
}
public class DummyWorkflowStore implements WorkflowStore {
public Step createCurrentStep(long entryId, int stepId, String owner,
Date startDate, Date dueDate, String status, long[] previousIds)
throws StoreException {
// TODO Auto-generated method stub
return null;
}
public WorkflowEntry createEntry(String workflowName)
throws StoreException {
// TODO Auto-generated method stub
return null;
}
public List findCurrentSteps(long entryId) throws StoreException {
if (entryId == getId()) {
return getCurrentSteps();
}
return null;
}
public WorkflowEntry findEntry(long entryId) throws StoreException {
// TODO Auto-generated method stub
return null;
}
public List findHistorySteps(long entryId) throws StoreException {
// TODO Auto-generated method stub
return null;
}
public PropertySet getPropertySet(long entryId) throws StoreException {
// TODO Auto-generated method stub
return null;
}
public void init(Map props) throws StoreException {
// TODO Auto-generated method stub
}
public Step markFinished(Step step, int actionId, Date finishDate,
String status, String caller) throws StoreException {
// TODO Auto-generated method stub
return null;
}
public void moveToHistory(Step step) throws StoreException {
// TODO Auto-generated method stub
}
public List query(WorkflowQuery query) throws StoreException {
// TODO Auto-generated method stub
return null;
}
public List query(WorkflowExpressionQuery query) throws StoreException {
// TODO Auto-generated method stub
return null;
}
public void setEntryState(long entryId, int state)
throws StoreException {
// TODO Auto-generated method stub
}
}
public class DummyWorkflowContext implements WorkflowContext {
public String getCaller() {
// TODO
return "caller";
}
public void setRollbackOnly() {
// TODO
}
}
}