/** * Copyright 2007-2010 非也 * All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License 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 General Public License * along with this program. If not, see http://www.gnu.org/licenses. * */ package org.fireflow.engine.invocation.impl; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.script.ScriptException; import javax.xml.namespace.QName; import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.beanutils.MethodUtils; import org.apache.ws.commons.schema.XmlSchemaCollection; import org.fireflow.client.WorkflowSession; import org.fireflow.client.impl.WorkflowSessionLocalImpl; import org.fireflow.engine.context.RuntimeContext; import org.fireflow.engine.entity.runtime.ActivityInstance; import org.fireflow.engine.entity.runtime.ProcessInstance; import org.fireflow.engine.exception.ServiceInvocationException; import org.fireflow.engine.invocation.ServiceInvoker; 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.binding.Assignment; import org.fireflow.model.binding.ResourceBinding; import org.fireflow.model.binding.ServiceBinding; import org.fireflow.model.data.Expression; import org.fireflow.model.servicedef.ServiceDef; import org.firesoa.common.schema.DOMInitializer; import org.firesoa.common.schema.NameSpaces; import org.w3c.dom.Document; /** * * * @author 非也 * @version 2.0 */ public abstract class AbsServiceInvoker implements ServiceInvoker { // DocumentFactory docFactory = DocumentFactory.getInstance(); /* * (non-Javadoc) * * @see * org.fireflow.engine.service.ServiceExecutor#complete(org.fireflow.engine * .WorkflowSession, org.fireflow.engine.entity.runtime.ActivityInstance, * java.lang.Object) */ // public void onServiceCompleted(WorkflowSession session, // ActivityInstance activityInstance) { // RuntimeContext ctx = ((WorkflowSessionLocalImpl) session) // .getRuntimeContext(); // ActivityInstanceManager activityInstanceMgr = ctx.getEngineModule( // ActivityInstanceManager.class, // activityInstance.getProcessType()); // // activityInstanceMgr.onServiceCompleted(session, activityInstance); // // } public int determineActivityCloseStrategy(WorkflowSession session, ActivityInstance activityInstance, Object theActivity, ServiceBinding serviceBinding) { return ServiceInvoker.CLOSE_ACTIVITY; } public boolean invoke(WorkflowSession session, ActivityInstance activityInstance, ServiceBinding serviceBinding, ResourceBinding resourceBinding, Object theActivity) throws ServiceInvocationException { try { WorkflowSessionLocalImpl sessionLocalImpl = (WorkflowSessionLocalImpl) session; RuntimeContext runtimeContext = sessionLocalImpl .getRuntimeContext(); ProcessInstance processInstance = sessionLocalImpl.getCurrentProcessInstance(); ProcessLanguageManager processUtil = runtimeContext.getEngineModule(ProcessLanguageManager.class, activityInstance.getProcessType()); ServiceDef svc = processUtil.getServiceDef(activityInstance,theActivity, serviceBinding.getServiceId()); if (svc==null){ ServiceInvocationException ex = new ServiceInvocationException("没有找到Id为"+serviceBinding.getServiceId()+"的服务"); ex.setErrorCode(ServiceInvocationException.SERVICE_DEF_NOT_FOUND); ex.setActivityInstance(activityInstance); throw ex; } // 1、首先获得Service Object Object serviceObject = this.getServiceObject(runtimeContext, session, activityInstance, serviceBinding,svc,theActivity); if (serviceObject==null){ ServiceInvocationException ex = new ServiceInvocationException("无法初始化 service object,Service定义是[name="+svc.getName()+",displayName="+svc.getDisplayName()+"]"); ex.setErrorCode(ServiceInvocationException.SERVICE_OBJECT_NOT_FOUND); ex.setActivityInstance(activityInstance); throw new ServiceInvocationException(); } // 2、然后获得被调用的Method String methodName = this.getOperationName(runtimeContext, session, activityInstance, serviceBinding); if (methodName==null || methodName.trim().equals("")){ ServiceInvocationException ex = new ServiceInvocationException("服务没有名称为"+serviceBinding.getOperationName()+"的方法,Service定义是[name="+svc.getName()+",displayName="+svc.getDisplayName()+"]"); ex.setErrorCode(ServiceInvocationException.OPERATION_NOT_FOUND); ex.setActivityInstance(activityInstance); throw new ServiceInvocationException(); } // 3、解析参数 Object[] params = resolveInputParams(runtimeContext, session,processInstance, activityInstance, serviceBinding,svc); // 4、获得参数类型 Class[] parameterTypes = this.getParameterTypes(serviceObject.getClass(), methodName, params); // 5、调用 System.out.println("===Inside AbsServiceInvoker,serviceObject="+serviceObject); System.out.println("===methodName is "+methodName); System.out.println("===params is "+ java.util.Arrays.toString(params)); System.out.println("===params typs is "+ java.util.Arrays.toString(parameterTypes)); Object result = MethodUtils.invokeMethod(serviceObject, methodName, params,parameterTypes); // 6、返回值回写到流程系统中 assignOutputToVariable(runtimeContext, session,processInstance, activityInstance, serviceBinding, result); return true; } catch(ServiceInvocationException e){ if (e.getActivityInstance()==null){ e.setActivityInstance(activityInstance); } throw e; } catch (ScriptException e) { ServiceInvocationException ex = new ServiceInvocationException(e); ex.setErrorCode(findRootCause(e).getClass().getName()); ex.setActivityInstance(activityInstance); throw ex; } catch (SecurityException e) { ServiceInvocationException ex = new ServiceInvocationException(e); ex.setErrorCode(findRootCause(e).getClass().getName()); ex.setActivityInstance(activityInstance); throw ex; } catch (NoSuchMethodException e) { ServiceInvocationException ex = new ServiceInvocationException(e); ex.setErrorCode(findRootCause(e).getClass().getName()); ex.setActivityInstance(activityInstance); throw ex; } catch (IllegalArgumentException e) { ServiceInvocationException ex = new ServiceInvocationException(e); ex.setErrorCode(findRootCause(e).getClass().getName()); ex.setActivityInstance(activityInstance); throw ex; } catch (IllegalAccessException e) { ServiceInvocationException ex = new ServiceInvocationException(e); ex.setErrorCode(findRootCause(e).getClass().getName()); ex.setActivityInstance(activityInstance); throw ex; } catch (InvocationTargetException e) { ServiceInvocationException ex = new ServiceInvocationException(e); ex.setErrorCode(findRootCause(e).getClass().getName()); ex.setActivityInstance(activityInstance); throw ex; } catch (Exception e) { ServiceInvocationException ex = new ServiceInvocationException(e); ex.setErrorCode(findRootCause(e).getClass().getName()); ex.setActivityInstance(activityInstance); throw ex; } } private Throwable findRootCause(Throwable e){ if (e.getCause()==null){ return e; } return findRootCause(e.getCause()); } protected abstract Object getServiceObject(RuntimeContext runtimeContext, WorkflowSession session, ActivityInstance activityInstance, ServiceBinding serviceBinding,ServiceDef serviceDef,Object activity)throws ServiceInvocationException; public static Map<String ,Object> resolveInputAssignments(RuntimeContext runtimeContext, WorkflowSession session,ProcessInstance processInstance, ActivityInstance activityInstance, ServiceBinding serviceBinding,ServiceDef service)throws ScriptException{ List<Assignment> inputAssignmentList = serviceBinding.getInputAssignments(); // OperationDef operation = serviceBinding.getOperation(); // List<Input> inputs = operation.getInputs(); Map<String, Object> contextVars = ScriptEngineHelper.fulfillScriptContext(session, runtimeContext, processInstance, activityInstance); //初始化xml类型的input输入,所有的xml类型输入用org.w3c.dom.Document表示 Map<String,Object> inputsContext = new HashMap<String,Object>(); for (Assignment assignment : inputAssignmentList){ Expression toExpression = assignment.getTo(); if (toExpression.getName()==null || toExpression.getName().trim().equals("")){ throw new ScriptException("The name of the assignment's To-Expression can NOT be empty. More information : the body of the To-Expression is '"+toExpression.getBody()+"';the activity id is "+activityInstance.getNodeId()); } if (toExpression.getDataType()!=null && !NameSpaces.JAVA.getUri().equals(toExpression.getDataType().getNamespaceURI()) && inputsContext.get(toExpression.getName())==null){ Document doc = initDocument(service.getXmlSchemaCollection(),toExpression.getDataType()); inputsContext.put(toExpression.getName(), doc); } } contextVars.put(ScriptContextVariableNames.INPUTS, inputsContext); Map<String, Object> inputParamValues = ScriptEngineHelper .resolveInputParameters(runtimeContext, serviceBinding.getInputAssignments(), contextVars); return inputParamValues; } protected Object[] resolveInputParams(RuntimeContext runtimeContext, WorkflowSession session,ProcessInstance processInstance, ActivityInstance activityInstance, ServiceBinding serviceBinding,ServiceDef service)throws ScriptException { Map<String,Object> inputParamValues = resolveInputAssignments(runtimeContext,session,processInstance, activityInstance,serviceBinding,service); List<Assignment> inputAssignmentList = serviceBinding.getInputAssignments(); // OperationDef operation = null; // List<Input> inputs = operation.getInputs(); List<Object> args = new ArrayList<Object>(); for (Assignment assignment : inputAssignmentList) { Expression toExpression = assignment.getTo(); if (inputParamValues!=null && inputParamValues.containsKey(toExpression.getName())){ Object paramValue = inputParamValues.get(toExpression.getName()); args.add(paramValue); }else{ args.add(null); //TODO 缺省参数需要处理吗? //由于所有的接口采用java接口,貌似没有必要。 // String defaultValueAsString = _input.getDefaultValueAsString(); // if (StringUtils.isEmpty(defaultValueAsString)){ // args.add(null); // }else { // Object obj = JavaDataTypeConvertor.dataTypeConvert(_input.getDataType(), defaultValueAsString, _input.getDataPattern()); // args.add(obj); // } } } return args.toArray(); } protected void assignOutputToVariable(RuntimeContext runtimeContext, WorkflowSession session, ProcessInstance processInstance,ActivityInstance activityInstance, ServiceBinding serviceBinding, Object result) throws ScriptException{ // OperationDef operation = serviceBinding.getOperation(); List<Assignment> outputAssignments = serviceBinding.getOutputAssignments(); if (outputAssignments==null || outputAssignments.size()==0)return ;//无赋值操作 Map<String,Object> scriptContext = new HashMap<String,Object>(); Map<String, Object> outputsResults = new HashMap<String, Object>(); Assignment assignment = outputAssignments.get(0); Expression fromExp = assignment.getFrom(); outputsResults.put(fromExp.getName(), result); scriptContext.put(ScriptContextVariableNames.OUTPUTS, outputsResults); //System.out.println("======待输出的结果是===="+outputsResults); ScriptEngineHelper.assignOutputToVariable(session,runtimeContext, processInstance,activityInstance, outputAssignments, scriptContext); } /** * 根据Schema创建org.w3c.dom.Document; * TODO 对于Schema中的Choice指示器,将不创建子元素,所以在这种情况下,有可能出现问题。 * @param xmlSchemaCollection * @param elementQName * @return */ protected static Document initDocument(XmlSchemaCollection xmlSchemaCollection, QName rootElementQName)throws ScriptException{ try{ Document doc = DOMInitializer.generateDocument(xmlSchemaCollection, rootElementQName); return doc; }catch(ParserConfigurationException e){ throw new ScriptException(e); } } // protected org.dom4j.QName javaxQName4Dom4JQName(javax.xml.namespace.QName qNameIn){ // org.dom4j.Namespace ns = new org.dom4j.Namespace(qNameIn.getPrefix(),qNameIn.getNamespaceURI()); // org.dom4j.QName qName = new org.dom4j.QName(qNameIn.getLocalPart(),ns); // return qName; // } protected String getOperationName(RuntimeContext runtimeContext, WorkflowSession session, ActivityInstance activityInstance, ServiceBinding serviceBinding)throws ServiceInvocationException{ return serviceBinding.getOperationName(); } protected abstract Class[] getParameterTypes(Class serviceClass,String methodName, Object[] params)throws ServiceInvocationException; }