1. 概要

Activiti APIは、ワークフローおよびビジネスプロセス管理システムです。 APIによって提供されるサービスを使用して、プロセスを定義し、実行し、さまざまな方法で操作できます。 JDK7以降が必要です。

APIを使用した開発はどのIDEでも実行できますが、 Activity Designer を使用するには、Eclipseが必要です。

BPMN 2.0標準を使用して、その中でプロセスを定義できます。 もう1つの、あまり一般的ではない方法があります。 StartEvent EndEvent UserTask SequenceFlowなどのJavaクラスを使用します。

プロセスを実行したり、サービスにアクセスしたりする場合は、ProcessEngineConfigurationを作成する必要があります。

ProcessEngine は、 ProcessEngineConfiguration、を使用して取得できます。これについては、この記事で詳しく説明します。から ]ProcessEngineワークフローおよびBPMN操作を実行できます。

2. Mavenの依存関係

このAPIを使用するには、Activitiの依存関係を含める必要があります。

<dependency>
    <groupId>org.activiti</groupId>
    <artifactId>activiti-engine</artifactId>
</dependency>

3. ProcessEngineの作成

ActivitiのProcessEngineは、通常、XMLファイルactiviti.cfg.xmlを使用して構成されます。 この構成ファイルの例は次のとおりです。

<beans xmlns="...">
    <bean id="processEngineConfiguration" class=
      "org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <property name="jdbcUrl" 
          value="jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000" />
        <property name="jdbcDriver" value="org.h2.Driver" />
        <property name="jdbcUsername" value="root" />
        <property name="jdbcPassword" value="" />
        <property name="databaseSchemaUpdate" value="true" />
    </bean>
</beans>

これで、ProcessEnginesクラスを使用してProcessEngineを取得できます。

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

このステートメントは、クラスパスでactiviti.cfg。xmlファイルを検索し、ファイルの構成に基づいてProcessEngineを構築します。

構成ファイルのサンプルコードは、それが単なるSpringベースの構成であることを示しています。 ただし、これは、Spring環境でのみActivitiを使用できることを意味するものではありません。 Springの機能は、ProcessEngineを作成するために内部的に使用されます。

上記の構成ファイルを使用してProcessEngineを作成するJUnitテストケースを作成しましょう。

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

4. Activiti ProcessEngineAPIおよびサービス

APIとの対話のエントリポイントは、ProcessEngineです。 ProcessEngine、を介して、ワークフロー/BPMNメソッドを提供するさまざまなサービスにアクセスできます。 ProcessEngineとすべてのサービスオブジェクトはスレッドセーフです。

https://www.activiti.org/userguide/images/api.services.pngから取得

ProcessEngines クラスは、activiti.cfg.xmlおよびactiviti-context.xmlファイルをスキャンします。 前述のように、すべての activiti.cfg.xml ファイルについて、ProcessEngineは通常の方法で作成されます。

一方、すべての activiti-context.xml ファイルについては、Springの方法で作成されます— Springアプリケーションコンテキストを作成し、そこからProcessEngineを取得します。 プロセスの実行中、すべてのステップは、BPMNファイルで定義されている順序でアクセスされます。

プロセスの実行中、すべてのステップは、BPMNファイルで定義されている順序でアクセスされます。

4.1. プロセスの定義と関連用語

ProcessDefinitionはビジネスプロセスを表します。これは、プロセスのさまざまなステップの構造と動作を定義するために使用されます。 プロセス定義をデプロイするということは、プロセス定義をActivitiデータベースにロードすることを意味します。

プロセス定義は、主にBPMN2.0標準によって定義されています。 Javaコードを使用してそれらを定義することも可能です。 このセクションで定義されているすべての用語は、Javaクラスとしても使用できます。

プロセス定義の実行を開始すると、それをプロセスと呼ぶことができます

ProcessInstance は、ProcessDefinition。の1回の実行です。

StartEventは、すべてのビジネスプロセスに関連付けられています。 プロセスのエントリポイントを示します。 同様に、 EndEvent これは、プロセスの終了を示します。 これらのイベントの条件を定義できます。

開始と終了の間のすべてのステップ(または要素)は、タスクと呼ばれます。 タスクにはさまざまなタイプがあります。 最も一般的に使用されるタスクは、UserTasksおよびServiceTasksです。

