Un guide pour Activiti avec Java

Un guide pour Activiti avec Java

1. Vue d'ensemble

L'API Activiti est un système de gestion des processus et des processus métier. Nous pouvons définir un processus, l'exécuter et le manipuler de différentes façons à l'aide des services fournis par l'API. Il nécessite JDK 7+.

Le développement à l'aide de l'API peut être effectué dans n'importe quel IDE, mais pour utiliser lesActiviti Designer, nous avons besoin d'Eclipse.

Nous pouvons définir un processus en utilisant le standard BPMN 2.0. Il existe un autre moyen, moins populaire, d'utiliser des classes Java telles queStartEvent,EndEvent,UserTask,SequenceFlow, etc.

Si nous voulons exécuter un processus ou accéder à l'un des services, nous devons créer unProcessEngineConfiguration.

Nous pouvons obtenir lesProcessEngine en utilisantProcessEngineConfiguration, de certaines manières, dont nous parlerons plus loin dans cet article. Grâce à_ the _ProcessEngine, nous pouvons effectuer les opérations de workflow et BPMN.

2. Dépendances Maven

Pour utiliser cette API, nous devons inclure la dépendance Activiti:


    org.activiti
    activiti-engine

3. Créer unProcessEngine

ProcessEngine dans Activiti, est généralement configuré à l'aide d'un fichier XML,activiti.cfg.xml. Un exemple de ce fichier de configuration est:


    
        
        
        
        
        
    

Nous pouvons maintenant obtenir lesProcessEngine en utilisant la classeProcessEngines:

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

Cette instruction recherchera un fichier sxmlactiviti.cfg.dans le chemin de classe et construira un fichierProcessEngine en fonction de la configuration du fichier.

L'exemple de code du fichier de configuration indique qu'il s'agit simplement d'une configuration basée sur Spring. Mais cela ne signifie pas que nous ne pouvons utiliser Activiti que dans un environnement Spring. Les capacités de Spring sont simplement utilisées en interne pour créer lesProcessEngine.

Écrivons un cas de test JUnit qui créera lesProcessEngine en utilisant le fichier de configuration ci-dessus:

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

4. API et services Activiti Process Engine

Le point d'entrée d'interaction avec l'API est leProcessEngine. Grâce auxProcessEngine,, nous pouvons accéder à divers services qui fournissent des méthodes de workflow / BPMN. LesProcessEngine et tous les objets de service sont thread-safe.

image

La classeProcessEngines recherchera les fichiersactiviti.cfg.xml etactiviti-context.xml. Comme mentionné précédemment, pour tous les fichiersactiviti.cfg.xml, lesProcessEngine seront créés de manière typique.

Alors que, pour tous les fichiersactiviti-context.xml, il sera créé à la manière Spring - je vais créer le contexte d'application Spring et j'obtiendrai lesProcessEngine à partir de cela. Lors de l'exécution d'un processus, toutes les étapes sont visitées dans l'ordre défini dans le fichier BPMN.

Lors de l'exécution d'un processus, toutes les étapes sont visitées dans l'ordre défini dans le fichier BPMN.

A ProcessDefinition represents a business process. Il est utilisé pour définir la structure et le comportement des différentes étapes du processus. Déployer une définition de processus signifie charger la définition de processus dans la base de données Activiti.

Les définitions de processus sont principalement définies par la norme BPMN 2.0. Il est également possible de les définir en utilisant du code Java. Tous les termes définis dans cette section sont également disponibles en tant que classes Java.

Une fois que nous commençons à exécuter une définition de processus, nous pouvons l’appeler processus.

UnProcessInstance est une exécution d'unProcessDefinition.

A StartEvent is associated with every business process. It indicates the entry point of the process. De même, il y a unEndEvent qui indique la fin du processus. Nous pouvons définir des conditions sur ces événements.

Toutes les étapes (ou éléments) entre le début et la fin sont appeléesTasks. LesTasks peuvent être de différents types. Les tâches les plus couramment utilisées sontUserTasks etServiceTasks.

LesUserTasks, comme son nom l'indique, sont tels qu'ils doivent être exécutés manuellement par un utilisateur.

ServiceTasks, d'autre part, sont configurés avec un morceau de code. Chaque fois que l'exécution les atteint, leur bloc de code sera exécuté.

SequenceFlows connectent lesTasks. Nous pouvons définir lesSequenceFlows par les éléments source et cible qu'ils vont connecter. Encore une fois, nous pouvons également définir des conditions sur lesSequenceFlows pour créer des chemins conditionnels dans le processus.

4.2. Prestations de service

