Um guia para a Activiti com Java

Um guia para a Activiti com Java

1. Visão geral

A API da Activiti é um sistema de fluxo de trabalho e gerenciamento de processos de negócios. Podemos definir um processo nele, executá-lo e manipulá-lo de diferentes maneiras, usando os serviços fornecidos pela API. Requer JDK 7+.

O desenvolvimento usando a API pode ser feito em qualquer IDE, mas para usar oActiviti Designer, precisamos do Eclipse.

Podemos definir um processo usando o padrão BPMN 2.0. Existe outra maneira menos popular - usando classes Java comoStartEvent,EndEvent,UserTask,SequenceFlow, etc.

Se quisermos executar um processo ou acessar algum dos serviços, precisamos criar umProcessEngineConfiguration.

Podemos obterProcessEngine usandoProcessEngineConfiguration, de algumas maneiras, que discutiremos mais a fundo neste artigo. Por meio de_ the _ProcessEngine, podemos realizar o fluxo de trabalho e as operações BPMN.

2. Dependências do Maven

Para usar esta API, precisamos incluir a dependência da Activiti:


    org.activiti
    activiti-engine

3. Criando umProcessEngine

ProcessEngine no Activiti, normalmente é configurado usando um arquivo XML,activiti.cfg.xml. Um exemplo desse arquivo de configuração é:


    
        
        
        
        
        
    

Agora podemos obter oProcessEngine usando a classeProcessEngines:

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

Esta instrução procurará um arquivoactiviti.cfg.xml no caminho de classe e construirá umProcessEngine com base na configuração do arquivo.

O código de amostra para o arquivo de configuração mostra que é apenas uma configuração baseada em Spring. Mas isso não significa que só podemos usar o Activiti em um ambiente Spring. Os recursos do Spring são usados ​​apenas internamente para criarProcessEngine.

Vamos escrever um caso de teste JUnit que criará oProcessEngine usando o arquivo de configuração mostrado acima:

@Test
public void givenXMLConfig_whenGetDefault_thenGotProcessEngine() {
    ProcessEngine processEngine
      = ProcessEngines.getDefaultProcessEngine();
    assertNotNull(processEngine);
    assertEquals("root", processEngine.getProcessEngineConfiguration()
      .getJdbcUsername());
}

4. API e serviços do Activiti Process Engine

O ponto de entrada da interação com a API é oProcessEngine. Por meio doProcessEngine,, podemos acessar vários serviços que fornecem métodos de fluxo de trabalho / BPMN. OProcessEnginee todos os objetos de serviço são thread-safe.

image

A classeProcessEngines procurará os arquivosactiviti.cfg.xmleactiviti-context.xml. Conforme mencionado anteriormente, para todos os arquivosactiviti.cfg.xml, osProcessEngine serão criados de maneira típica.

Considerando que, para todos os arquivosactiviti-context.xml, ele será criado no modo Spring - criarei o Contexto do aplicativo Spring e obtereiProcessEngine a partir dele. Durante a execução de um processo, todas as etapas serão visitadas na ordem definida no arquivo BPMN.

Durante a execução de um processo, todas as etapas serão visitadas na ordem definida no arquivo BPMN.

A ProcessDefinition represents a business process. É usado para definir a estrutura e o comportamento das diferentes etapas do processo. A implantação de uma definição de processo significa carregar a definição de processo no banco de dados do Activiti.

As definições de processo são definidas principalmente pelo padrão BPMN 2.0. Também é possível defini-los usando o código Java. Todos os termos definidos nesta seção também estão disponíveis como classes Java.

Quando começamos a executar uma definição de processo, ela pode ser chamada de processo

UmProcessInstance é uma execução de umProcessDefinition.

A StartEvent is associated with every business process. It indicates the entry point of the process. Da mesma forma, existe umEndEvent que indica o fim do processo. Podemos definir condições sobre esses eventos.

Todas as etapas (ou elementos) entre o início e o fim são chamados deTasks. Tasks pode ser de vários tipos. As tarefas mais comumente usadas sãoUserTaskseServiceTasks.

UserTasks, como o nome sugere, são tais que precisam ser executados manualmente por um usuário.

ServiceTasks, por outro lado, são configurados com um trecho de código. Sempre que a execução os alcançar, seu bloco de código será executado.