UserTasks は、その名前が示すように、ユーザーが手動で実行する必要があるようなものです。

一方、 ServiceTasks は、コードの一部で構成されます。 実行がそれらに到達するたびに、それらのコードブロックが実行されます。

SequenceFlowsTasksを接続します。 SequenceFlows は、それらが接続するソース要素とターゲット要素によって定義できます。 ここでも、 SequenceFlows で条件を定義して、プロセスに条件付きパスを作成することもできます。

4.2. サービス

Activitiが提供するサービスについて簡単に説明します。

  • RepositoryService は、プロセス定義のデプロイメントを操作するのに役立ちます。 このサービスは、プロセス定義に関連する静的データを処理します
  • RuntimeService は、 ProcessInstances (現在実行中のプロセス)とプロセス変数を管理します
  • TaskServiceUserTasksを追跡します。 ユーザーが手動で実行する必要のあるタスクは、ActivitiAPIの中核です。 タスクの作成、タスクの要求と完了、タスクの担当者の操作などを行うことができます。 このサービスを使用する
  • FormServiceはオプションのサービスです。 APIは、APIがなくても、その機能を犠牲にすることなく使用できます。 プロセス内の開始フォームとタスクフォームを定義するために使用されます。
  • IdentityService は、ユーザーおよびグループを管理します
  • HistoryService は、ActivitiEngineの履歴を追跡します。 さまざまな履歴レベルを設定することもできます。
  • ManagementService はメタデータに関連しており、通常、アプリケーションの作成時には必要ありません。
  • DynamicBpmnService は、プロセスを再デプロイせずに、プロセス内のすべてを変更するのに役立ちます

5. Activitiサービスの操作

さまざまなサービスを操作してプロセスを実行する方法を学ぶために、「従業員の休暇申請」のプロセスの例を見てみましょう。

このプロセスのBPMN2.0ファイルVacationRequest.bpmn20.xmlには、開始イベントが次のように定義されています。

<startEvent id="startEvent" name="request" 
  activiti:initiator="employeeName">
    <extensionElements>
        <activiti:formProperty id="numberOfDays" 
          name="Number of days" type="long" required="true"/>
        <activiti:formProperty id="startDate" 
          name="Vacation start date (MM-dd-yyyy)" type="date" 
          datePattern="MM-dd-yyyy hh:mm" required="true"/>
        <activiti:formProperty id="reason" name="Reason for leave" 
          type="string"/>
     </extensionElements>
</startEvent>

同様に、ユーザーグループ「管理」に割り当てられた最初のユーザータスクは次のようになります。

<userTask id="handle_vacation_request" name=
  "Handle Request for Vacation">
    <documentation>${employeeName} would like to take ${numberOfDays} day(s)
      of vacation (Motivation: ${reason}).</documentation>
    <extensionElements>
        <activiti:formProperty id="vacationApproved" name="Do you approve
          this vacation request?" type="enum" required="true"/>
        <activiti:formProperty id="comments" name="Comments from Manager"
          type="string"/>
    </extensionElements>
    <potentialOwner>
      <resourceAssignmentExpression>
        <formalExpression>management</formalExpression>
      </resourceAssignmentExpression>
    </potentialOwner>
</userTask>

ServiceTask、を使用して、実行するコードを定義する必要があります。 このコードはJavaクラスとしてあります。

<serviceTask id="send-email-confirmation" name="Send email confirmation" 
  activiti:class=
  "com.example.activiti.servicetasks.SendEmailServiceTask.java">
</serviceTask>

条件付きフローは、「conditionExpression」タグを「sequenceFlow」:に追加することで表示されます。

<sequenceFlow id="flow3" name="approved" 
  sourceRef="sid-12A577AE-5227-4918-8DE1-DC077D70967C" 
  targetRef="send-email-confirmation">
    <conditionExpression xsi:type="tFormalExpression">
      <![CDATA[${vacationApproved == 'true'}]]>
    </conditionExpression>
</sequenceFlow>

ここで、 vacationApproved は、上記のUserTaskformPropertyです。

図からわかるように、これは非常に単純なプロセスです。 従業員は休暇申請を行い、休暇の日数と開始日を提供します。 リクエストはマネージャーに送信されます。 リクエストを承認/却下できます。

承認された場合、確認メールを送信するために定義されたサービスタスクがあります。 不承認の場合、従業員はリクエストを変更して再送信するか、何もしないかを選択できます。

