package org.basuyi.xflow.core;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.apache.log4j.Logger;
import org.basuyi.xflow.core.actions.SubflowAction;
import org.basuyi.xflow.core.actions.WorkflowAction;
import org.basuyi.xflow.core.actions.WorkflowCondition;
import org.basuyi.xflow.core.config.model.WfConfigAction;
import org.basuyi.xflow.core.config.model.WfConfigActivity;
import org.basuyi.xflow.core.config.model.WfConfigArgument;
import org.basuyi.xflow.core.config.model.WfConfigCondition;
import org.basuyi.xflow.core.config.model.WfConfigResult;
import org.basuyi.xflow.core.config.model.WfConfigSubflowActivity;
import org.basuyi.xflow.core.config.model.WfConfigUserActivity;
import org.basuyi.xflow.core.config.model.WfConfigUserPolicy;
import org.basuyi.xflow.core.config.model.Workflow;
import org.basuyi.xflow.core.config.model.WorkflowContext;
import org.basuyi.xflow.core.config.model.WorkflowDefination;
import org.basuyi.xflow.core.config.model.WorkflowException;
import org.basuyi.xflow.core.utils.StringUtils;
import org.basuyi.xflow.core.utils.beanshell.BeanShellAction;
import org.basuyi.xflow.core.utils.beanshell.BeanShellCondition;
/**
* ����������ӿ�
* @author mashuai
* @version 0.1
* @date 2009-10-19
*/
public abstract class AbstractWorkflowEngine implements WorflowEngine {
/*�����������Ķ���*/
protected WorkflowContext context = null;
/*����������*/
protected Workflow workflow = null;
/*�λ��ڶ���*/
protected WfConfigActivity nextActivity = null;
/*��������*/
protected Map<String, WfConfigActivity> wfConfigActivities = null;
/*���ö���*/
protected Properties properties = null;
/*��־����*/
private static final Logger log = Logger.getLogger(AbstractWorkflowEngine.class.getSimpleName());
public AbstractWorkflowEngine() {
/*��ʼ�����������������ļ�*/
initialize();
/*���û����������û��ӿڲ�������������ӻ����м��ع��������������Ķ���*/
loadWorkflowContext();
}
/**
* ȡ�õ�ǰ������������
*/
protected abstract void initWorkflowContext(String workflowId);
/**
* ��ʼ������ȡ�����ļ�
*/
private void initialize() {
properties = new Properties();
FileInputStream fis = null;
try {
URL url = Thread.currentThread().getContextClassLoader().getResource("msworkflow.properties");
String file = url.getFile();
fis = new FileInputStream(new File(file));
properties.load(fis);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
fis = null;
}
}
}
}
/**
* ���������淽��
*/
protected void execute() throws Exception {
try {
WfConfigActivity currentActivity = context.getCurrentActivity();
if (currentActivity == null) {
WfConfigActivity start_activity = getStartActivity();
context.setCurrentActivity(start_activity);
executeActivity(start_activity);
} else {
executeActivity(currentActivity);
/*�ж��Ƿ���ֹ*/
if (WorkflowStatus.TERMINAL == context.getEngineStatus()) {
return;
}
/*�ж��Ƿ����û���������*/
if (WorkflowStatus.SUSPEND == context.getEngineStatus()) {
/*���湤����״̬*/
cacheWorkflowContext();
/*ת�û��ӿڲ���*/
lanchUserInterface(context);
return;
}
}
/*�ݹ鴦����*/
execute();
} catch (Exception e) {
//e.printStackTrace();
throw e;
}
}
/**
* ȡ��ʼ������Ϣ
* @return
*/
private WfConfigActivity getStartActivity() {
for (WfConfigActivity activity : wfConfigActivities.values()) {
if (WorkflowDefination.START_ACTIVITY.equals(activity.getActivityType())) {
return activity;
}
}
return null;
}
/**
* �����û��ӿڲ���
* @param context
*/
protected abstract void lanchUserInterface(WorkflowContext context);
/**
* ���湤���������Ķ���
*/
protected abstract void cacheWorkflowContext();
/**
* �ָ������������Ķ���
*/
protected abstract void loadWorkflowContext();
/**
* ͨ�����ڱ�ʾȡ�û��ڶ���
* @param activityId
* @return
*/
private WfConfigActivity getActivityById(String activityId) {
WfConfigActivity nextActivity1 = wfConfigActivities.get(activityId);
return nextActivity1;
}
/**
* ִ�л���
* @param activityId
* @throws WorkflowException
*/
private void executeActivity(WfConfigActivity wfConfigActivity) throws WorkflowException {
try {
System.out.println(wfConfigActivity);
log.error("��ǰ���ڣ�" + context.getWorkflow().getWorkflowId() + "." + wfConfigActivity.getActivityId());
/*Ԥ����*/
beforeExecuteActivity(wfConfigActivity);
/*������ִ��ʵ��*/
if (WorkflowDefination.SUBFLOW_ACTIVITY.equals(wfConfigActivity.getActivityType())) {
executeSubflowActivity(wfConfigActivity);
} else if (WorkflowDefination.USER_ACTIVITY.equals(wfConfigActivity.getActivityType())) {
executeUserActivity(wfConfigActivity);
/*������״̬��Ϊ��������ͣ����*/
if (WorkflowStatus.SUSPEND == context.getEngineStatus()) {
return;
}
} else {
/*ִ�л���ʵ�嶯������*/
List<WfConfigAction> wfConfigActions = wfConfigActivity.getActions();
executeActions(wfConfigActions);
}
/*���ڽ������*/
Map<String, WfConfigResult> wfConfigResults = wfConfigActivity.getResults();
WfConfigResult wfConfigResult = executeResults(wfConfigResults);
/*���ں���*/
String nextActivityId = wfConfigResult.getActivityId();
nextActivity = getActivityById(nextActivityId);
context.setCurrentActivity(nextActivity);
if (nextActivity == null
&& WorkflowDefination.WORKFLOW_FINISH_ACTIVITY_ID.equals(nextActivityId)
&& WorkflowDefination.WORKFLOW_FINISH.equals(wfConfigResult.getStatus())) {
context.setEngineStatus(WorkflowStatus.TERMINAL);
}
// else {
// if (WorkflowDefination.USER_ACTIVITY.equals(nextActivity.getActivityType())) {
// context.setEngineStatus(WorkflowStatus.SUSPEND);
// }
// }
/*����*/
log.error("�������ڣ�" + context.getWorkflow().getWorkflowId() + "." + nextActivityId);
afterExecuteActivity(wfConfigActivity);
} catch (WorkflowException e) {
/*�쳣����*/
errorExecuteActivity(wfConfigActivity);
throw e;
} catch (Exception e) {
/*�쳣����*/
e.printStackTrace();
errorExecuteActivity(wfConfigActivity);
throw new WorkflowException();
}
}
/**
* �˹�������չ�������
* @param wfConfigActivity
*/
protected abstract void extendUserActivity(WfConfigActivity wfConfigActivity);
/**
* ִ�л����쳣�������
* @param wfConfigActivity
*/
protected abstract void errorExecuteActivity(WfConfigActivity wfConfigActivity);
/**
* ִ�л��ں������
* @param wfConfigActivity
*/
protected abstract void afterExecuteActivity(WfConfigActivity wfConfigActivity);
/**
* ִ�л���Ԥ�������
* @param wfConfigActivity
*/
protected abstract void beforeExecuteActivity(WfConfigActivity wfConfigActivity);
/**
* �����û�����
* @param wfConfigActivity
* @throws Exception
* @throws WorkflowException
*/
private void executeUserActivity(WfConfigActivity wfConfigActivity) throws WorkflowException {
WfConfigUserActivity wfConfigUserActivity = (WfConfigUserActivity)wfConfigActivity;
WfConfigUserPolicy wfConfigUserPolicy = wfConfigUserActivity.getUserPolicy();
/*�����û�������Ϣ*/
if (WorkflowStatus.NORMAL == context.getEngineStatus()) {
/*�˹�������չ����*/
context.putPrivate(WorkflowDefination.CONTEXT_KEY_POST_ID, wfConfigUserPolicy.getRoleId());
context.putPrivate(WorkflowDefination.CONTEXT_KEY_USER_ID, wfConfigUserPolicy.getUserId());
/*������״̬��Ϊ����*/
context.setEngineStatus(WorkflowStatus.SUSPEND);
/*�û��ӿ���չ����*/
extendUserActivity(wfConfigActivity);
}
/*�û��ӿڷ���Ĺ���������ָ�����*/
else if (WorkflowStatus.SUSPEND == context.getEngineStatus()) {
Map<String, Object> in_params = (Map<String, Object>)context.getPrivate(WorkflowDefination.IN_PARAMS);
if (StringUtils.trimToString(in_params.get(WorkflowDefination.USER_ENTRY)).equals(wfConfigUserPolicy.getEntry())) {
/*ִ�л��ں�ʵ�嶯������*/
List<WfConfigAction> postActions = wfConfigUserActivity.getPostActions();
executeActions(postActions);
/*������״̬�ָ�Ϊ����*/
context.setEngineStatus(WorkflowStatus.NORMAL);
/*�û��ӿ���չ����*/
extendUserActivity(wfConfigActivity);
} else {
/*ִ�л���ǰʵ�嶯������*/
List<WfConfigAction> preActions = wfConfigUserActivity.getPreActions();
executeActions(preActions);
}
}
}
/**
* ���������̻���
* @param wfConfigActivity
* @throws Exception
*/
private void executeSubflowActivity(WfConfigActivity wfConfigActivity) throws WorkflowException {
/*ִ�л���ǰʵ�嶯������*/
WfConfigSubflowActivity wfConfigSubflowActivity = (WfConfigSubflowActivity)wfConfigActivity;
List<WfConfigAction> preActions = wfConfigSubflowActivity.getPreActions();
executeActions(preActions);
/*����������*/
String subflowId = wfConfigSubflowActivity.getSubflowId();
context.put(WorkflowDefination.CONTEXT_KEY_SUBFLOW_ID, subflowId);
WorkflowAction subflowAction = new SubflowAction();
subflowAction.execute(context);
context.remove(WorkflowDefination.CONTEXT_KEY_SUBFLOW_ID);
/*ִ�л��ں�ʵ�嶯������*/
List<WfConfigAction> postActions = wfConfigSubflowActivity.getPostActions();
executeActions(postActions);
}
/**
* ִ�л���ʵ�嶯������
* @param wfConfigActions
* @throws Exception
*/
private void executeActions(List<WfConfigAction> wfConfigActions) throws WorkflowException {
try {
for (WfConfigAction wfConfigAction : wfConfigActions) {
log.error("ִ�д���ʼ��" + wfConfigAction.getActionId());
String type = wfConfigAction.getType();
if ("".equals(type) || WorkflowDefination.DEFAULT_ACTION_TYPE.equals(type)) {
String argName = wfConfigAction.getArgument().getArgName();
if (WorkflowDefination.ARG_VALUE_CLASS.equals(argName)) {
String className = wfConfigAction.getArgument().getArgValue();
Class clsAction = Class.forName(className);
WorkflowAction workflowAction = (WorkflowAction)clsAction.newInstance();
//log.error("ִ�д���ʼ��" + wfConfigAction.getActionId() + "-" + className);
workflowAction.execute(context);
//log.error("ִ�д��������" + wfConfigAction.getActionId() + "-" + className);
}
} else if (WorkflowDefination.BEANSHELL_ACTION_TYPE.equals(type)) {
context.put(WorkflowDefination.CONTEXT_KEY_ARGUMENT, wfConfigAction.getArgument());
WorkflowAction workflowAction = new BeanShellAction();
workflowAction.execute(context);
context.remove(WorkflowDefination.CONTEXT_KEY_ARGUMENT);
}
log.error("ִ�д��������" + wfConfigAction.getActionId());
}
} catch (WorkflowException e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw e;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new WorkflowException();
}
}
/**
* ���ڽ������
* @param wfConfigResults
*/
private WfConfigResult executeResults(Map<String, WfConfigResult> wfConfigResults) {
WfConfigResult wfConfigResult = null;
Set<String> resultSet = wfConfigResults.keySet();
String [] resultKeys = resultSet.toArray(new String[0]);
for (String resultKey : resultKeys) {
wfConfigResult = wfConfigResults.get(resultKey);
// if (WorkflowDefination.DEFAULT_RESULT_TYPE.equals(wfConfigResult.getResultType())) {
// break;
// }
List<WfConfigCondition> wfConfigConditions = wfConfigResult.getConditions();
if (wfConfigConditions == null) {
break;
}
String policy = StringUtils.trimToString(wfConfigResult.getPolicy());
boolean match = false;
for (WfConfigCondition wfConfigCondition : wfConfigConditions) {
boolean _match = executeCondition(wfConfigCondition);
if ("or".equals(policy)) {
if (_match) {
match = true;
break;
}
} else if ("and".equals(policy)) {
if (_match) {
match = true;
continue;
} else {
match = false;
break;
}
} else {
if (_match) {
match = true;
break;
}
}
}
if (match) {
break;
}
}
//����������Ϊ�գ���Ϊ������ִ�н������ֶ��������״̬
if (wfConfigResult == null) {
wfConfigResult = new WfConfigResult();
wfConfigResult.setActivityId(WorkflowDefination.WORKFLOW_FINISH_ACTIVITY_ID);
wfConfigResult.setStatus(WorkflowDefination.WORKFLOW_FINISH);
}
return wfConfigResult;
}
/**
* ִ�������ж�
* @param wfConfigCondition
* @return
*/
private boolean executeCondition(WfConfigCondition wfConfigCondition) {
boolean match = false;
try {
WorkflowCondition workflowCondition = getCondition(wfConfigCondition);
if (WorkflowDefination.BEANSHELL_CONDITION_TYPE.equals(wfConfigCondition.getConditionType()))
context.put(WorkflowDefination.CONTEXT_KEY_ARGUMENT, wfConfigCondition.getArgument());
match = workflowCondition.processCondition(context);
if (WorkflowDefination.BEANSHELL_CONDITION_TYPE.equals(wfConfigCondition.getConditionType()))
context.remove(WorkflowDefination.CONTEXT_KEY_ARGUMENT);
} catch (WorkflowException e) {
e.printStackTrace();
}
return match;
}
/**
* ȡ����������
* @param wfConfigCondition
* @return
* @throws WorkflowException
*/
private WorkflowCondition getCondition(WfConfigCondition wfConfigCondition) throws WorkflowException {
String conditionType = wfConfigCondition.getConditionType();
WfConfigArgument arg = wfConfigCondition.getArgument();
String argValue = arg.getArgValue();
WorkflowCondition workflowCondition = null;
if ("".equals(conditionType) || WorkflowDefination.DEFAULT_CONDITION_TYPE.equals(conditionType)) {
try {
workflowCondition = (WorkflowCondition)Class.forName(argValue).newInstance();
} catch (Exception e) {
if (e instanceof WorkflowException) {
throw (WorkflowException)e;
} else {
throw new WorkflowException("", e);
}
}
} else if (WorkflowDefination.BEANSHELL_CONDITION_TYPE.equals(conditionType)) {
workflowCondition = new BeanShellCondition();
} else {
throw new WorkflowException();
}
return workflowCondition;
}
/**
* @return �����������Ķ���
*/
public WorkflowContext getContext() {
return context;
}
/**
* @param context �����������Ķ���
*/
public void setContext(WorkflowContext context) {
this.context = context;
}
/**
* @return ����������
*/
public Workflow getWorkflow() {
return workflow;
}
/**
* @param workflow ����������
*/
public void setWorkflow(Workflow workflow) {
this.workflow = workflow;
}
protected Properties getProperties() {
return properties;
}
protected void setProperties(Properties properties) {
this.properties = properties;
}
/**
* ��������������
*/
public void start() throws Exception {
this.execute();
}
/**
* ������������ǰ����
*/
protected abstract Map<String, Object> preStartWorkflow(Map<String, Object> params);
/**
* �����������̺���
*/
protected abstract Map<String, Object> postStartWorkflow(Map<String, Object> params);
/**
* ����������
* @throws WorkflowException
*/
public Map<String, Object> startWorkflow(Map<String, Object> in_params) throws WorkflowException {
Map<String, Object> out_params = new HashMap<String, Object>();
String workflowId = StringUtils.trimToString(in_params.get(WorkflowDefination.WORKFLOW_ID));
/*��ʼ��������������*/
if (context == null) {
initWorkflowContext(workflowId);
}
/*���������������*/
context.putPrivate(WorkflowDefination.IN_PARAMS, in_params);
context.put(WorkflowDefination.IN_PARAMS, in_params);
workflow = context.getWorkflow();
wfConfigActivities = workflow.getActivities();
/*�����������ǰ����*/
this.preStartWorkflow(in_params);
/*��������*/
try {
this.start();
} catch (Exception e) {
// TODO Auto-generated catch block
//e.printStackTrace();
if (e instanceof WorkflowException) {
throw (WorkflowException)e;
} else {
throw new WorkflowException("", e);
}
}
/*�����������̺���*/
this.postStartWorkflow(in_params);
out_params.put(WorkflowDefination.WORKFLOW_CONTEXT, context);
return out_params;
}
}