SequenceFlows conectaTasks. Podemos definir oSequenceFlows pelos elementos de origem e destino que eles irão conectar. Novamente, também podemos definir condições sobreSequenceFlows para criar caminhos condicionais no processo.

4.2. Serviços

Discutiremos brevemente os serviços prestados pela Activiti:

  • RepositoryService nos ajuda a manipular a implantação de definições de processo. Este serviço lida com os dados estáticos relacionados a uma definição de processo

  • RuntimeService gerenciaProcessInstances (processos atualmente em execução), bem como as variáveis ​​do processo

  • TaskService mantém o controle deUserTasks. OsTasks que precisam ser executados manualmente por um usuário estão no centro da API do Activiti. Podemos criar uma tarefa, reivindicar e concluir uma tarefa, manipular o responsável pela tarefa etc. usando este serviço

  • FormService é um serviço opcional. A API pode ser usada sem ela e sem sacrificar nenhum de seus recursos. É usado para definir o formulário inicial e o formulário da tarefa em um processo.

  • IdentityService gerenciaUsers eGroups

  • HistoryService mantém um registro do histórico do Motor Activiti. Também podemos definir diferentes níveis de histórico.

  • ManagementService está relacionado aos metadados e geralmente não é necessário ao criar um aplicativo

  • DynamicBpmnService nos ajuda a mudar qualquer coisa em um processo sem redistribuí-lo

5. Trabalhando com Activiti Services

Para aprender como podemos trabalhar com diferentes serviços e executar um processo, vamos dar um exemplo de processo para "Solicitação de férias do funcionário":

image

O arquivo BPMN 2.0,VacationRequest.bpmn20.xml, para este processo terá o evento de início definido como:


    
        
        
        
     

Da mesma forma, a primeira tarefa do usuário, atribuída ao grupo de usuários "gerenciamento", terá a seguinte aparência:


    ${employeeName} would like to take ${numberOfDays} day(s)
      of vacation (Motivation: ${reason}).
    
        
        
    
    
      
        management
      
    

Com oServiceTask,, precisamos definir o trecho de código a ser executado. Temos esse pedaço de código como uma classe Java:


O fluxo condicional será mostrado adicionando a tag“conditionExpression” no“sequenceFlow”:


    
      
    

Aqui,vacationApproved é oformProperty deUserTask mostrado acima.

Como podemos ver no diagrama, é um processo muito simples. O funcionário faz uma solicitação de férias, fornecendo o número de dias e a data de início das férias. A solicitação vai para o gerente. Eles podem aprovar / desaprovar a solicitação.

Se aprovado, há uma tarefa de Serviço definida para enviar o email de confirmação. Se reprovado, o Funcionário pode optar por modificar e reenviar a solicitação ou não fazer nada.

As tarefas de serviço são fornecidas com algum trecho de código a ser executado (aqui, como uma classe Java). Demos a classeSendEmailServiceTask.java.

Esses tipos de classes devem estenderJavaDelegate.. Além disso, precisamos sobrescrever seu métodoexecute(), que será executado quando a execução do processo atingir esta etapa.

5.1. Implantando um Processo

Para tornar nosso processo conhecido pelo mecanismo da Activiti, precisamos implantar o processo. Podemos fazer isso programaticamente usando oRepositoryService.. Vamos escrever um teste JUnit para mostrar isso:

@Test
public void givenBPMN_whenDeployProcess_thenDeployed() {
    ProcessEngine processEngine
      = ProcessEngines.getDefaultProcessEngine();
    RepositoryService repositoryService
      = processEngine.getRepositoryService();
    repositoryService.createDeployment()
      .addClasspathResource(
      "org/activiti/test/vacationRequest.bpmn20.xml")
      .deploy();
    Long count=repositoryService.createProcessDefinitionQuery().count();
    assertEquals("1", count.toString());
}

Implantação significa que o mecanismo analisará o arquivo BPMN e o converterá em algo executável. Além disso, um registro será adicionado à tabela Repositório para cada implantação.

Portanto, depois disso, podemos consultar o serviçoRepository para obter os processos implantados; oProcessDefinitions.

5.2. Iniciando umProcessInstance

Depois de implantar oProcessDefinition no Activiti Engine, podemos executar o processo criandoProcessInstances. OProcessDefinition é um blueprint e oProcessInstance é a execução em tempo de execução dele.

