Hi Demian,
not sure what type of configuration you want me to share.
If you need any other information, please let me know.
Spring 3.0.1
Jbpm 5.1.0-Final
JPA 1.2
Hibernate 3.3.2.GA
/**
* Todos os direitos reservados para Softway.
*
* Data de criacao: 27/06/2011 16:12:28
*/
package br.com.softcomex.components.workflow.service.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.transaction.TransactionManager;
import org.drools.KnowledgeBase;
import org.drools.KnowledgeBaseFactory;
import org.drools.SystemEventListener;
import org.drools.SystemEventListenerFactory;
import org.drools.builder.KnowledgeBuilder;
import org.drools.builder.KnowledgeBuilderFactory;
import org.drools.builder.ResourceType;
import org.drools.io.ResourceFactory;
import org.drools.logger.KnowledgeRuntimeLogger;
import org.drools.logger.KnowledgeRuntimeLoggerFactory;
import org.drools.persistence.jpa.JPAKnowledgeService;
import org.drools.runtime.Environment;
import org.drools.runtime.EnvironmentName;
import org.drools.runtime.KnowledgeSessionConfiguration;
import org.drools.runtime.StatefulKnowledgeSession;
import org.drools.runtime.process.ProcessInstance;
import org.drools.spi.ProcessContext;
import org.jbpm.process.audit.JPAProcessInstanceDbLog;
import org.jbpm.process.audit.JPAWorkingMemoryDbLogger;
import org.jbpm.process.workitem.wsht.CommandBasedWSHumanTaskHandler;
import org.jbpm.task.Status;
import org.jbpm.task.query.TaskSummary;
import org.jbpm.task.service.TaskClient;
import org.jbpm.task.service.TaskServer;
import org.jbpm.task.service.TaskService;
import org.jbpm.task.service.mina.MinaTaskClientConnector;
import org.jbpm.task.service.mina.MinaTaskClientHandler;
import org.jbpm.task.service.mina.MinaTaskServer;
import org.jbpm.task.service.responsehandlers.BlockingTaskOperationResponseHandler;
import org.jbpm.task.service.responsehandlers.BlockingTaskSummaryResponseHandler;
import br.com.softcomex.components.log.SfwLogger;
import br.com.softcomex.components.log.SfwLoggerFactory;
import br.com.softcomex.components.workflow.service.SfwJbpmWorkFlow;
/**
*
* Implementação da classe responsável por criar o ambiente do JBPM.
*
* @author João Augusto Charnet *
*/
public class SfwJbpmWorkFlowImpl implements SfwJbpmWorkFlow {
/**
* Log.
*/
private SfwLogger sfwLogger = SfwLoggerFactory.getLogger(getClass());
/**
* Entity Manager Factory injetado.
*/
private EntityManagerFactory emf;
/**
* Transação.
*/
private TransactionManager transactionManager;
/**
* Sessão da base de conhecimento do JBPM.
*/
private StatefulKnowledgeSession kSession;
/**
* Thread do servidor de tarefa humana.
*/
private TaskServer humanTaskServerThread;
/**
* Porta do sevidor de tarefa humana.
*/
private int humanTaskServerPort = -1;
/**
* Endereço do Servidor de tarefa humana.
*/
private String humanTaskServerLocalAddress = "127.0.0.1";
/**
* Lista com os jbpm que precisa ser carregado.
*/
private List workFlowResourcesList;
/**
* Responsável por se comunicar com o servidor de tarefas humanas.
*/
private TaskClient taskClient;
/**
* Contexto do processo.
*/
/**
* Construtor padrão.
*/
public SfwJbpmWorkFlowImpl() {
}
@Override
public void prepareSession() {
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
for (String resource : this.workFlowResourcesList) {
kbuilder.add(ResourceFactory.newClassPathResource(resource), ResourceType.BPMN2);
}
KnowledgeBase kbase = kbuilder.newKnowledgeBase();
Environment env = KnowledgeBaseFactory.newEnvironment();
env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, this.emf);
env.set(EnvironmentName.TRANSACTION_MANAGER,
this.transactionManager);
// Human Task
SystemEventListener systemEventListener = SystemEventListenerFactory.getSystemEventListener();
TaskService taskService = new TaskService(this.emf, systemEventListener);
this.startHumanTaskServer(taskService);
Properties properties = new Properties();
properties.put("drools.processInstanceManagerFactory", "org.jbpm.persistence.processinstance.JPAProcessInstanceManagerFactory");
properties.put("drools.processSignalManagerFactory", "org.jbpm.persistence.processinstance.JPASignalManagerFactory");
KnowledgeSessionConfiguration config = KnowledgeBaseFactory.newKnowledgeSessionConfiguration(properties);
StatefulKnowledgeSession ksession =
JPAKnowledgeService.newStatefulKnowledgeSession(kbase, config, env);
//this will log in audit tables
JPAWorkingMemoryDbLogger jpaWorkingMemoryLog = new JPAWorkingMemoryDbLogger(ksession);
JPAProcessInstanceDbLog processLog = new JPAProcessInstanceDbLog(ksession.getEnvironment());
KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newConsoleLogger(ksession);
CommandBasedWSHumanTaskHandler humanTask = new CommandBasedWSHumanTaskHandler(ksession);
humanTask.setConnection(this.humanTaskServerLocalAddress, this.humanTaskServerPort);
ksession.getWorkItemManager().registerWorkItemHandler("Human Task", humanTask);
this.setkSession(ksession);
}
/**
* Inicia o servidor para a tarefa humana.
*
* @param taskService Serviço da tarefa.
*/
private void startHumanTaskServer(TaskService taskService) {
if (this.humanTaskServerPort <= 0) {
this.humanTaskServerPort = SfwJbpmWorkFlow.DEFAULT_HUMAN_TASK_SERVER_PORT;
}
this.sfwLogger.debug("Iniciando Human Task Server! ip [ " + this.humanTaskServerLocalAddress + "] port [" + this.humanTaskServerPort +"]");
this.humanTaskServerThread = new MinaTaskServer(taskService, this.humanTaskServerPort);
Thread thread = new Thread(this.humanTaskServerThread);
thread.start();
}
@Override
public void stopHumanTaskServer() throws Exception {
if (this.humanTaskServerThread != null &&
this.humanTaskServerThread.isRunning()) {
this.taskClient.disconnect();
this.humanTaskServerThread.stop();
this.sfwLogger.debug("Encerrando Human Task Server!");
}
}
@Override
public void setHumanTaskServerPort(int humanTaskServerPort) {
this.humanTaskServerPort = humanTaskServerPort;
}
@Override
public int getHumanTaskServerPort() {
return humanTaskServerPort;
}
@Override
public EntityManagerFactory getEmf() {
return emf;
}
@Override
public void setEmf(EntityManagerFactory emf) {
this.emf = emf;
}
@Override
public void setkSession(StatefulKnowledgeSession kSession) {
this.kSession = kSession;
}
@Override
public StatefulKnowledgeSession getkSession() {
return kSession;
}
@Override
public void setTransactionManager(TransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
@Override
public TransactionManager getTransactionManager() {
return transactionManager;
}
@Override
public ProcessInstance startProcess(String processId, Map params) {
return this.kSession.startProcess(processId, params);
}
@Override
public void setWorkFlowResourcesList(List workFlowResourcesList) {
this.workFlowResourcesList = workFlowResourcesList;
}
@Override
public List getWorkFlowResourcesList() {
return workFlowResourcesList;
}
@Override
public void addWorkFlowResource(String workFlowResource) {
if (this.workFlowResourcesList == null) {
this.workFlowResourcesList = new ArrayList();
}
this.workFlowResourcesList.add(workFlowResource);
}
@Override
public String getHumanTaskServerLocalAddress() {
return humanTaskServerLocalAddress;
}
@Override
public void setHumanTaskServerLocalAddress(String humanTaskServerLocalAddress) {
this.humanTaskServerLocalAddress = humanTaskServerLocalAddress;
}
@Override
public ProcessContext getProcessContext() {
ProcessContext procContext = new ProcessContext(this.kSession);
return procContext;
}
/**
* Cria um TaskClient conectando no servido de tarefa humana.
* @return TaskClient TaskClient.
*/
private TaskClient createTaskClient() {
if (this.taskClient == null) {
this.taskClient = new TaskClient(new MinaTaskClientConnector("SfwTaskClient",
new MinaTaskClientHandler(SystemEventListenerFactory.getSystemEventListener())));
boolean connected = this.taskClient.connect(this.humanTaskServerLocalAddress, this.humanTaskServerPort);
if (!connected) {
this.sfwLogger.error("Não foi possível conectar no servidor de tarefa humana. Server [" + this.humanTaskServerLocalAddress + "] - Port [" + this.humanTaskServerPort + "]");
}
}
return this.taskClient;
}
@Override
public TaskClient getTaskClient() {
return taskClient;
}
@Override
public void setTaskClient(TaskClient taskClient) {
this.taskClient = taskClient;
}
@Override
public List getTasksByUser(String user) {
this.createTaskClient();
BlockingTaskSummaryResponseHandler taskSummaryResponseHandler =
new BlockingTaskSummaryResponseHandler();
this.taskClient.getTasksAssignedAsPotentialOwner(user, "en-UK", taskSummaryResponseHandler);
final int oneSec = 1000;
taskSummaryResponseHandler.waitTillDone(oneSec);
List tasks = taskSummaryResponseHandler.getResults();
return tasks;
}
/**
* Cria uma TaskClient, caso necessário e retorna um taskResponseHandler
* para se comunicar com o servidor de tarefa humana.
*
* @return BlockingTaskOperationResponseHandler
*/
private BlockingTaskOperationResponseHandler createTaskClientAndReturnTaskOperationResponseHandler() {
this.createTaskClient();
BlockingTaskOperationResponseHandler taskResponseHandler =
new BlockingTaskOperationResponseHandler();
return taskResponseHandler;
}
@Override
public void completeTask(List tasks, String user) {
for (TaskSummary task : tasks) {
this.sfwLogger.debug("Completando tarefa [" + task.getName() + "] do usuário [" + user + "]");
this.completeTask(task, user);
}
}
@Override
public void completeTask(TaskSummary task, String user) {
BlockingTaskOperationResponseHandler taskResponseHandler =
this.createTaskClientAndReturnTaskOperationResponseHandler();
this.taskClient.complete(task.getId(), user, null, taskResponseHandler);
final int oneSec = 1000;
taskResponseHandler.waitTillDone(oneSec);
}
@Override
public void failTask(TaskSummary task, String user) {
BlockingTaskOperationResponseHandler taskResponseHandler =
this.createTaskClientAndReturnTaskOperationResponseHandler();
this.taskClient.fail(task.getId(), user, null, taskResponseHandler);
final int oneSec = 1000;
taskResponseHandler.waitTillDone(oneSec);
}
@Override
public void suspendTask(TaskSummary task, String user) {
BlockingTaskOperationResponseHandler taskResponseHandler =
this.createTaskClientAndReturnTaskOperationResponseHandler();
this.taskClient.suspend(task.getId(), user, taskResponseHandler);
}
@Override
public void startTask(TaskSummary task,
String user) {
BlockingTaskOperationResponseHandler taskResponseHandler =
this.createTaskClientAndReturnTaskOperationResponseHandler();
if (!task.getStatus().equals(Status.InProgress)) {
this.taskClient.start(task.getId(), user, taskResponseHandler);
final int oneSec = 1000;
taskResponseHandler.waitTillDone(oneSec);
}
}
@Override
public void stopTask(TaskSummary task,
String user) {
BlockingTaskOperationResponseHandler taskResponseHandler =
this.createTaskClientAndReturnTaskOperationResponseHandler();
this.taskClient.stop(task.getId(), user, taskResponseHandler);
final int oneSec = 1000;
taskResponseHandler.waitTillDone(oneSec);
}
@Override
public void releaseTask(TaskSummary task,
String user) {
BlockingTaskOperationResponseHandler taskResponseHandler =
this.createTaskClientAndReturnTaskOperationResponseHandler();
this.taskClient.release(task.getId(), user, taskResponseHandler);
final int oneSec = 1000;
taskResponseHandler.waitTillDone(oneSec);
}
@Override
public void resumeTask(TaskSummary task,
String user) {
BlockingTaskOperationResponseHandler taskResponseHandler =
this.createTaskClientAndReturnTaskOperationResponseHandler();
this.taskClient.resume(task.getId(), user, taskResponseHandler);
final int oneSec = 1000;
taskResponseHandler.waitTillDone(oneSec);
}
@Override
public void skipTask(TaskSummary task,
String user) {
BlockingTaskOperationResponseHandler taskResponseHandler =
this.createTaskClientAndReturnTaskOperationResponseHandler();
this.taskClient.skip(task.getId(), user, taskResponseHandler);
final int oneSec = 1000;
taskResponseHandler.waitTillDone(oneSec);
}
@Override
public void claimTask(TaskSummary task,
String user) {
BlockingTaskOperationResponseHandler taskResponseHandler =
this.createTaskClientAndReturnTaskOperationResponseHandler();
this.taskClient.claim(task.getId(), user, taskResponseHandler);
final int oneSec = 1000;
taskResponseHandler.waitTillDone(oneSec);
}
}
Unit Test case
/**
* Todos os direitos reservados para Softway.
*
* Data de criacao: 28/06/2011 15:18:56
*/
package br.com.softcomex.components.workflow.service.impl;
import java.net.ConnectException;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
import junit.framework.Assert;
import org.drools.runtime.process.ProcessInstance;
import org.drools.runtime.process.WorkItem;
import org.drools.runtime.process.WorkItemHandler;
import org.drools.runtime.process.WorkItemManager;
import org.drools.spi.ProcessContext;
import org.jbpm.task.query.TaskSummary;
import org.junit.BeforeClass;
import org.junit.Test;
import bitronix.tm.TransactionManagerServices;
import bitronix.tm.resource.jdbc.PoolingDataSource;
import br.com.softcomex.components.workflow.service.SfwJbpmWorkFlow;
import br.com.softcomex.test.serviceeao.SfwBaseServiceTestCase;
/**
* Classe de teste do serviço SfwJbmWorkFlowImpl.
*
* @author João Augusto Charnet *
*/
public class SfwJbpmWorkFlowImplTest extends SfwBaseServiceTestCase {
/**
* Serviço.
*/
@Inject
private SfwJbpmWorkFlow sfwWorkFlow;
/**
* Prepara o datasource.
*/
@BeforeClass
public static void prepareDatasource() {
PoolingDataSource ds = new PoolingDataSource();
ds.setUniqueName("localDataSource");
ds.setClassName("oracle.jdbc.xa.client.OracleXADataSource");
ds.setMaxPoolSize(3);
ds.setAllowLocalTransactions(true);
ResourceBundle rb = ResourceBundle.getBundle("jdbc");
ds.getDriverProperties().put("user", rb.getString("jdbc.username"));
ds.getDriverProperties().put("password", rb.getString("jdbc.password"));
ds.getDriverProperties().put("URL", rb.getString("jdbc.url"));
ds.init();
}
/**
* Teste.
* @throws Exception Exceção.
*/
@Test
public void testJbpmWorkFlow() throws Exception {
this.sfwWorkFlow.setTransactionManager(TransactionManagerServices.getTransactionManager());
this.sfwWorkFlow.getTransactionManager().begin();
//this.sfwWorkFlow.setHumanTaskServerPort(1234);
this.sfwWorkFlow.addWorkFlowResource("test.bpmn");
this.sfwWorkFlow.addWorkFlowResource("testHumanTask.bpmn");
this.sfwWorkFlow.prepareSession();
MyAutomaticHumanSimulatorWorkItemHandler workHandler = new MyAutomaticHumanSimulatorWorkItemHandler();
TestWorkItemHandler workItemHandler = new TestWorkItemHandler();
//this.sfwWorkFlow.getkSession().getWorkItemManager().registerWorkItemHandler("Human Task", workHandler);
Socket socket = new Socket("127.0.0.1", this.sfwWorkFlow.getHumanTaskServerPort());
Assert.assertNotNull(socket);
Map params = new HashMap();
params.put("ator", "Joao");
params.put("responsible", "Joao");
//ProcessInstance processInstance = this.sfwWorkFlow.startProcess("test.bpmn", params);
ProcessInstance processInstance = this.sfwWorkFlow.startProcess("testHumanTask", params);
Thread.currentThread().sleep(3000);
List tasks = this.sfwWorkFlow.getTasksByUser("John");
this.sfwWorkFlow.startTask(tasks.get(0), "John");
this.sfwWorkFlow.completeTask(tasks.get(0), "John");
Thread.currentThread().sleep(5000);
Assert.assertEquals(ProcessInstance.STATE_COMPLETED, processInstance.getState());
this.sfwWorkFlow.stopHumanTaskServer();
try {
socket = new Socket("127.0.0.1", this.sfwWorkFlow.getHumanTaskServerPort());
Assert.fail("Esperando exceção, por não ter ninguém escutando na porta do sevidor " + this.sfwWorkFlow.getHumanTaskServerPort());
} catch (ConnectException excep) {
Assert.assertTrue(true);
} finally {
this.sfwWorkFlow.getTransactionManager().rollback();
}
}
}
http://community.jboss.org/servlet/JiveServlet/downloadImage/2-615187-16726/408-442/testHumanTask.JPG
jbpm xml
<?xml version="1.0" encoding="UTF-8"?>
<definitions id="Definition"
targetNamespace="http://www.jboss.org/drools"
typeLanguage="http://www.java.com/javaTypes"
expressionLanguage="http://www.mvel.org/2.0"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
xs:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd"
xmlns:g="http://www.jboss.org/drools/flow/gpd"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:di="http://www.omg.org/spec/DD/20100524/DI"
xmlns:tns="http://www.jboss.org/drools">
<itemDefinition id="_responsibleItem" structureRef="String" />
<process processType="Private" isExecutable="true" id="testHumanTask" name="testHumanTask" >
<!-- process variables -->
<property id="responsible" itemSubjectRef="_responsibleItem"/>
<!-- nodes -->
<startEvent id="_1" name="Start" />
<userTask id="_2" name="User Task" >
<ioSpecification>
<dataInput id="_2_TaskNameInput" name="TaskName" />
<inputSet>
<dataInputRefs> _2_TaskNameInput</dataInputRefs>
</inputSet>
<outputSet>
</outputSet>
</ioSpecification>
<dataInputAssociation>
<targetRef> _2_TaskNameInput</targetRef>
<assignment>
<from xs:type="tFormalExpression"> Test Human Task</from>
<to xs:type="tFormalExpression"> _2_TaskNameInput</to>
</assignment>
</dataInputAssociation>
<potentialOwner>
<resourceAssignmentExpression>
<formalExpression> #{responsible}</formalExpression>
</resourceAssignmentExpression>
</potentialOwner>
</userTask>
<scriptTask id="_3" name="Script" scriptFormat="http://www.java.com/java" >
<script> System.out.println("Script task :" + new java.util.Date());</script>
</scriptTask>
<endEvent id="_4" name="End" >
<terminateEventDefinition/>
</endEvent>
<!-- connections -->
<sequenceFlow id="_1-_2" sourceRef="_1" targetRef="_2" />
<sequenceFlow id="_2-_3" sourceRef="_2" targetRef="_3" />
<sequenceFlow id="_3-_4" sourceRef="_3" targetRef="_4" />
</process>
<bpmndi:BPMNDiagram>
<bpmndi:BPMNPlane bpmnElement="testHumanTask" >
<bpmndi:BPMNShape bpmnElement="_1" >
<dc:Bounds x="51" y="34" width="48" height="48" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_2" >
<dc:Bounds x="165" y="35" width="100" height="48" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_3" >
<dc:Bounds x="176" y="158" width="80" height="48" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_4" >
<dc:Bounds x="191" y="301" width="48" height="48" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="_1-_2" >
<di:waypoint x="75" y="58" />
<di:waypoint x="215" y="59" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_2-_3" >
<di:waypoint x="215" y="59" />
<di:waypoint x="216" y="182" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_3-_4" >
<di:waypoint x="216" y="182" />
<di:waypoint x="215" y="325" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>