Javaを使ったActivitiのガイド

1概要

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

  • APIを使用した開発はどのIDEでも実行できますが、https://www.activiti.org/userguide/index.html?__ga=2.55182893.76071610.1499064413-1368418377.1499064413#eclipseDesignerInstallation[Ativiti Designer]を使用するにはEclipseが必要です。 **

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

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

いくつかの方法で ProcessEngineConfigurationを使用して ProcessEngine__を取得できます。これについては、この記事で詳しく説明します。

2 Mavenの依存関係

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

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

3 ProcessEngine を作成する

Activitiの ProcessEngine は通常、 activiti.cfg.xml という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 Process Engine APIとサービス

APIとの対話の開始点は ProcessEngine です。

ProcessEngineを通じて、ワークフロー/BPMNメソッドを提供するさまざまなサービスにアクセスできます。 ProcessEngine__とすべてのサービスオブジェクトはスレッドセーフです。

/uploads/api.services.png%3C/p%3E%3C/div%3E%0A%3Cp%3EThe%20%3Cem%3EProcessEngines%3C/em%3E%20class%20will%20scan%20for%20the%20%3Cem%3Eactiviti.cfg.xml%3C/em%3E%20and%20%3Cem%3Eactiviti-context.xml%3C/em%3E%20files.%20As%20mentioned%20earlier,%20for%20all%20the%20%3Cem%3Eactiviti.cfg.xml%3C/em%3E%20files,%20the%20%3Cem%3EProcessEngine%3C/em%3E%20will%20be%20created%20in%20a%20typical%20way.%3C/p%3E%0A%3Cp%3EWhereas,%20for%20all%20the%20%3Cem%3Eactiviti-context.xml%3C/em%3E%20files,%20it%20will%20be%20created%20in%20the%20Spring%20way%20—%20I’ll%20create%20the%20Spring%20Application%20Context%20and%20will%20obtain%20the%20%3Cem%3EProcessEngine%3C/em%3E%20from%20that.%20During%20the%20execution%20of%20a%20process,%20all%20the%20steps%20will%20be%20visited%20in%20the%20order%20that%20is%20defined%20in%20the%20BPMN%20file.%3C/p%3E%0A%3Cp%3EDuring%20the%20execution%20of%20a%20process,%20all%20the%20steps%20will%20be%20visited%20in%20the%20order%20that%20is%20defined%20in%20the%20BPMN%20file.%3C/p%3E%0A%3Ch3%3E%3Cstrong%3E4.1.%20Process%20Definition%20and%20Related%20Terms%3C/strong%3E%3C/h3%3E%0A%3Cp%3E%3Cstrong%3EA%20%3Cem%3EProcessDefinition%3C/em%3E%20represents%20a%20business%20process.%3C/strong%3E%20It’s%20used%20to%20define%20the%20structure%20and%20behavior%20of%20different%20steps%20in%20the%20process.%20Deploying%20a%20process%20definition%20means%20loading%20the%20process%20definition%20into%20the%20Activiti%20database.%3C/p%3E%0A%3Cp%3EProcess%20definitions%20are%20mostly%20defined%20by%20the%20BPMN%202.0%20standard.%20It’s%20also%20possible%20to%20define%20them%20using%20Java%20code.%20All%20the%20terms%20defined%20in%20this%20section%20are%20available%20as%20Java%20classes%20as%20well.%3C/p%3E%0A%3Cp%3EOnce%20we%20start%20running%20a%20process%20definition,%20it%20can%20be%20referred%20to%20as%20a%20process%3C/p%3E%0A%3Cp%3E%3Cstrong%3EA%20%3Cem%3EProcessInstance%3C/em%3E%20is%20one%20execution%20of%20a%20%3Cem%3EProcessDefinition.%3C/em%3E%3C/strong%3E%3C/p%3E%0A%3Cp%3E%3Cstrong%3EA%20%3Cem%3EStartEvent%3C/em%3E%20is%20associated%20with%20every%20business%20process.%20It%20indicates%20the%20entry%20point%20of%20the%20process.%3C/strong%3E%20Similarly,%20there%20is%20an%20%3Cem%3EEndEvent%3C/em%3E%20which%20indicates%20the%20end%20of%20the%20process.%20We%20can%20define%20conditions%20over%20these%20events.%3C/p%3E%0A%3Cp%3EAll%20the%20steps%20(or%20elements)%20in%20between%20the%20start%20and%20end%20are%20referred%20to%20as%20%3Cem%3ETasks%3C/em%3E.%20%3Cem%3ETasks%3C/em%3E%20can%20be%20of%20various%20types.%20The%20most%20commonly%20used%20tasks%20are%20%3Cem%3EUserTasks%3C/em%3E%20and%20%3Cem%3EServiceTasks%3C/em%3E.%3C/p%3E%0A%3Cp%3E%3Cem%3EUserTasks%3C/em%3E,%20as%20the%20name%20suggests,%20are%20such%20that%20they%20need%20to%20be%20carried%20out%20manually%20by%20a%20user.%3C/p%3E%0A%3Cp%3E%3Cem%3EServiceTasks%3C/em%3E,%20on%20the%20other%20hand,%20are%20configured%20with%20a%20piece%20of%20code.%20Whenever%20the%20execution%20reaches%20them,%20their%20block%20of%20code%20will%20be%20executed.%3C/p%3E%0A%3Cp%3E%3Cem%3ESequenceFlows%3C/em%3E%20connect%20the%20%3Cem%3ETasks%3C/em%3E.%20We%20can%20define%20the%20%3Cem%3ESequenceFlows%3C/em%3E%20by%20the%20source%20and%20target%20elements%20that%20they’ll%20connect.%20Again,%20we%20can%20also%20define%20conditions%20over%20the%20%3Cem%3ESequenceFlows%3C/em%3E%20to%20create%20conditional%20paths%20in%20the%20process.%3C/p%3E%0A%3Ch3%3E%3Cstrong%3E4.2.%20Services%3C/strong%3E%3C/h3%3E%0A%3Cp%3EWe’ll%20discuss%20in%20brief%20the%20services%20provided%20by%20Activiti:%3C/p%3E%0A%3Cul%3E%0A%3Cli%3E%3Cem%3E%3Cstrong%3ERepositoryService%3C/strong%3E%3C/em%3E%20helps%20us%20manipulate%20the%20deployment%20of%20process%20definitions.%20This%20service%20deals%20with%20the%20static%20data%20related%20to%20a%20process%20definition%3C/li%3E%0A%3Cli%3E%3Cem%3E%3Cstrong%3ERuntimeService%3C/strong%3E%3C/em%3E%20manages%20the%20%3Cem%3EProcessInstances%3C/em%3E%20(currently%20running%20processes)%20as%20well%20as%20the%20process%20variables%3C/li%3E%0A%3Cli%3E%3Cem%3E%3Cstrong%3ETaskService%3C/strong%3E%3C/em%3E%20keeps%20track%20of%20the%20%3Cem%3EUserTasks%3C/em%3E.%20The%20%3Cem%3ETasks%3C/em%3E%20that%20need%20to%20be%20carried%20out%20manually%20by%20a%20user%20are%20at%20the%20core%20of%20the%20Activiti%20API.%20We%20can%20create%20a%20task,%20claim%20and%20complete%20a%20task,%20manipulate%20the%20assignee%20of%20the%20task,%20etc.%20using%20this%20service%3C/li%3E%0A%3Cli%3E%3Cem%3E%3Cstrong%3EFormService%3C/strong%3E%3C/em%3E%20is%20an%20optional%20service.%20The%20API%20can%20be%20used%20without%20it,%20and%20without%20sacrificing%20any%20of%20its%20features.%20It%20is%20used%20to%20define%20the%20start%20form%20and%20task%20form%20in%20a%20process.%3C/li%3E%0A%3Cli%3E%3Cem%3E%3Cstrong%3EIdentityService%3C/strong%3E%3C/em%3E%20manages%20the%20%3Cem%3EUsers%3C/em%3E%20and%20%3Cem%3EGroups%3C/em%3E%3C/li%3E%0A%3Cli%3E%3Cem%3E%3Cstrong%3EHistoryService%3C/strong%3E%3C/em%3E%20keeps%20track%20of%20the%20history%20of%20Activiti%20Engine.%20We%20can%20also%20set%20different%20history%20levels.%3C/li%3E%0A%3Cli%3E%3Cem%3E%3Cstrong%3EManagementService%3C/strong%3E%3C/em%3E%20is%20related%20to%20the%20metadata%20and%20usually%20not%20required%20when%20creating%20an%20application%3C/li%3E%0A%3Cli%3E%3Cem%3E%3Cstrong%3EDynamicBpmnService%20%3C/strong%3E%3C/em%3Ehelps%20us%20to%20change%20anything%20in%20a%20process%20without%20redeploying%20it%3C/li%3E%0A%3C/ul%3E%0A%3Ch2%3E%3Cstrong%3E5.%20Working%20with%20%3C/strong%3EActiviti%3Cstrong%3E%20Services%3C/strong%3E%3C/h2%3E%0A%3Cp%3ETo%20learn%20how%20we%20can%20work%20with%20different%20services%20and%20run%20a%20process,%20let’s%20take%20an%20example%20of%20a%20process%20for%20“Employee%20vacation%20request”:%3C/p%3E%0A%3Ca%20href=[]

