/**
* Copyright 2007-2010 非也
* All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License v3 as published by the Free Software
* Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this library; if not, see http://www.gnu.org/licenses/lgpl.html.
*
*/
package org.fireflow.service.call;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.script.ScriptException;
import org.fireflow.client.WorkflowQuery;
import org.fireflow.client.WorkflowSession;
import org.fireflow.client.impl.WorkflowSessionLocalImpl;
import org.fireflow.client.query.Restrictions;
import org.fireflow.engine.context.RuntimeContext;
import org.fireflow.engine.entity.repository.ProcessKey;
import org.fireflow.engine.entity.repository.ProcessRepository;
import org.fireflow.engine.entity.runtime.ActivityInstance;
import org.fireflow.engine.entity.runtime.ProcessInstance;
import org.fireflow.engine.entity.runtime.ProcessInstanceProperty;
import org.fireflow.engine.exception.ServiceInvocationException;
import org.fireflow.engine.invocation.ServiceInvoker;
import org.fireflow.engine.invocation.impl.AbsServiceInvoker;
import org.fireflow.engine.modules.instancemanager.ProcessInstanceManager;
import org.fireflow.engine.modules.loadstrategy.ProcessLoadStrategy;
import org.fireflow.engine.modules.ousystem.User;
import org.fireflow.engine.modules.persistence.PersistenceService;
import org.fireflow.engine.modules.persistence.ProcessPersister;
import org.fireflow.engine.modules.processlanguage.ProcessLanguageManager;
import org.fireflow.engine.modules.script.ScriptContextVariableNames;
import org.fireflow.engine.modules.script.ScriptEngineHelper;
import org.fireflow.model.InvalidModelException;
import org.fireflow.model.binding.Assignment;
import org.fireflow.model.binding.ResourceBinding;
import org.fireflow.model.binding.ServiceBinding;
/**
*
* @author 非也 nychen2000@163.com
* Fire Workflow 官方网站:www.firesoa.com 或者 www.fireflow.org
*
*/
public class CallServiceInvoker implements ServiceInvoker {
/* (non-Javadoc)
* @see org.fireflow.engine.invocation.ServiceInvoker#invoke(org.fireflow.engine.WorkflowSession, org.fireflow.engine.entity.runtime.ActivityInstance, org.fireflow.model.binding.ServiceBinding, org.fireflow.model.binding.ResourceBinding, java.lang.Object)
// */
public boolean invoke(WorkflowSession session,
ActivityInstance activityInstance, ServiceBinding serviceBinding,
ResourceBinding resourceBinding, Object theActivity)
throws ServiceInvocationException {
RuntimeContext context = ((WorkflowSessionLocalImpl)session).getRuntimeContext();
WorkflowSessionLocalImpl sessionLocal = (WorkflowSessionLocalImpl)session;
ProcessInstance oldProcessInstance = sessionLocal.getCurrentProcessInstance();
ActivityInstance oldActivityInstance = sessionLocal.getCurrentActivityInstance();
((WorkflowSessionLocalImpl)session).setCurrentProcessInstance(null);
((WorkflowSessionLocalImpl)session).setCurrentActivityInstance(null);
ProcessLanguageManager processUtil = context.getEngineModule(ProcessLanguageManager.class, activityInstance.getProcessType());
try{
//1、确定子流程的ProcessId,SubflowId,版本号等信息
CallServiceDef subflowService = (CallServiceDef)processUtil.getServiceDef(activityInstance, theActivity, serviceBinding.getServiceId());
if (subflowService==null){
ServiceInvocationException ex = new ServiceInvocationException("没有找到Id为"+serviceBinding.getServiceId()+"的服务");
ex.setErrorCode(ServiceInvocationException.SERVICE_DEF_NOT_FOUND);
ex.setActivityInstance(activityInstance);
throw ex;
}
String subflowId = subflowService.getSubProcessId();
String processId = subflowService.getProcessId();
String processType = activityInstance.getProcessType();
Integer version = subflowService.getProcessVersion();
//同一流程只能用相同的版本号
if (processId.equals(activityInstance.getProcessId())){
version = activityInstance.getVersion();
}
if (version==CallServiceDef.THE_LATEST_VERSION){
//查找流程的最新版本号。
ProcessLoadStrategy loadStrategy = context.getEngineModule(
ProcessLoadStrategy.class, activityInstance.getProcessType());
User u = session.getCurrentUser();
ProcessKey pk = loadStrategy.findTheProcessKeyForRunning(
processId, activityInstance.getProcessType(),u,session);
version = pk.getVersion();
}
//2、构建输入参数
Map<String, Object> variables = null;
try {
variables = AbsServiceInvoker.resolveInputAssignments(context, session, oldProcessInstance, oldActivityInstance, serviceBinding,subflowService);
} catch (ScriptException e) {
ServiceInvocationException ex = new ServiceInvocationException(e);
ex.setErrorCode(findRootCause(e).getClass().getName());
ex.setActivityInstance(activityInstance);
throw ex;
}
ProcessInstanceManager processInstanceManager = context.getEngineModule(ProcessInstanceManager.class, processType);
PersistenceService persistenceService = context.getEngineModule(PersistenceService.class,processType);
ProcessPersister processPersister = persistenceService.getProcessPersister();
ProcessRepository repository = null;
try {
repository = processPersister.findProcessRepositoryByProcessKey(new ProcessKey(processId,version,processType));
if (repository==null){
ServiceInvocationException ex = new ServiceInvocationException("流程库中没有ProcessId="+processId+",version="+version+"的流程定义文件。");
ex.setActivityInstance(activityInstance);
ex.setErrorCode(ServiceInvocationException.PROCESS_DEF_NOT_FOUND);
throw ex;
}
} catch (InvalidModelException e) {
ServiceInvocationException ex = new ServiceInvocationException(e.getMessage(),e);
ex.setErrorCode(ServiceInvocationException.INVALID_PROCESS_MODEL);
ex.setActivityInstance(activityInstance);
throw ex;
}
Object workflowProcess = repository.getProcessObject();
//启动子流程
// Token parentToken = kernelManager.getToken(activityInstance.getTokenId(), activityInstance.getProcessType());
ProcessInstance childProcessInstance = processInstanceManager.createProcessInstance(session, workflowProcess, subflowId, repository, oldActivityInstance);
((WorkflowSessionLocalImpl)session).setCurrentProcessInstance(childProcessInstance);
processInstanceManager.runProcessInstance(session, childProcessInstance.getId(), childProcessInstance.getProcessType(), oldActivityInstance.getBizId(), variables);
}finally{
((WorkflowSessionLocalImpl)session).setCurrentProcessInstance(oldProcessInstance);
((WorkflowSessionLocalImpl)session).setCurrentActivityInstance(oldActivityInstance);
}
return false;//表示异步调用
}
private Throwable findRootCause(Throwable e){
if (e.getCause()==null){
return e;
}
return findRootCause(e.getCause());
}
/* (non-Javadoc)
* @see org.fireflow.engine.invocation.ServiceInvoker#determineActivityCloseStrategy(org.fireflow.engine.WorkflowSession, org.fireflow.engine.entity.runtime.ActivityInstance, java.lang.Object)
*/
public int determineActivityCloseStrategy(WorkflowSession session,
ActivityInstance activityInstance, Object theActivity, ServiceBinding serviceBinding) {
RuntimeContext context = ((WorkflowSessionLocalImpl)session).getRuntimeContext();
WorkflowSessionLocalImpl sessionLocal = (WorkflowSessionLocalImpl)session;
int result = ServiceInvoker.CLOSE_ACTIVITY;
//此处可以增加特殊逻辑,以判断子流程是否可以结束。
if (result==ServiceInvoker.CLOSE_ACTIVITY){
//校验currentActivityInstance和currentProcessInstance
((WorkflowSessionLocalImpl)session).setCurrentActivityInstance(activityInstance);
ProcessInstance parentProcessInstance = sessionLocal.getCurrentProcessInstance();
if (parentProcessInstance==null || !parentProcessInstance.getId().equals(activityInstance.getProcessInstanceId())){
parentProcessInstance = activityInstance.getProcessInstance(session);
((WorkflowSessionLocalImpl)session).setCurrentProcessInstance(parentProcessInstance);
}
//查询出子流程实例
WorkflowQuery<ProcessInstance> query = session.createWorkflowQuery(ProcessInstance.class);
query.add(Restrictions.eq(ProcessInstanceProperty.PARENT_ACTIVITY_INSTANCE_ID, activityInstance.getId()))
.add(Restrictions.eq(ProcessInstanceProperty.PARENT_PROCESS_INSTANCE_ID, parentProcessInstance.getId()));
ProcessInstance subProcInst = query.unique();//在不定制的情况下,只可能创建一个子流程
Map<String,Object> subProcInstVars = subProcInst.getVariableValues(session);
//处理输出,将子流程的流程变量反馈到父流程实例或者父活动实例
// OperationDef operation = serviceBinding.getOperation();
List<Assignment> outputAssignments = serviceBinding
.getOutputAssignments();
if (outputAssignments != null && outputAssignments.size() > 0) {
Map<String, Object> scriptContext = new HashMap<String, Object>();
scriptContext.put(ScriptContextVariableNames.OUTPUTS,
subProcInstVars);
try {
ScriptEngineHelper.assignOutputToVariable(session, context,
parentProcessInstance, activityInstance,
outputAssignments, scriptContext);
} catch (ScriptException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return result;
}
}