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.
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.
4.1. Definição de Processo e Termos Relacionados
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":
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.