このプロセスのBPMN 2.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>

同様に、ユーザーグループ "management"に割り当てられている最初のユーザータスクは、次のようになります。

<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>

条件付きフローは、 "sequenceFlow"に "conditionExpression" __タグを追加して表示されます。

<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 は上記の UserTask formProperty です。

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

承認された場合は、確認Eメールを送信するように定義されたサービスタスクがあります。不承認の場合、従業員は要求を変更して再送信することを選択するか、何もしません。

サービスタスクには、実行するコードがいくつか提供されています(ここではJavaクラスとして)。クラス SendEmailServiceTask.java. を指定しました。

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

5.1. プロセスのデプロイ

私たちのプロセスをActiviti Engineに知らせるためには、プロセスをデプロイする必要があります。 __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 をActiviti Engineにデプロイした後、 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. タスクを完了する

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

ユーザーは、自分が実行するタスクのリストを含む受信箱を持っているかもしれません。さて、もしプロセスの実行を続けたいのなら、ユーザーはこのタスクを終了する必要があります。 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);
}

TaskService complete() メソッドも必要なプロセス変数を取り込むことに注意してください。私達はマネージャーからの返事を渡します。

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

そのため、 ProcessInstance は、この UserTask で待機しています。

5.4. プロセスの中断と有効化

ProcessDefinition ProcessInstance を中断することができます。 ProcessDefinitionを中断した場合、 その中断中はインスタンスを作成できません。 __RepositoryServiceを使用してこれを実行できます。

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

再度アクティブにするには、 repositoryService.activateProcessDefinitionXXX メソッドの1つを呼び出すだけです。

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

6. 結論

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

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

いつものように、私達が記事で見た例のためのコードはhttps://github.com/eugenp/tutorials/tree/master/spring-activiti[over on GitHub]にあります。