Nous aborderons brièvement les services fournis par Activiti:

  • RepositoryService nous aide à manipuler le déploiement des définitions de processus. Ce service traite les données statiques liées à une définition de processus.

  • RuntimeService gère lesProcessInstances (processus en cours d'exécution) ainsi que les variables de processus

  • TaskService garde la trace desUserTasks. LesTasks qui doivent être exécutés manuellement par un utilisateur sont au cœur de l'API Activiti. Nous pouvons créer une tâche, réclamer et terminer une tâche, manipuler le destinataire de la tâche, etc. en utilisant ce service

  • FormService est un service optionnel. L'API peut être utilisée sans elle et sans sacrifier aucune de ses fonctionnalités. Il est utilisé pour définir le formulaire de début et le formulaire de tâche dans un processus.

  • IdentityService gère lesUsers etGroups

  • HistoryService garde une trace de l'historique d'Activiti Engine. Nous pouvons également définir différents niveaux d’historique.

  • ManagementService est lié aux métadonnées et n'est généralement pas requis lors de la création d'une application

  • DynamicBpmnService nous aide à changer quoi que ce soit dans un processus sans le redéployer

5. Travailler avec les services Activiti

Pour découvrir comment nous pouvons travailler avec différents services et exécuter un processus, prenons un exemple de processus pour "Demande de vacances des employés":

image

Le fichier BPMN 2.0,VacationRequest.bpmn20.xml, pour ce processus aura l'événement de démarrage défini comme:


    
        
        
        
     

De même, la première tâche utilisateur, assignée au groupe d'utilisateurs «management», ressemblera à ceci:


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

Avec lesServiceTask,, nous devons définir le morceau de code à exécuter. Nous avons ce morceau de code en tant que classe Java:


Le flux conditionnel sera affiché en ajoutant la balise“conditionExpression” dans les“sequenceFlow”:


    
      
    

Ici,vacationApproved est leformProperty desUserTask indiqués ci-dessus.

Comme on peut le voir sur le diagramme, le processus est très simple. L'employé fait une demande de congé annuel en précisant le nombre de jours et la date du début des vacances. La demande va au gestionnaire. Ils peuvent approuver / désapprouver la demande.

Si approuvé, une tâche de service est définie pour envoyer l'e-mail de confirmation. En cas de refus, l'employé peut choisir de modifier et de renvoyer la demande ou de ne rien faire.

Les tâches de service sont fournies avec un morceau de code à exécuter (ici, en tant que classe Java). Nous avons donné la classeSendEmailServiceTask.java.

Ces types de classes devraient étendre lesJavaDelegate. De plus, nous devons surcharger sa méthodeexecute(), qui sera exécutée lorsque l'exécution du processus atteindra cette étape.

5.1. Déployer un processus

Pour faire connaître notre processus au moteur Activiti, nous devons le déployer. Nous pouvons le faire par programmation en utilisant leRepositoryService. Écrivons un test JUnit pour montrer ceci:

@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());
}

Le déploiement signifie que le moteur analysera le fichier BPMN et le convertira en un exécutable. En outre, un enregistrement sera ajouté à la table Repository pour chaque déploiement.

Par conséquent, par la suite, nous pouvons interroger le serviceRepository pour obtenir les processus déployés; lesProcessDefinitions.

5.2. Démarrage d'unProcessInstance

Après avoir déployé lesProcessDefinition sur Activiti Engine, nous pouvons exécuter le processus en créant desProcessInstances. LeProcessDefinition est un plan, et leProcessInstance en est l'exécution à l'exécution.

Pour un seulProcessDefinition, il peut y avoir plusieursProcessInstances.

Tous les détails relatifs auxProcessInstances sont accessibles via lesRuntimeService.

Dans notre exemple, lors de l'événement de départ, nous devons indiquer le nombre de jours de vacances, la date de début et la raison. Nous utiliserons les variables de processus et les passerons lors de la création desProcessInstance.

Écrivons un cas de test JUnit pour avoir une meilleure idée:

@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());
}

Les multiples instances d'une même définition de processus diffèrent par les variables de processus.

Il existe plusieurs façons de démarrer une instance de processus. Ici, nous utilisons la clé du processus. Après avoir démarré l'instance de processus, nous pouvons obtenir les informations à ce sujet en interrogeant lesRuntimeService.

5.3. Effectuer des tâches

Lorsque notre instance de processus démarre, la première étape est une tâche utilisateur, affectée au groupe d'utilisateurs“management”.

L'utilisateur peut avoir une boîte de réception contenant une liste de tâches à effectuer. Maintenant, si nous voulons continuer l'exécution du processus, l'utilisateur doit terminer cette tâche. Pour Activiti Engine, cela s'appelle «terminer la tâche».

Nous pouvons interroger lesTaskService, pour obtenir l'objet de tâche, puis le terminer.

Le code que nous devons écrire pour cela ressemble à ceci:

@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);
}

Notez que la méthodecomplete() deTaskService prend également en compte les variables de processus requises. Nous passons dans la réponse du gestionnaire.

Après cela, le moteur de processus passera à l'étape suivante. Ici, l'étape suivante demande à l'employé si la demande de congé doit être renvoyée ou non.

Donc, notreProcessInstance attend maintenant à ceUserTask, qui porte le nom“Modify vacation request ».

5.4. Suspendre et activer un processus

On peut suspendre unProcessDefinition et aussi unProcessInstance. Si nous suspendons unProcessDefinition,, nous ne pouvons pas en créer une instance tant qu'il est suspendu. Nous pouvons le faire en utilisant lesRepositoryService:

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

Pour l'activer à nouveau, il suffit d'appeler l'une des méthodesrepositoryService.activateProcessDefinitionXXX.

De même, nous pouvons suspendre unProcessInstance, en utilisant leRuntimeService.

6. Conclusion

Dans cet article, nous avons vu comment utiliser Activiti avec Java. Nous avons créé un exemple de fichierProcessEngineCofiguration, qui nous aide à créer lesProcessEngine.

En l'utilisant, nous avons eu accès à divers services fournis par l'API. Ces services nous aident à gérer et à garder une trace deProcessDefinitions,ProcessInstances,UserTasks, etc.

Comme toujours, le code des exemples que nous avons vu dans l'article se trouve àover on GitHub.