サービスタスクには、実行するためのコードがいくつか用意されています(ここでは、Javaクラスとして)。 私たちはクラスを与えました SendEmailServiceTask.java。

これらのタイプのクラスは、 JavaDelegate。 また、そのオーバーライドする必要があります実行する() メソッド。これは、プロセスの実行がこのステップに達したときに実行されます。

5.1. プロセスの展開

プロセスをActivitiEngineに通知するには、プロセスをデプロイする必要があります。 プログラムでそれを行うことができます RepositoryService。 これを示すJUnitテストを書いてみましょう。

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

デプロイメントとは、エンジンがBPMNファイルを解析し、それを実行可能ファイルに変換することを意味します。 また、すべてのデプロイメントのリポジトリテーブルにレコードが追加されます。

したがって、後で、 Repository サービスにクエリを実行して、デプロイされたプロセスを取得できます。 ProcessDefinitions

5.2. ProcessInstanceを開始しています

ProcessDefinitionをActivitiEngineにデプロイした後、ProcessInstancesを作成してプロセスを実行できます。 ProcessDefinition は青写真であり、ProcessInstanceはその実行時の実行です。

単一のProcessDefinitionの場合、複数のProcessInstancesが存在する可能性があります。

ProcessInstances に関連するすべての詳細には、RuntimeServiceからアクセスできます。

この例では、開始イベントで、休暇日数、開始日、および理由を渡す必要があります。 プロセス変数を使用し、作成中にそれらを渡します ProcessInstance。

より良いアイデアを得るために、JUnitテストケースを書いてみましょう。

@Test
public void givenDeployedProcess_whenStartProcessInstance_thenRunning() {
    //deploy the process definition    
    Map<String, Object> 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());
}

単一のプロセス定義の複数のインスタンスは、プロセス変数によって異なります。

プロセスインスタンスを開始する方法は複数あります。 ここでは、プロセスのキーを使用しています。 プロセスインスタンスを開始した後、 RuntimeService にクエリを実行することで、プロセスインスタンスに関する情報を取得できます。

5.3. タスクの完了

プロセスインスタンスの実行が開始されると、最初のステップはユーザーグループ「管理」に割り当てられたユーザータスクです。

ユーザーは、自分が実行するタスクのリストを含む受信トレイを持っている場合があります。 ここで、プロセスの実行を続行する場合、ユーザーはこのタスクを完了する必要があります。 Activiti Engineの場合、これは「タスクの完了」と呼ばれます。

TaskService、にクエリを実行して、タスクオブジェクトを取得し、それを完了することができます。

このために作成する必要のあるコードは次のようになります。

@Test 
public void givenProcessInstance_whenCompleteTask_thenGotNextTask() {
    // deploy process and start process instance   
    TaskService taskService = processEngine.getTaskService();
    List<Task> tasks = taskService.createTaskQuery()
      .taskCandidateGroup("management").list();
    Task task = tasks.get(0);
    
    Map<String, Object> 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);
}

TaskServicecomplete()メソッドも、必要なプロセス変数を取り込むことに注意してください。 店長からの返事をお渡しします。

この後、プロセスエンジンは次のステップに進みます。 ここで、次のステップでは、休暇申請を再送するかどうかを従業員に尋ねます。

したがって、 ProcessInstance は、この UserTask、で待機しています。の名前は「休暇の変更リクエスト」です。

5.4. プロセスの一時停止とアクティブ化

ProcessDefinitionProcessInstanceを一時停止できます。 ProcessDefinitionを一時停止すると、一時停止中はインスタンスを作成できません。 これは、 RepositoryService:を使用して実行できます。

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

再度アクティブ化するには、repositoryService.activateProcessDefinitionXXXメソッドの1つを呼び出す必要があります。

同様に、一時停止することができます ProcessInstance、 を使用して RuntimeService。

6. 結論

この記事では、JavaでActivitiを使用する方法を説明しました。 サンプルのProcessEngineCofigurationファイルを作成しました。これは、ProcessEngineの作成に役立ちます。

それを使って、APIが提供するさまざまなサービスにアクセスしました。 これらのサービスは、 ProcessDefinitions ProcessInstances UserTasksなどの管理と追跡に役立ちます。

いつものように、この記事で見た例のコードは、GitHubあります。