/**
* 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.pdl.fpdl.test.service.callback;
import java.net.URL;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.Dispatch;
import org.apache.commons.jxpath.JXPathContext;
import org.fireflow.FireWorkflowJunitEnviroment;
import org.fireflow.client.WorkflowQuery;
import org.fireflow.client.WorkflowSession;
import org.fireflow.client.WorkflowSessionFactory;
import org.fireflow.client.WorkflowStatement;
import org.fireflow.client.query.Order;
import org.fireflow.client.query.Restrictions;
import org.fireflow.engine.entity.repository.ProcessDescriptor;
import org.fireflow.engine.entity.repository.impl.ProcessDescriptorImpl;
import org.fireflow.engine.entity.runtime.ActivityInstance;
import org.fireflow.engine.entity.runtime.ActivityInstanceProperty;
import org.fireflow.engine.entity.runtime.ActivityInstanceState;
import org.fireflow.engine.entity.runtime.ProcessInstance;
import org.fireflow.engine.entity.runtime.ProcessInstanceState;
import org.fireflow.engine.modules.environment.Environment;
import org.fireflow.engine.modules.ousystem.impl.FireWorkflowSystem;
import org.fireflow.engine.modules.script.ScriptContextVariableNames;
import org.fireflow.model.InvalidModelException;
import org.fireflow.model.binding.impl.AssignmentImpl;
import org.fireflow.model.binding.impl.ServiceBindingImpl;
import org.fireflow.model.data.impl.ExpressionImpl;
import org.fireflow.model.data.impl.InputImpl;
import org.fireflow.model.data.impl.OutputImpl;
import org.fireflow.model.data.impl.PropertyImpl;
import org.fireflow.model.misc.Duration;
import org.fireflow.model.process.WorkflowElement;
import org.fireflow.model.servicedef.impl.CommonInterfaceDef;
import org.fireflow.model.servicedef.impl.OperationDefImpl;
import org.fireflow.pdl.fpdl.misc.FpdlConstants;
import org.fireflow.pdl.fpdl.process.SubProcess;
import org.fireflow.pdl.fpdl.process.WorkflowProcess;
import org.fireflow.pdl.fpdl.process.features.startnode.impl.WebserviceStartFeatureImpl;
import org.fireflow.pdl.fpdl.process.impl.ActivityImpl;
import org.fireflow.pdl.fpdl.process.impl.EndNodeImpl;
import org.fireflow.pdl.fpdl.process.impl.StartNodeImpl;
import org.fireflow.pdl.fpdl.process.impl.TransitionImpl;
import org.fireflow.pdl.fpdl.process.impl.WorkflowProcessImpl;
import org.fireflow.pvm.kernel.Token;
import org.fireflow.pvm.kernel.TokenProperty;
import org.fireflow.pvm.kernel.TokenState;
import org.fireflow.service.callback.CallbackService;
import org.firesoa.common.schema.NameSpaces;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.w3c.dom.Document;
/**
* 通过Webservice启动流程
* @author 非也 nychen2000@163.com
* Fire Workflow 官方网站:www.firesoa.com 或者 www.fireflow.org
*
*/
public class WebserviceStartProcessTest extends FireWorkflowJunitEnviroment{
protected static final String processName = "TheSimplestSquenceProcess";
protected static final String processDisplayName = "最简单的测试流程";
protected static final String description = "一个最简单的顺序流程,没有绑定服务和resource";
protected static final String bizId = "biz_123";
protected static final String approveResult = "Very good!";
protected static final String responseResult = "OK";
protected static String targetNsUri = "http://www.fireflow.org/junit/webservice_start_process";
protected static String serviceName = "StartProcessService";
protected static String serviceVersion = "1";
protected static String interfaceName = "StartProcess";
protected static QName serviceQName = new QName(targetNsUri,serviceName+"_"+serviceVersion);
protected static QName portQName = new QName(targetNsUri,interfaceName+"_Port");
@Test
public void testCallbackService(){
final WorkflowSession session = WorkflowSessionFactory.createWorkflowSession(fireflowRuntimeContext,FireWorkflowSystem.getInstance());
final WorkflowStatement stmt = session.createWorkflowStatement(FpdlConstants.PROCESS_TYPE_FPDL20);
//0、构建流程定义
final WorkflowProcess process = getWorkflowProcess();
//1、首先发布流程
transactionTemplate.execute(new TransactionCallback(){
public Object doInTransaction(TransactionStatus arg0) {
//发布
try {
ProcessDescriptor descriptor = stmt.uploadProcessObject(process,0);
((ProcessDescriptorImpl)descriptor).setPublishState(true);
stmt.updateProcessDescriptor(descriptor);
} catch (InvalidModelException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
});
//2、调用CallbackManager的init方法发布Webservice
//TODO 通过WorkflowServer发布webservice
// WebServiceManager callbackManager = this.runtimeContext.getEngineModule(WebServiceManager.class, FpdlConstants.PROCESS_TYPE_FPDL20);
// try {
// callbackManager.publishAllCallbackServices();
// } catch (WebservicePublishException e1) {
// // TODO Auto-generated catch block
// e1.printStackTrace();
// }
//用Jaxws客户端调用Webservice
Environment env = fireflowRuntimeContext.getEngineModule(Environment.class, FpdlConstants.PROCESS_TYPE_FPDL20);
URL url = null;
try{
String contextPath = env.getWebserviceContextPath();
if (!contextPath.startsWith("/")){
contextPath = "/"+contextPath;
}
if (!contextPath.endsWith("/")){
contextPath = contextPath+"/";
}
String address = "http://"+env.getWebserviceIP()+":"
+Integer.toString(env.getWebservicePort())
+contextPath;
url = new URL(address+serviceQName.getLocalPart()+"?wsdl");
}catch(Exception e){
e.printStackTrace();
}
javax.xml.ws.Service jawsService = javax.xml.ws.Service.create(url, serviceQName);
Dispatch<Source> dispatch = jawsService.createDispatch(portQName, Source.class, javax.xml.ws.Service.Mode.PAYLOAD);
String messageStr = "<cal:acceptRequest xmlns:cal=\""+targetNsUri+"\">"+
"<cal:id>"+bizId+"</cal:id>"+
"<cal:approveResult>"+approveResult+"</cal:approveResult>"+
"</cal:acceptRequest>";
java.io.ByteArrayInputStream byteInStream = new java.io.ByteArrayInputStream(messageStr.getBytes());
StreamSource source = new StreamSource(byteInStream);
Source response = dispatch.invoke(source);
DOMResult result = new DOMResult();
// StreamResult result = new StreamResult(System.out);
Transformer transformer = null;
try {
TransformerFactory transformerFactory = TransformerFactory.newInstance();
transformer = transformerFactory.newTransformer();
transformer.transform(response, result);
} catch (TransformerConfigurationException e) {
throw new RuntimeException("Couldn't parse response stream.", e);
} catch (TransformerException e) {
throw new RuntimeException("Couldn't parse response stream.", e);
}
Document theResponsePayload = (Document)result.getNode();
Assert.assertNotNull(theResponsePayload);
JXPathContext jxpathContext = JXPathContext.newContext(theResponsePayload);
jxpathContext.registerNamespace("ns0", targetNsUri);
String response2 = (String)jxpathContext.getValue("ns0:acceptResponse/ns0:response2");
String response1 = (String)jxpathContext.getValue("ns0:acceptResponse/ns0:response1");
Assert.assertEquals(responseResult, response2);
Assert.assertNotNull(response1);
this.processInstanceId = response1;
this.assertResult(session);
}
@Override
public void assertResult(WorkflowSession session) {
// TODO Auto-generated method stub
super.assertResult(session);
// 验证ProcessInstance信息
WorkflowQuery<ProcessInstance> q4ProcInst = session
.createWorkflowQuery(ProcessInstance.class);
ProcessInstance procInst = q4ProcInst.get(processInstanceId);
Assert.assertNotNull(procInst);
Assert.assertEquals(bizId, procInst.getBizId());
Assert.assertEquals(processName, procInst.getProcessId());
Assert.assertEquals(FpdlConstants.PROCESS_TYPE_FPDL20,
procInst.getProcessType());
Assert.assertEquals(new Integer(1), procInst.getVersion());
Assert.assertEquals(processName, procInst.getProcessName());// name
// 为空的情况下默认等于processId,
Assert.assertEquals(processDisplayName, procInst.getProcessDisplayName());// displayName为空的情况下默认等于name
Assert.assertEquals(ProcessInstanceState.COMPLETED, procInst.getState());
Assert.assertEquals(Boolean.FALSE, procInst.isSuspended());
Assert.assertEquals(FireWorkflowSystem.getInstance().getId(),
procInst.getCreatorId());
Assert.assertEquals(FireWorkflowSystem.getInstance().getName(),
procInst.getCreatorName());
Assert.assertEquals(FireWorkflowSystem.getInstance().getDeptId(),
procInst.getCreatorDeptId());
Assert.assertEquals(FireWorkflowSystem.getInstance().getDeptName(),
procInst.getCreatorDeptName());
Assert.assertNotNull(procInst.getCreatedTime());
Assert.assertNotNull(procInst.getEndTime());
Assert.assertNull(procInst.getParentActivityInstanceId());
Assert.assertNull(procInst.getParentProcessInstanceId());
Assert.assertNull(procInst.getParentScopeId());
Assert.assertNull(procInst.getNote());
// 验证Token信息
WorkflowQuery<Token> q4Token = session.createWorkflowQuery(Token.class);
q4Token.add(
Restrictions.eq(TokenProperty.PROCESS_INSTANCE_ID,
processInstanceId)).addOrder(
Order.asc(TokenProperty.STEP_NUMBER));
List<Token> tokenList = q4Token.list();
Assert.assertNotNull(tokenList);
Assert.assertEquals(6, tokenList.size());
Token procInstToken = tokenList.get(0);
Assert.assertEquals(processName+WorkflowElement.ID_SEPARATOR+WorkflowProcess.MAIN_PROCESS_NAME, procInstToken.getElementId());
Assert.assertEquals(processInstanceId,
procInstToken.getElementInstanceId());
Assert.assertEquals(processName, procInstToken.getProcessId());
Assert.assertEquals(FpdlConstants.PROCESS_TYPE_FPDL20,
procInstToken.getProcessType());
Assert.assertEquals(new Integer(1), procInstToken.getVersion());
Assert.assertEquals(TokenState.COMPLETED, procInstToken.getState());
Assert.assertNull(procInstToken.getParentTokenId());
Assert.assertTrue(procInstToken.isBusinessPermitted());
Assert.assertEquals(procInst.getTokenId(), procInstToken.getId());
Token startNodeToken = tokenList.get(1);
Assert.assertEquals(processName, startNodeToken.getProcessId());
Assert.assertEquals(new Integer(1), startNodeToken.getVersion());
Assert.assertEquals(FpdlConstants.PROCESS_TYPE_FPDL20,
startNodeToken.getProcessType());
Assert.assertEquals(procInstToken.getId(),
startNodeToken.getParentTokenId());
Assert.assertTrue(startNodeToken.isBusinessPermitted());
Token activity1Token = tokenList.get(3);
// 验证ActivityInstance信息
WorkflowQuery<ActivityInstance> q4ActInst = session
.createWorkflowQuery(ActivityInstance.class);
q4ActInst.add(
Restrictions.eq(ActivityInstanceProperty.PROCESS_INSTANCE_ID,
processInstanceId)).add(
Restrictions.eq(ActivityInstanceProperty.NODE_ID, processName
+WorkflowElement.ID_SEPARATOR+WorkflowProcess.MAIN_PROCESS_NAME+ ".Activity1"));
List<ActivityInstance> actInstList = q4ActInst.list();
Assert.assertNotNull(actInstList);
Assert.assertEquals(1, actInstList.size());
ActivityInstance activityInstance = actInstList.get(0);
Assert.assertEquals(bizId, activityInstance.getBizId());
Assert.assertEquals("Activity1", activityInstance.getName());
Assert.assertEquals("Activity1", activityInstance.getDisplayName());
Assert.assertEquals(processInstanceId,
activityInstance.getParentScopeId());
Assert.assertNotNull(activityInstance.getCreatedTime());
Assert.assertNotNull(activityInstance.getStartedTime());
Assert.assertNotNull(activityInstance.getEndTime());
Assert.assertNotNull(activityInstance.getExpiredTime());
Assert.assertNotNull(activityInstance.getTokenId());
Assert.assertEquals(activity1Token.getId(),
activityInstance.getTokenId());
Assert.assertEquals(activity1Token.getElementId(),
activityInstance.getNodeId());
Assert.assertEquals(activity1Token.getElementInstanceId(),
activityInstance.getId());
Assert.assertNotNull(activityInstance.getScopeId());
Assert.assertEquals(new Integer(1), activityInstance.getVersion());
Assert.assertEquals(FpdlConstants.PROCESS_TYPE_FPDL20,
activityInstance.getProcessType());
Assert.assertEquals(procInst.getProcessName(),
activityInstance.getProcessName());
Assert.assertEquals(procInst.getProcessDisplayName(),
activityInstance.getProcessDisplayName());
Assert.assertEquals(ActivityInstanceState.COMPLETED, activityInstance.getState());
}
/*
* Start-->CallbackService-->End
*
* @see org.fireflow.FireWorkflowJunitEnviroment#createWorkflowProcess()
*/
@Override
public WorkflowProcess createWorkflowProcess() {
WorkflowProcessImpl process = new WorkflowProcessImpl(processName,processDisplayName);
process.setDescription(description);
SubProcess mainflow = process.getMainSubProcess();
PropertyImpl property = new PropertyImpl(mainflow,"id");//流程变量x
property.setDataType(new QName(NameSpaces.JAVA.getUri(),"java.lang.String"));
property.setInitialValueAsString("");
mainflow.getProperties().add(property);
property = new PropertyImpl(mainflow,"response");//流程变量x
property.setDataType(new QName(NameSpaces.JAVA.getUri(),"java.lang.String"));
property.setInitialValueAsString("OK");
mainflow.getProperties().add(property);
property = new PropertyImpl(mainflow,"approveResult");//流程变量x
property.setDataType(new QName(NameSpaces.JAVA.getUri(),"java.lang.String"));
property.setInitialValueAsString("");
mainflow.getProperties().add(property);
mainflow.setDuration(new Duration(5,Duration.MINUTE));
StartNodeImpl startNode = new StartNodeImpl(process.getMainSubProcess(),"Start");
ActivityImpl activity = new ActivityImpl(process.getMainSubProcess(),"Activity1");
activity.setDuration(new Duration(6,Duration.DAY));
EndNodeImpl endNode = new EndNodeImpl(process.getMainSubProcess(),"End");
mainflow.setEntry(startNode);
mainflow.getStartNodes().add(startNode);
mainflow.getActivities().add(activity);
mainflow.getEndNodes().add(endNode);
TransitionImpl transition1 = new TransitionImpl(process.getMainSubProcess(),"start2activity");
transition1.setFromNode(startNode);
transition1.setToNode(activity);
startNode.getLeavingTransitions().add(transition1);
activity.getEnteringTransitions().add(transition1);
TransitionImpl transition2 = new TransitionImpl(process.getMainSubProcess(),"activity2end");
transition2.setFromNode(activity);
transition2.setToNode(endNode);
activity.getLeavingTransitions().add(transition2);
endNode.getEnteringTransitions().add(transition2);
mainflow.getTransitions().add(transition1);
mainflow.getTransitions().add(transition2);
//创建CallbackService 并绑定到StartNode
CallbackService callbackService = new CallbackService();
callbackService.setName(serviceName);
callbackService.setTargetNamespaceUri(this.targetNsUri);
CommonInterfaceDef commonInterface = new CommonInterfaceDef();
commonInterface.setName(interfaceName);
callbackService.setInterface(commonInterface);
OperationDefImpl op = new OperationDefImpl();
op.setOperationName("accept");
commonInterface.getOperations().add(op);
InputImpl input = new InputImpl();
input.setName("id");
input.setDataType(new QName(NameSpaces.XSD.getUri(),"string"));
op.getInputs().add(input);
input = new InputImpl();
input.setName("approveResult");
input.setDataType(new QName(NameSpaces.XSD.getUri(),"string"));
op.getInputs().add(input);
OutputImpl output = new OutputImpl();
output.setName("response1");
output.setDataType(new QName(NameSpaces.XSD.getUri(),"string"));
op.getOutputs().add(output);
output = new OutputImpl();
output.setName("response2");
output.setDataType(new QName(NameSpaces.XSD.getUri(),"string"));
op.getOutputs().add(output);
//对于启动流程的callback service,Correlation用于设置bizId
ExpressionImpl correlation = new ExpressionImpl();
correlation.setLanguage("JEXL");
correlation.setBody("Xpath:getValue('"+ScriptContextVariableNames.INPUTS+
"/ns0:"+op.getOperationName()+"Request/ns0:id')");
correlation.getNamespaceMap().put("ns0",callbackService.getTargetNamespaceUri());
callbackService.setCorrelation(correlation);
//绑定
ServiceBindingImpl svcBinding = new ServiceBindingImpl();
// svcBinding.setService(callbackService);
svcBinding.setServiceId(callbackService.getId());
// svcBinding.setOperation(op);
svcBinding.setOperationName(op.getOperationName());
//io输入映射
// id-->processVars.id
AssignmentImpl assignment = new AssignmentImpl();
ExpressionImpl from = new ExpressionImpl();
from.setBody(ScriptContextVariableNames.INPUTS+"/ns0:"+op.getOperationName()+"Request/ns0:id");
from.setLanguage("XPATH");
from.getNamespaceMap().put("ns0",callbackService.getTargetNamespaceUri());
assignment.setFrom(from);
ExpressionImpl to = new ExpressionImpl();
to.setBody(ScriptContextVariableNames.PROCESS_VARIABLES+"/"+"id");
to.setLanguage("XPATH");
assignment.setTo(to);
svcBinding.getInputAssignments().add(assignment);
// approveResult-->processVars.approveResult
assignment = new AssignmentImpl();
from = new ExpressionImpl();
from.setBody(ScriptContextVariableNames.INPUTS+"/ns0:"+op.getOperationName()+"Request/ns0:approveResult");
from.setLanguage("XPATH");
from.getNamespaceMap().put("ns0",callbackService.getTargetNamespaceUri());
assignment.setFrom(from);
to = new ExpressionImpl();
to.setBody(ScriptContextVariableNames.PROCESS_VARIABLES+"/"+"approveResult");
to.setLanguage("XPATH");
assignment.setTo(to);
svcBinding.getInputAssignments().add(assignment);
//io输出映射
// currentProcessInstance.id-->response1
assignment = new AssignmentImpl();
from = new ExpressionImpl();
from.setBody(ScriptContextVariableNames.CURRENT_PROCESS_INSTANCE+"/id");
from.setLanguage("XPATH");
assignment.setFrom(from);
to = new ExpressionImpl();
to.setBody(ScriptContextVariableNames.OUTPUTS+"/ns0:"+op.getOperationName()+"Response/ns0:response1");
to.setLanguage("XPATH");
to.getNamespaceMap().put("ns0", callbackService.getTargetNamespaceUri());
assignment.setTo(to);
svcBinding.getOutputAssignments().add(assignment);
// processVars.response-->response2
assignment = new AssignmentImpl();
from = new ExpressionImpl();
from.setBody(ScriptContextVariableNames.PROCESS_VARIABLES+"/response");
from.setLanguage("XPATH");
assignment.setFrom(from);
to = new ExpressionImpl();
to.setBody(ScriptContextVariableNames.OUTPUTS+"/ns0:"+op.getOperationName()+"Response/ns0:response2");
to.setLanguage("XPATH");
to.getNamespaceMap().put("ns0", callbackService.getTargetNamespaceUri());
assignment.setTo(to);
svcBinding.getOutputAssignments().add(assignment);
//设置到activity和workflowprocess
process.addService(callbackService);
WebserviceStartFeatureImpl feature = new WebserviceStartFeatureImpl();
feature.setServiceBinding(svcBinding);
startNode.setFeature(feature);
return process;
}
}