Para um únicoProcessDefinition, pode haver váriosProcessInstances.

Todos os detalhes relacionados aoProcessInstances podem ser acessados ​​por meio doRuntimeService.

Em nosso exemplo, no evento de início, precisamos passar o número de dias de férias, a data de início e o motivo. Vamos usar as variáveis ​​de processo e passá-las ao criar oProcessInstance.

Vamos escrever um caso de teste JUnit para ter uma ideia melhor:

@Test
public void givenDeployedProcess_whenStartProcessInstance_thenRunning() {
    //deploy the process definition
    Map variables = new HashMap>();
    variables.put("employeeName", "John");
    variables.put("numberOfDays", 4);
    variables.put("vacationMotivation", "I need a break!");

    RuntimeService runtimeService = processEngine.getRuntimeService();
    ProcessInstance processInstance = runtimeService
      .startProcessInstanceByKey("vacationRequest", variables);
    Long count=runtimeService.createProcessInstanceQuery().count();

    assertEquals("1", count.toString());
}

As várias instâncias de uma única definição de processo serão diferentes pelas variáveis ​​do processo.

Existem várias maneiras de iniciar uma instância do processo. Aqui, estamos usando a chave do processo. Depois de iniciar a instância do processo, podemos obter as informações sobre ele consultandoRuntimeService.

5.3. Concluindo Tarefas

Quando nossa instância de processo começa a ser executada, a primeira etapa é uma tarefa do usuário, atribuída ao grupo de usuários“management”.

O usuário pode ter uma caixa de entrada com uma lista de tarefas a serem executadas por eles. Agora, se quisermos continuar a execução do processo, o usuário precisará concluir esta tarefa. Para o Activiti Engine, é chamado de “completar a tarefa”.

Podemos consultarTaskService, para obter o objeto de tarefa e concluí-lo.

O código que precisamos escrever para isso se parece com:

@Test
public void givenProcessInstance_whenCompleteTask_thenGotNextTask() {
    // deploy process and start process instance
    TaskService taskService = processEngine.getTaskService();
    List tasks = taskService.createTaskQuery()
      .taskCandidateGroup("management").list();
    Task task = tasks.get(0);

    Map taskVariables = new HashMap<>();
    taskVariables.put("vacationApproved", "false");
    taskVariables.put("comments", "We have a tight deadline!");
    taskService.complete(task.getId(), taskVariables);

    Task currentTask = taskService.createTaskQuery()
      .taskName("Modify vacation request").singleResult();
    assertNotNull(currentTask);
}

Observe que o métodocomplete() deTaskService também leva nas variáveis ​​de processo necessárias. Passamos a resposta do gerente.

Depois disso, o mecanismo de processo continuará na próxima etapa. Aqui, a próxima etapa pergunta ao funcionário se a solicitação de férias deve ser reenviada ou não.

Então, nossoProcessInstance agora está esperando nesteUserTask, que tem o nome“Modify vacation solicitação ”.

5.4. Suspendendo e ativando um processo

Podemos suspender umProcessDefinition e também umProcessInstance. Se suspendermos umProcessDefinition,, não podemos criar uma instância dele enquanto ele estiver suspenso. Podemos fazer isso usando oRepositoryService:

@Test(expected = ActivitiException.class)
public void givenDeployedProcess_whenSuspend_thenNoProcessInstance() {
    // deploy the process definition
    repositoryService.suspendProcessDefinitionByKey("vacationRequest");
    runtimeService.startProcessInstanceByKey("vacationRequest");
}

Para ativá-lo novamente, precisamos apenas chamar um dos métodosrepositoryService.activateProcessDefinitionXXX.

Da mesma forma, podemos suspender umProcessInstance, usando oRuntimeService.

6. Conclusão

Neste artigo, vimos como poderíamos usar o Activiti com Java. Criamos um arquivo de amostraProcessEngineCofiguration, que nos ajuda a criar oProcessEngine.

Utilizando-o, acessamos vários serviços fornecidos pela API. Esses serviços nos ajudam a gerenciar e acompanharProcessDefinitions,ProcessInstances,UserTasks, etc.

Como sempre, o código dos exemplos que vimos no artigo estáover on GitHub.