[jboss-user] [jBPM] - Re: Human task API, how to move forward in the workflow ?

John Augusto Charnet do-not-reply at jboss.com
Thu Jul 14 09:23:40 EDT 2011


John Augusto Charnet [http://community.jboss.org/people/jcharnet] created the discussion

"Re: Human task API, how to move forward in the workflow ?"

To view the discussion, visit: http://community.jboss.org/message/615187#615187

--------------------------------------------------------------
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  mailto:jcharnet at sfw.com.br 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  mailto:jcharnet at sfw.com.br 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/showImage/2-615187-16726/testHumanTask.JPG  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>                                                                                                                                 
--------------------------------------------------------------

Reply to this message by going to Community
[http://community.jboss.org/message/615187#615187]

Start a new discussion in jBPM at Community
[http://community.jboss.org/choose-container!input.jspa?contentType=1&containerType=14&container=2034]

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/jboss-user/attachments/20110714/4eb82d6a/attachment-0001.html 


More information about the jboss-user mailing list