Java Activiti User Guide Digest

JavaActivitiUserGuideDigest

User Manual:

Open the PDF directly: View PDF PDF.
Page Count: 46

2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 1/46
Java Activiti User Guide Digest
2018-07-2018-07-
0303
20182018
JulyJuly
Week 27Week 27
Day 03Day 03
TueTue
⽬次
FrontPage
・さくらVPS
Fedora13
SuSe10
Docker
Ansible
Java
Scala
Python
Ruby
Lisp
Computer
GIS
HTML
Culture
Random
Link
訪問者
total: 5611
today: 21
yesterday: 11
now: 4
更新
最新の10
2018-07-02
Python
CuPy on
MacBookPro
Python
2018-06-28
Thought
伝搬について
の整理
2018-06-25
Random
Memorandum
2018Q1
2018-06-24
Mac 数式の⼊
った資料を作
OmniGraffle+LaTeXiT
2018-06-23
Mac
2018-06-12
Books 深層
学習 Deep
Learning
2018-06-07
Thought
ンソル
2018-05-30
Culture
Python
Matplotlib
1. Introduction
2. Getting Started
3. Configuration
3.16. Loggin
3.18. Event handlers
4. The Activiti API
4.1~4.3 ワークフローを実⾏するコンソールアプリ
4.3.4.プロセスの Suspend Activate
4.4 Query API
4.5.Variables
4.7 Unit Test
4.9 The process engine in a web application
6. Deployment
7.標準 BPMN 2.0
8.Activiti 拡張 BPMN 2.0
8.2.Event
8.3 Sequence Flow
8.4 Gateways
8.5 Task
8.15.12.Execution listener
8.5.13. Task listener
8.5.14 Multi-instance (for each)
8.6. Sub-Processes and Call Activities
9. Form
11.History
13. Activiti Explorer 14. Modeler
15. REST API
本家 : http://www.activiti.org/userguide/
1. Introduction
Activiti 本体 Apache License V2
Activiti Modeler LGPL 2.1
http://activiti.org/download.html
https://github.com/Activiti/Activiti
JDK6+
Eclipse designer plugin
http://www.eclipse.org/downloads/ (最新の Mars でも OK だった)
http://activiti.org/designer/update/ (Plugin Repository)
2. Getting Started
Tutorial
Java6 + Tomcat + Activiti-Explorer
Demo database setup flag
Activiti Explorer Rest API では、後述する標準の activiti.cfg.xml の代わりに db.properties,
engine.properties でアプリケーションの設定を⾏う
WEB-INF/classes/db.properties
WEB-INF/classes/engine.properties
1
2
3
4
5
db=h2
jdbc.driver=org.h2.Driver
jdbc.url=jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000
jdbc.username=sa
jdbc.password=
1
2
3
4
5
6
7
# demo data properties
create.demo.users=true
create.demo.definitions=true
create.demo.models=true
create.demo.reports=true
# engine properties
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 2/46
⼈気の10
FrontPage(431163)
Maven
Eclipseとの
連携(72491)
Jakarta
log4j.xml
に設定するロ
グレベルの整
(67255)
VBAの基本構
(60656)
Win32 Trac
Lightning(54708)
Jakarta
POI(45451)
JavaSE RSA
暗号(41483)
Java(40691)
OpenAM
Wordpress
との SAML
連携(37622)
OpenAM イン
ストール
(37126)
MenuBar
3. Configuration
独⾃の Workflow アプリ ProcessEngine? を使ってワークフローを操作
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
デフォルト設定では Classpath にある activiti.cfg.xml または activiti-context.xml の設定に基づいて
ProcessEngine? が作られる
(設定内容をプログラム内で明⽰的に設定することも可。後述)
activity.cfg.xml
8
9
10
11
12
13
14
15
16
17
engine.schema.update=true
engine.activate.jobexecutor=false
engine.asyncexecutor.enabled=true
engine.asyncexecutor.activate=true
engine.history.level=full
# email properties
#engine.email.enabled=true
#engine.email.host=localhost
#engine.email.port=1025
https://github.com/kagyuu/ActivitiExam/blob/master/src/main/resources/activiti.cfg.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframew
<!-- 3.2.processEngineConfiguration
Stand alone app : org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration
Test (Use in-memory h2) : org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfigurat
Spring integration : org.activiti.spring.SpringProcessEngineConfiguration
Stand alone app with JTA : org.activiti.engine.impl.cfg.JtaProcessEngineConfiguration
-->
<bean id="processEngineConfiguration"
class="org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration">
<!-- 3.3-3.8.database connection
support h2, musql, oracle, postgres, db2, mssql
-->
<property name="jdbcUrl" value="jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000" />
<property name="jdbcDriver" value="org.h2.Driver" />
<property name="jdbcUsername" value="sa" />
<property name="jdbcPassword" value="" />
<!-- Optional database connection properties * The unit of XXXTime is millisec *
<property name="jdbcMaxActiveConnections" value="10" />
<property name="jdbcMaxIdleConnections" value="" />
<property name="jdbcMaxCheckoutTime" value="20000" />
<property name="jdbcMaxWaitTime" value="20000" />
-->
<!-- Schema Update
false (default) : If the db schema version != activiti lib version then abend
true : If the db schema version != activiti lib version then update db schema
create-drop : Always create and drop schema
<property name="databaseSchemaUpdate" value="false" />
-->
<!-- 3.9-3.11 Job Executor
By default, the JobExecutor is activated when the process engine boots.
By default, the AsyncExecutor is not enabled and the JobExecutor is used
due to legacy reasons.
It?'s however recommended to use the new AsyncExecutor instead.
-->
<!--
<property name="jobExecutorActivate" value="false" />
<property name="asyncExecutorEnabled" value="true" />
<property name="asyncExecutorActivate" value="true" />
-->
<!-- 3.12. Mail Configuration (for email task)
|======================|=======================|
|property name | Default value |
|======================|=======================|
|mailServerHost | localhost |
|mailServerPort | 25 |
|mailServerDefaultFrom | activiti@activiti.org |
|mailServerUsername | (not set) |
|mailServerPassword | (not set) |
|mailServerUseSSL | (not set) |
|mailServerUseTLS | (not set) |
|======================|=======================|
-->
<property name="mailServerHost" value="localhost" />
<property name="mailServerPort" value="50025" />
<!-- 3.13. History (for logging task execution)
<property name="history" value="audit" />
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 3/46
Spring bean.xml 形式だが、⽂法を借りているだけ。Activiti Spring が必須ではない
JNDI から Datasource lookup して利⽤することも可能
Activiti Explorer Activity Rest API は、db.properties で接続先を設定するようになっている。
内部的には、その他の ProcessEngine 作成⽅法
その他の ProcessEngine 作成⽅法
1. 設定ファイルを明⽰する
ProcessEngine processEngine
= ProcessEngineConfiguration
.createProcessEngineConfigurationFromInputStream(inputStream).buildProcessEngine()
2. プログラム中で設定を⾏う (Activiti-ExplorerActiviti-Rest はこのやり⽅)
デフォルト設定
ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration();
ProcessEngineConfiguration.createStandaloneInMemProcessEngineConfiguration();
デフォルト設定に個別設定を追加
ProcessEngine processEngine
= ProcessEngineConfiguration
.createStandaloneInMemProcessEngineConfiguration()
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_FALSE)
.setJdbcUrl("jdbc:h2:mem:my-own-db;DB_CLOSE_DELAY=1000")
.setAsyncExecutorEnabled(true)
.setAsyncExecutorActivate(false)
.buildProcessEngine();
ProcessEngine? は、Singleton。設定ファイルを読み直すには
ProcessEngine.destory();
ProcessEngine.init();
を実⾏する必要あり
3.16. Loggin
Activiti SLF4J にログを書いている
SLF4J は、出⼒先がないときは NOP-logger にログを送っているので、結果的にログは出ない
SLF4J 推奨の logback Classpath に追加すれば logback からログが出る
pom.xml
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
log4j でログを出⼒させるときには SLF4J-log4j ブリッジを Classpath に追加すれば良い
pom.xml
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
Activiti Explorer Activity Rest API はこの⽅式
Spring (commons-loggin) に統合したいときは
pom.xml
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
64
65
66
67
68
69
70
71
-->
<!-- 3.15. Cache (default is no limit)
<property name="processDefinitionCacheLimit" value="10" />
-->
</bean>
</beans>
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 4/46
Activiti は、SLF4J Mapped Diagnostic Contexts に、実⾏中のワークフローの情報を詰め込んでいるので、
ログ出⼒の設定(logback.xmlなど)で適宜拾うことができる 【留意点あり】
processDefinition Id as mdcProcessDefinitionID
processInstance Id as mdcProcessInstanceID
execution Id as mdcexecutionId
【留意点】
実装は、http://activiti.org/javadocs/org/activiti/engine/logging/LogMDC.html
Activiti の本体コードを⾒てみると、タスク開始時に⼀律 MDC にタスク情報が設定されて、終了時にクリア
されるわけではないらしい。最初そう思ってうまく⾏かず、⾊々調べてみた。
どうやら、例外発⽣時に MDC にプロセス情報が設定されるようだ。きっと、障害解析⽤の仕組みなんだろう
業務ログとしてこういう情報が欲しければ、⾃前で 3.18. Event handler を作って MDC にタスク情報を格
納する必要あり
LogMDC.putMDCExecution(ActivityExecution? e) の引き数は、Activiti の内部クラス
org.activiti.engine.impl.pvm.delegate.ActivityExecution? であり、ユーザプログラムからは取
得できない。LogMDC を強制初期化するようなユーザプログラム (イベントハンドラ) は作ることが出来ない
3.18. Event handlers
ProcessEngine? の起動・停⽌、JOB の開始・終了イベントをフックできる
3.18.6. Supported event types
EventListener? ProcessEngine? のインスタンスのもちもの。DBを共有して同じJOBを⼆つの
ProcessEneigne? をまたいで実⾏した場合、それぞれの EventLister? はそれぞれの ProcessEngine? (
実⾏環境にある activiti.cfg.xml) に定義されているもの
EventListener? 実装
インタフェース org.activiti.engine.delegate.event.ActivitiEventListener? を実装する
3.18.1. Event listener implementation
EventListener? 定義
activiti.cfg.xml に定義する
全イベントを拾う 3.18.2. Configuration and setup
特定のイベントだけを拾う
処理中でイベントリスナを設定 3.18.3. Adding listeners at runtime
特定のプロセスだけ拾う 3.18.4. Adding listeners to process definitions
4. The Activiti API
http://activiti.org/javadocs/index.html
アプリの中では ProcessEngine? のインスタンスは⼀つだけにする。Thread Safe になっている。
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
何回 ProcessEngines?.getDefaultProcessEngine?(); を呼び出しても返ってくるインスタンスは同じ (
定ファイルを毎回読まない)
設定ファイルを読み直すには
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<withJansi>true</withJansi>
<encoder>
<pattern>%date [%thread] %highlight(%-5level) %-20logger{20} %mdc{mdcProcessDefinitionID} %msg %
</encoder>
</appender>
1
2
3
4
5
6
7
8
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEn
...
<property name="eventListeners">
<list>
<bean class="org.activiti.engine.example.MyEventListener" />
</list>
</property>
</bean>
1
2
3
4
5
6
7
8
9
10
11
12
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessE
...
<property name="typedEventListeners">
<map>
<entry key="JOB_EXECUTION_SUCCESS,JOB_EXECUTION_FAILURE" >
<list>
<bean class="org.activiti.engine.example.MyJobEventListener" />
</list>
</entry>
</map>
</property>
</bean>
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 5/46
ProcessEngine.destory();
ProcessEngine.init();
を実⾏する必要あり
ProcessEngine? から getXXXService() で、Service API を取得できる
RuntimeService?processEngine.getRuntimeService?() プロセス管理
RepositoryService?processEngine.getRepositoryService?() BPMN 管理。配備とか
TaskService?processEngine.getTaskService?() ユーザ操作の実現 (エミュレーション)
ManagementService?processEngine.getManagementService?() Activiti ⾃体の管理
IdentityService?processEngine.getIdentityService?() 認証
HistoryService?processEngine.getHistoryService?() タスク処理の記録をDBに永続化
FormService?processEngine.getFormService?() タスク開始・終了時のユーザ確認
http://activiti.org/javadocs/org/activiti/engine/ProcessEngine.html
どのサービスもStateless JOB管理DBが共有でもクラスタで同時実⾏可能
Exception
org.activiti.engine.ActivitiException? の⼦
http://activiti.org/javadocs/org/activiti/engine/ActivitiException.html
It's RuntimeException?.
4.1~4.3 ワークフローを実⾏するコンソールアプリ
開発環境
https://eclipse.org/ 最新版(2015時点)MarsOK
plugin
Name Activiti BPMN 2.0 designer
Location http://activiti.org/designer/update/
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 6/46
BPMN GUI で編集するために Activiti BPMN 2.0 designer が必要ないのであれば Eclipse でなくてもい
い。プログラム本体を作るだけなら Java Maven Project が扱えればどんな IDE でもいい。
サンプルプロジェクト
普通の Maven Project
pom.xml
https://github.com/kagyuu/ActivitiExam/blob/master/pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-i
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven
<modelVersion>4.0.0</modelVersion>
<groupId>com.snail.exam</groupId>
<artifactId>ActivitExam</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-engine</artifactId>
<version>5.19.0</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 7/46
レポジトリに Alfresco (Activiti開発元) のレポジトリを追加
依存ライブラリに Activiti Engine を設定する
その他に、ログ出⼒⽤に logback、テスト⽤ DB H2
activiti.cfg.xml
ここでは、テスト⽤の Table をロードする設定(StandaloneInMemProcessEngineConfiguration?)を使う
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<version>1.4.190</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Make JAR OSGi Bundle Ready -->
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.7</version>
<extensions>true</extensions>
</plugin>
<!-- Compile -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<!-- http://www.activiti.org/community.html -->
<id>Alfresco Maven Repository</id>
<url>https://maven.alfresco.com/nexus/content/groups/public/</url>
</repository>
</repositories>
</project>
https://github.com/kagyuu/ActivitiExam/blob/master/src/main/resources/activiti.cfg.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework
<!-- 3.2.processEngineConfiguration
Stand alone app : org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration
Test (Use in-memory h2) : org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration
Spring integration : org.activiti.spring.SpringProcessEngineConfiguration
Stand alone app with JTA : org.activiti.engine.impl.cfg.JtaProcessEngineConfiguration
-->
<bean id="processEngineConfiguration"
class="org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration">
<!-- 3.3-3.8.database connection
support h2, musql, oracle, postgres, db2, mssql
-->
<property name="jdbcUrl" value="jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000" />
<property name="jdbcDriver" value="org.h2.Driver" />
<property name="jdbcUsername" value="sa" />
<property name="jdbcPassword" value="" />
<!-- Optional database connection properties * The unit of XXXTime is millisec *
<property name="jdbcMaxActiveConnections" value="10" />
<property name="jdbcMaxIdleConnections" value="" />
<property name="jdbcMaxCheckoutTime" value="20000" />
<property name="jdbcMaxWaitTime" value="20000" />
-->
<!-- Schema Update
false (default) : If the db schema version != activiti lib version then abend
true : If the db schema version != activiti lib version then update db schema
create-drop : Always create and drop schema
<property name="databaseSchemaUpdate" value="false" />
-->
<!-- 3.9-3.11 Job Executor
By default, the JobExecutor is activated when the process engine boots.
By default, the AsyncExecutor is not enabled and the JobExecutor is used
due to legacy reasons.
It?'s however recommended to use the new AsyncExecutor instead.
-->
<!--
<property name="jobExecutorActivate" value="false" />
<property name="asyncExecutorEnabled" value="true" />
<property name="asyncExecutorActivate" value="true" />
-->
<!-- 3.12. Mail Configuration (for email task)
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 8/46
テスト⽤BPMN (VacationRequest?.bpmn20.xml)
ActivitiExplorerのデモアプリ で使った休暇申請のワークフローを /src/main/resources/org/activiti/test
配置
Java コンソールアプリ
BMMNの配備(DB格納) プロセス開始 (休暇申請) 否決 再申請
の流れをやってみる
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|======================|=======================|
|property name | Default value |
|======================|=======================|
|mailServerHost | localhost |
|mailServerPort | 25 |
|mailServerDefaultFrom | activiti@activiti.org |
|mailServerUsername | (not set) |
|mailServerPassword | (not set) |
|mailServerUseSSL | (not set) |
|mailServerUseTLS | (not set) |
|======================|=======================|
-->
<property name="mailServerHost" value="localhost" />
<property name="mailServerPort" value="50025" />
<!-- 3.13. History (for logging task execution)
<property name="history" value="audit" />
-->
<!-- 3.15. Cache (default is no limit)
<property name="processDefinitionCacheLimit" value="10" />
-->
</bean>
</beans>
https://github.com/kagyuu/ActivitiExam/blob/master/src/main/java/com/snail/exam/MyProcess.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.snail.exam;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyProcess {
private static final Logger log = LoggerFactory.getLogger(MyProcess.class);
public static void main(String[] args) {
try {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 9/46
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// ----- 4.3.1. Deploying the process
log.info("--- #1. Deploying the process");
RepositoryService repositoryService = processEngine.getRepositoryService();
repositoryService.createDeployment()
.addClasspathResource("org/activiti/test/VacationRequest.bpmn20.xml")
.deploy();
log.info("Number of process definitions {}", repositoryService.createProcessDefinitionQ
for (ProcessDefinition p : repositoryService.createProcessDefinitionQuery().list()) {
log.info("PROCESS DEF [id={},name={},key={}]", p.getId(), p.getName(), p.getKey())
}
// ----- 4.3.2. Starting a process instance
log.info("--- #2. Starting a process instance");
// VacationRequest.bpmn20.xml L3-10
// --------------------------------------------------------------------------
// <process id="vacationRequest" name="Vacation request" isExecutable="true">
// ^^^^^^^^^^^^^^^
// <startEvent id="request" activiti:initiator="employeeName">
// ^^^^^^^*1 ^^^^^^^^^^^^ $employeeName = the use
// <extensionElements>
// <activiti:formProperty id="numberOfDays" name="Number of days" type="long" re
// ^^^^^^^^^^^^ ^^^^
// </activiti:formProperty>
// <activiti:formProperty id="startDate" name="First day of holiday (dd-MM-yyy)
// ^^^^^^^^^
// datePattern="dd-MM-yyyy hh:mm" required="true"></activiti:formProperty>
// <activiti:formProperty id="vacationMotivation" name="Motivation" type="string
// ^^^^^^^^^^^^^^^^^^ ^^^^^^
// </activiti:formProperty>
// </extensionElements>
// </startEvent>
// <activiti:formProperty>
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("employeeName", "Kermit");
variables.put("numberOfDays", new Integer(4));
variables.put("startDate", DateUtils.parseDate("1999-12-31", "yyyy-MM-dd"));
variables.put("vacationMotivation", "I'm really tired!");
// the process to run
// id : <process id="vacationRequest">
// arguments : <activiti:formProperty>
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("vacationReq
log.info("Number of process instances: " + runtimeService.createProcessInstanceQuery()
for (ProcessInstance p : runtimeService.createProcessInstanceQuery().list()) {
log.info("PROCESS INSTANCE [id={},pid={},pname={},pkey={}]"
, p.getId()
, p.getProcessDefinitionId()
, p.getProcessDefinitionName()
, p.getProcessDefinitionKey());
}
// ----- 4.3.3. Completing tasks (Reject Request)
// VacationRequest.bpmn20.xml L11-21
// --------------------------------------------------------------------------
// <sequenceFlow id="flow1" sourceRef="request" targetRef="handleRequest"></sequence
// ^^^^^^^*1 ^^^^^^^^^^^^^*2
// <userTask id="handleRequest" name="Handle vacation request" activiti:candidateGro
// ^^^^^^^^^^^^^*2
// <documentation>${employeeName} would like to take ${numberOfDays} day(s) of vac
// (Motivation: ${vacationMotivation}).</documentation>
// <extensionElements>
// <activiti:formProperty id="vacationApproved" name="Do you approve this vacati
// ^^^^^^^^^^^^^^^^
// required="true">
// <activiti:value id="true" name="Approve"></activiti:value>
// <activiti:value id="false" name="Reject"></activiti:value>
// </activiti:formProperty>
// <activiti:formProperty id="managerMotivation" name="Motivation" type="string
// ^^^^^^^^^^^^^^^^^
// </extensionElements>
// </userTask>
log.info("--- #3. Completing tasks (Reject Request)");
// Fetch all tasks for the management group
TaskService taskService = processEngine.getTaskService();
List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("management").list
for (Task task : tasks) {
if (task.getProcessDefinitionId().startsWith("vacationRequest")){
if (task.getTaskDefinitionKey().equals("handleRequest")) {
// Description is <documentation>.
log.info("TASK REJECT REQ [{}]", task.getDescription());
// Do task (reject application)
Map<String, Object> taskVariables = new HashMap<String, Object>();
taskVariables.put("vacationApproved", "false");
taskVariables.put("managerMotivation", "We have a tight deadline!");
taskService.complete(task.getId(), taskVariables);
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 10/46
実⾏ログ
I got it.
BPMNの配備 (RepositoryService?)
プロセス開始 (RuntimeService?)
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
}
}
}
// ----- 4.3.3. Completing tasks (Adjust rejected request)
// VacationRequest.bpmn20.xml L22-23
// --------------------------------------------------------------------------
// <sequenceFlow id="flow2" sourceRef="handleRequest" targetRef="requestApprovedDecisi
// ^^^^^^^^^^^^^*2 ^^^^^^^^^^^^^^^^^^^^^
// <exclusiveGateway id="requestApprovedDecision" name="Request approved?"></exclusive
// ^^^^^^^^^^^^^^^^^^^^^^^*3
//
// VacationRequest.bpmn20.xml L30-35
// --------------------------------------------------------------------------
// <sequenceFlow id="flow5" name="denied" sourceRef="requestApprovedDecision" targetRe
// ^^^^^^^^^^^^^^^^^^^^^^^*3
// <conditionExpression xsi:type="tFormalExpression"><![CDATA[${vacationApp
// ^^^^^^^^^^^^^^
// </conditionExpression>
// </sequenceFlow>
// <userTask id="adjustVacationRequestTask" name="Adjust vacation request" activiti:a
// ^^^^^^^^^^^^^^^^^^^^^^^^^*4
// <documentation>Your manager has disapproved your vacation request for ${n
// Reason: ${managerMotivation}</documentation>
log.info("--- #4. Completing tasks (Adjust rejected request)");
taskService = processEngine.getTaskService();
tasks = taskService.createTaskQuery().active().list();
for (Task task : tasks) {
if (task.getProcessDefinitionId().startsWith("vacationRequest")){
if (task.getTaskDefinitionKey().equals("adjustVacationRequestTask")) {
// Description is <documentation>.
log.info("ADJUST REJECT REQ [{}]", task.getDescription());
}
}
}
} catch (Throwable th) {
log.error("ERROR", th);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
16-03-24 00:24:21 [INFO ] Initializing process engine using configuration 'file:/Users/atsushi/E
16-03-24 00:24:21 [INFO ] initializing process engine for resource file:/Users/atsushi/EclipseWo
16-03-24 00:24:21 [INFO ] Loading XML bean definitions from resource loaded through InputStream
16-03-24 00:24:22 [INFO ] performing create on engine with resource org/activiti/db/create/activ
16-03-24 00:24:22 [INFO ] performing create on history with resource org/activiti/db/create/acti
16-03-24 00:24:22 [INFO ] performing create on identity with resource org/activiti/db/create/act
16-03-24 00:24:22 [INFO ] ProcessEngine default created
16-03-24 00:24:22 [INFO ] initialised process engine default
16-03-24 00:24:22 [INFO ] --- #1. Deploying the process
16-03-24 00:24:22 [INFO ] Processing resource org/activiti/test/VacationRequest.bpmn20.xml
16-03-24 00:24:23 [INFO ] Number of process definitions 1
16-03-24 00:24:23 [INFO ] PROCESS DEF [id=vacationRequest:1:4,name=Vacation request,key=vacation
16-03-24 00:24:23 [INFO ] --- #2. Starting a process instance
16-03-24 00:24:23 [INFO ] Number of process instances: 1
16-03-24 00:24:23 [INFO ] PROCESS INSTANCE [id=5,pid=vacationRequest:1:4,pname=Vacation request,
16-03-24 00:24:23 [INFO ] --- #3. Completing tasks (Reject Request)
16-03-24 00:24:23 [INFO ] TASK REJECT REQ [Kermit would like to take 4 day(s) of vacation (Motiv
16-03-24 00:24:23 [INFO ] --- #4. Completing tasks (Adjust rejected request)
16-03-24 00:24:23 [INFO ] ADJUST REJECT REQ [Your manager has disapproved your vacation request
Reason: We have a tight deadline!]
1
2
3
4
5
log.info("--- #1. Deploying the process");
RepositoryService repositoryService = processEngine.getRepositoryService();
repositoryService.createDeployment()
.addClasspathResource("org/activiti/test/VacationRequest.bpmn20.xml")
.deploy()
1
2
3
4
5
6
7
8
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("employeeName", "Kermit");
variables.put("numberOfDays", new Integer(4));
variables.put("startDate", DateUtils.parseDate("1999-12-31", "yyyy-MM-dd"));
variables.put("vacationMotivation", "I'm really tired!");
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("vacationRequest", variabl
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 11/46
http://activiti.org/javadocs/org/activiti/engine/RuntimeService.html
プロセスIDを指定してプロセスを開始する。⼊⼒値がある場合には Map 形式で投⼊する
RuntimeService?.startProcessInstanceByKey?(String processDefinitionId?, Map<String,Object>
variables) でプロセスを開始する
processDefinitionId? : BPMN process id
<process id="vacationRequest" name="Vacation request" isExecutable="true">
variables : BPMN <startEvent> に定義された⼊⼒値
タスク実⾏ (TaskService?)
プロセスが開始されたり、タスクが実⾏されたら、後続処理は ユーザによる⼊⼒待ちまで ProcessEngine? が実⾏す
ユーザの⼊⼒待ちになっているタスクのリストから、今回実⾏するタスクを選んで実⾏する
manager 決済のタスクのうち
プロセスID vacationRequest で始まり
タスクが名が handleRequest なもの
プロセスIDには、プロセス名に version ⼀意ID がつく。今回の場合 "vacationRequest:1:4" となる
cf. 6.Deployment
http://activiti.org/javadocs/org/activiti/engine/TaskService.html
TaskServcie?.complete(String taskId, Map<String,Object> variables) でタスクを実⾏する。⼊⼒値が
ある場合には Map 形式で投⼊する
taskId : TaskService?.crateTaskQeury?(). ... .list() で取得したタスクのID
variables : BPMN <userTask> に定義された⼊⼒値
<userTask> <documentation> task.getDescription() で取得できる
log.info("TASK REJECT REQ [{}]", task.getDescription());
4.3.4.プロセスの Suspend Activate
<startEvent id="request" activiti:initiator="employeeName">
<extensionElements>
<activiti:formProperty id="numberOfDays" name="Number of days" type="long" required="true"></ac
<activiti:formProperty id="startDate" name="First day of holiday (dd-MM-yyy)" type="date"
datePattern="dd-MM-yyyy hh:mm" required="true"></activiti:formProperty>
<activiti:formProperty id="vacationMotivation" name="Motivation" type="string"></activiti:formP
</extensionElements>
</startEvent>
<userTask id="handleRequest" name="Handle vacation request" activiti:candidateGroups="management">
<documentation>${employeeName} would like to take ${numberOfDays} day(s) of vacation
(Motivation: ${vacationMotivation}).</documentation>
<extensionElements>
<activiti:formProperty id="vacationApproved" name="Do you approve this vacation" type="enum" re
<activiti:value id="true" name="Approve"></activiti:value>
<activiti:value id="false" name="Reject"></activiti:value>
</activiti:formProperty>
<activiti:formProperty id="managerMotivation" name="Motivation" type="string"></activiti:formPr
</extensionElements>
</userTask>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
TaskService taskService = processEngine.getTaskService();
List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("management").list();
for (Task task : tasks) {
if (task.getProcessDefinitionId().startsWith("vacationRequest")){
if (task.getTaskDefinitionKey().equals("handleRequest")) {
// Description is <documentation>.
log.info("TASK REJECT REQ [{}]", task.getDescription());
// Do task (reject application)
Map<String, Object> taskVariables = new HashMap<String, Object>();
taskVariables.put("vacationApproved", "false");
taskVariables.put("managerMotivation", "We have a tight deadline!");
taskService.complete(task.getId(), taskVariables);
}
}
}
https://github.com/kagyuu/ActivitiExam/blob/master/src/main/java/com/snail/exam/MyProcess2.java
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 12/46
実⾏ログ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package com.snail.exam;
import java.util.HashMap;
import java.util.Map;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.runtime.ProcessInstance;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyProcess2 {
private static final Logger log = LoggerFactory.getLogger(MyProcess2.class);
public static void main(String[] args) {
try {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// ----- 4.3.1. Deploying the process
log.info("--- #1. Deploying the process");
RepositoryService repositoryService = processEngine.getRepositoryService();
repositoryService.createDeployment()
.addClasspathResource("org/activiti/test/VacationRequest.bpmn20.xml")
.deploy();
// ----- 4.3.4. Suspending and activating a process
log.info("--- #2. Suspend Process");
repositoryService.suspendProcessDefinitionByKey("vacationRequest");
// ----- 4.3.2. Starting a process instance
log.info("--- #3. Starting a process instance (will fail)");
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("employeeName", "Kermit");
variables.put("numberOfDays", new Integer(4));
variables.put("startDate", DateUtils.parseDate("1999-12-31", "yyyy-MM-dd"));
variables.put("vacationMotivation", "I'm really tired!");
// the process to run
// id : <process id="vacationRequest">
// arguments : <activiti:formProperty>
RuntimeService runtimeService = processEngine.getRuntimeService();
try {
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("vacation
} catch (ActivitiException e) {
log.error("ERROR", e);
}
// ----- 4.3.4. Suspending and activating a process
log.info("--- #5. Activate Process");
repositoryService.activateProcessDefinitionByKey("vacationRequest");
log.info("--- #6. Starting a process instance (will success)");
try {
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("vacation
log.info("{} was started", processInstance.getProcessDefinitionId());
} catch (ActivitiException e) {
log.error("ERROR", e);
}
} catch (Throwable th) {
log.error("ERROR", th);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
16-03-25 01:12:03 [INFO ] Initializing process engine using configuration 'file:/Users/atsushi/E
16-03-25 01:12:03 [INFO ] initializing process engine for resource file:/Users/atsushi/EclipseWo
16-03-25 01:12:03 [INFO ] Loading XML bean definitions from resource loaded through InputStream
16-03-25 01:12:04 [INFO ] performing create on engine with resource org/activiti/db/create/activ
16-03-25 01:12:04 [INFO ] performing create on history with resource org/activiti/db/create/acti
16-03-25 01:12:05 [INFO ] performing create on identity with resource org/activiti/db/create/act
16-03-25 01:12:05 [INFO ] ProcessEngine default created
16-03-25 01:12:05 [INFO ] initialised process engine default
16-03-25 01:12:05 [INFO ] --- #1. Deploying the process
16-03-25 01:12:05 [INFO ] Processing resource org/activiti/test/VacationRequest.bpmn20.xml
16-03-25 01:12:06 [INFO ] --- #2. Suspend Process
16-03-25 01:12:06 [INFO ] --- #3. Starting a process instance (will fail)
16-03-25 01:12:06 [INFO ] Processing resource org/activiti/test/VacationRequest.vacationRequest.
16-03-25 01:12:06 [INFO ] Processing resource org/activiti/test/VacationRequest.bpmn20.xml
16-03-25 01:12:06 [ERROR] ERROR
org.activiti.engine.ActivitiException: Cannot start process instance. Process definition Vacatio
at org.activiti.engine.impl.cmd.StartProcessInstanceCmd.execute(StartProcessInstanceCmd.java
at org.activiti.engine.impl.cmd.StartProcessInstanceCmd.execute(StartProcessInstanceCmd.java
at org.activiti.engine.impl.interceptor.CommandInvoker.execute(CommandInvoker.java:24) ~[act
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 13/46
4.4 Query API
タスクの検索
TaskQuery? NativeTaskQuery? を使うことができる
TaskQuery?
NativeTaskQuery?
クラス図
NativeTaskQuery? の列名
20
21
22
23
24
25
26
27
28
29
30
at org.activiti.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInte
at org.activiti.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:31) ~[act
at org.activiti.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:40) ~[a
at org.activiti.engine.impl.cfg.CommandExecutorImpl.execute(CommandExecutorImpl.java:35) ~[a
at org.activiti.engine.impl.RuntimeServiceImpl.startProcessInstanceByKey(RuntimeServiceImpl.
at com.snail.exam.MyProcess2.main(MyProcess2.java:49) ~[classes/:na]
16-03-25 01:12:06 [INFO ] --- #5. Activate Process
16-03-25 01:12:06 [INFO ] --- #6. Starting a process instance (will success)
16-03-25 01:12:06 [INFO ] Processing resource org/activiti/test/VacationRequest.vacationRequest.
16-03-25 01:12:06 [INFO ] Processing resource org/activiti/test/VacationRequest.bpmn20.xml
16-03-25 01:12:06 [INFO ] vacationRequest:1:4 was started
1
2
3
4
5
List<Task> tasks = taskService.createTaskQuery()
.taskAssignee("kermit")
.processVariableValueEquals("orderId", "0815")
.orderByDueDate().asc()
.list();
1
2
3
4
5
6
7
8
9
List<Task> tasks = taskService.createNativeTaskQuery()
.sql("SELECT count(*) FROM " + managementService.getTableName(Task.class) + " T WHERE T.NAM
.parameter("taskName", "gonzoTask")
.list();
long count = taskService.createNativeTaskQuery()
.sql("SELECT count(*) FROM " + managementService.getTableName(Task.class) + " T1, "
+ managementService.getTableName(VariableInstanceEntity.class) + " V1 WHERE V1.TASK_ID
.count();
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 14/46
その他の Query
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 15/46
代表的な TaskQuery? によるタスクの検索と同様に、ProcessEngine? から Service を取得して、Service から
Query を取得して、検索を⾏う。
どんな検索ができるかは Javadoc を参照
http://activiti.org/javadocs/org/activiti/engine/query/Query.html
4.5.Variables
プロセス変数は ACT_RU_VARIABLE に格納される
アクセス⽅法
BPMN の中の EL
${myVar}
${myBean.myProperty} Object も⼊れられるようだけど、⽂字列にしといたほうが無難だよね
暗黙オブジェクト
${execution} DelegateExecution?
${task} DelegateTask?
${authenticatedUserId?} String
Java Service Task execution
JavaDelegate?#execution(DelegateExecution? execution)
Object execution.getVariable(String variableName);
void execution.setVariable(String variableName, Object value);
Map<String,Object> execution.getVariables();
RuntimeService?
Object execution.getVariable(String executionId, String variableName);
void execution.setVariable(String executionId, String variableName, Object value);
Map<String,Object> execution.getVariables(String executionId);
TaskSerivce?
Object execution.getVariable(String taskId, String variableName);
void execution.setVariable(String taskId, String variableName, Object value);
Map<String,Object> execution.getVariables(String taskId);
変数をたくさん取り出すときには、Map<String,Object> getVariables() を使って⼀気に取り出す。変数は RDB
のテーブルから取り出しているので、⼀気に読み書きしたほうが効率的
変数スコープ
getVariable() getVariableLocal?() があって、変数スコープがあるようだけどよう分からん
こんな BPMN を作ってみた
B,C setVariablesLocal?() した変数は、D,E で⾒られなかたりするのかな...と思ったけどそうでもないら
しい
Task では、現在の Variable を表⽰して、⾃分のタスク名の変数を setVariable() setVariableLocal?
() する
https://github.com/kagyuu/ActivitiExam/blob/master/src/main/java/com/snail/exam/VariableTask.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.snail.exam;
import java.util.ArrayList;
import java.util.List;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class VariableTask implements JavaDelegate {
private static final Logger log = LoggerFactory.getLogger(VariableTask.class);
@Override
public void execute(DelegateExecution execution) throws Exception {
String id = execution.getCurrentActivityName();
log.info(id);
// Dump variables
List<String> keys = new ArrayList<String>(execution.getVariableNames());
keys.sort((o1,o2)->{return o1.compareTo(o2);});
keys.forEach((key)->{
log.info("@{} EXEC SCOPE {} = {}", id, key, execution.getVariable(key));
});
List<String> keysLocal = new ArrayList<String>(execution.getVariableNamesLocal());
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 16/46
実⾏結果
よくわからない。Local のことは忘れて、プロセス・インスタンのスコープで変数が保持されると思っておいたほう
が良さそう
4.7 Unit Test
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
keysLocal.sort((o1,o2)->{return o1.compareTo(o2);});
keysLocal.forEach((key)->{
log.info("@{} LOCAL SCOPE {} = {}", id, key, execution.getVariableLocal(key));
});
// Update variables
execution.getVariableNames().forEach((name)->{
execution.setVariable(name, id);
});
execution.getVariableNamesLocal().forEach((name)->{
execution.setVariableLocal(name, id);
});
execution.setVariable(id + "_EXEC", id);
execution.setVariable(id + "_LOCAL", id);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
16-05-21 23:38:30 [INFO ] Initializing process engine using configuration 'file:/Users/atsus
16-05-21 23:38:30 [INFO ] initializing process engine for resource file:/Users/atsushi/Eclip
16-05-21 23:38:30 [INFO ] Loading XML bean definitions from resource loaded through InputStr
16-05-21 23:38:31 [INFO ] performing create on engine with resource org/activiti/db/create/a
16-05-21 23:38:31 [INFO ] performing create on history with resource org/activiti/db/create/
16-05-21 23:38:31 [INFO ] performing create on identity with resource org/activiti/db/create
16-05-21 23:38:31 [INFO ] ProcessEngine default created
16-05-21 23:38:31 [INFO ] initialised process engine default
16-05-21 23:38:31 [INFO ] --- #1. Deploying the process
16-05-21 23:38:31 [INFO ] Processing resource org/activiti/test/VariableProcess.bpmn
16-05-21 23:38:32 [INFO ] TaskA
16-05-21 23:38:32 [INFO ] @TaskA EXEC SCOPE start = Start
16-05-21 23:38:32 [INFO ] @TaskA LOCAL SCOPE start = Start
16-05-21 23:38:32 [INFO ] TaskB
16-05-21 23:38:32 [INFO ] @TaskB EXEC SCOPE TaskA_EXEC = TaskA
16-05-21 23:38:32 [INFO ] @TaskB EXEC SCOPE TaskA_LOCAL = TaskA
16-05-21 23:38:32 [INFO ] @TaskB EXEC SCOPE start = TaskA
16-05-21 23:38:32 [INFO ] TaskC
16-05-21 23:38:32 [INFO ] @TaskC EXEC SCOPE TaskA_EXEC = TaskB
16-05-21 23:38:32 [INFO ] @TaskC EXEC SCOPE TaskA_LOCAL = TaskB
16-05-21 23:38:32 [INFO ] @TaskC EXEC SCOPE TaskB_EXEC = TaskB
16-05-21 23:38:32 [INFO ] @TaskC EXEC SCOPE TaskB_LOCAL = TaskB
16-05-21 23:38:32 [INFO ] @TaskC EXEC SCOPE start = TaskB
16-05-21 23:38:32 [INFO ] TaskD
16-05-21 23:38:32 [INFO ] @TaskD EXEC SCOPE TaskA_EXEC = TaskC
16-05-21 23:38:32 [INFO ] @TaskD EXEC SCOPE TaskA_LOCAL = TaskC
16-05-21 23:38:32 [INFO ] @TaskD EXEC SCOPE TaskB_EXEC = TaskC
16-05-21 23:38:32 [INFO ] @TaskD EXEC SCOPE TaskB_LOCAL = TaskC
16-05-21 23:38:32 [INFO ] @TaskD EXEC SCOPE TaskC_EXEC = TaskC
16-05-21 23:38:32 [INFO ] @TaskD EXEC SCOPE TaskC_LOCAL = TaskC
16-05-21 23:38:32 [INFO ] @TaskD EXEC SCOPE start = TaskC
16-05-21 23:38:32 [INFO ] TaskE
16-05-21 23:38:32 [INFO ] @TaskE EXEC SCOPE TaskA_EXEC = TaskD
16-05-21 23:38:32 [INFO ] @TaskE EXEC SCOPE TaskA_LOCAL = TaskD
16-05-21 23:38:32 [INFO ] @TaskE EXEC SCOPE TaskB_EXEC = TaskD
16-05-21 23:38:32 [INFO ] @TaskE EXEC SCOPE TaskB_LOCAL = TaskD
16-05-21 23:38:32 [INFO ] @TaskE EXEC SCOPE TaskC_EXEC = TaskD
16-05-21 23:38:32 [INFO ] @TaskE EXEC SCOPE TaskC_LOCAL = TaskD
16-05-21 23:38:32 [INFO ] @TaskE EXEC SCOPE TaskD_EXEC = TaskD
16-05-21 23:38:32 [INFO ] @TaskE EXEC SCOPE TaskD_LOCAL = TaskD
16-05-21 23:38:32 [INFO ] @TaskE EXEC SCOPE start = TaskD
16-05-21 23:38:32 [INFO ] TaskF
16-05-21 23:38:32 [INFO ] @TaskF EXEC SCOPE TaskA_EXEC = TaskE
16-05-21 23:38:32 [INFO ] @TaskF EXEC SCOPE TaskA_LOCAL = TaskE
16-05-21 23:38:32 [INFO ] @TaskF EXEC SCOPE TaskB_EXEC = TaskE
16-05-21 23:38:32 [INFO ] @TaskF EXEC SCOPE TaskB_LOCAL = TaskE
16-05-21 23:38:32 [INFO ] @TaskF EXEC SCOPE TaskC_EXEC = TaskE
16-05-21 23:38:32 [INFO ] @TaskF EXEC SCOPE TaskC_LOCAL = TaskE
16-05-21 23:38:32 [INFO ] @TaskF EXEC SCOPE TaskD_EXEC = TaskE
16-05-21 23:38:32 [INFO ] @TaskF EXEC SCOPE TaskD_LOCAL = TaskE
16-05-21 23:38:32 [INFO ] @TaskF EXEC SCOPE TaskE_EXEC = TaskE
16-05-21 23:38:32 [INFO ] @TaskF EXEC SCOPE TaskE_LOCAL = TaskE
16-05-21 23:38:32 [INFO ] @TaskF EXEC SCOPE start = TaskE
16-05-21 23:38:32 [INFO ] @TaskF LOCAL SCOPE TaskA_EXEC = TaskE
16-05-21 23:38:32 [INFO ] @TaskF LOCAL SCOPE TaskA_LOCAL = TaskE
16-05-21 23:38:32 [INFO ] @TaskF LOCAL SCOPE TaskB_EXEC = TaskE
16-05-21 23:38:32 [INFO ] @TaskF LOCAL SCOPE TaskB_LOCAL = TaskE
16-05-21 23:38:32 [INFO ] @TaskF LOCAL SCOPE TaskC_EXEC = TaskE
16-05-21 23:38:32 [INFO ] @TaskF LOCAL SCOPE TaskC_LOCAL = TaskE
16-05-21 23:38:32 [INFO ] @TaskF LOCAL SCOPE TaskD_EXEC = TaskE
16-05-21 23:38:32 [INFO ] @TaskF LOCAL SCOPE TaskD_LOCAL = TaskE
16-05-21 23:38:32 [INFO ] @TaskF LOCAL SCOPE TaskE_EXEC = TaskE
16-05-21 23:38:32 [INFO ] @TaskF LOCAL SCOPE TaskE_LOCAL = TaskE
16-05-21 23:38:32 [INFO ] @TaskF LOCAL SCOPE start = TaskE
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 17/46
@Deployment BPMN を配備することもできる
4.9 The process engine in a web application
コンソールアプリと同じように ProcessEngines?.getDefaultProcessEngine?() ProcessEngine? を取得する
が、アプリ再起動で確実に設定ファイルが反映されるように ServletContextListener? ProcessEngine?.init(),
ProcessEngine?.destroy() を実⾏する
6. Deployment
BPMN の配備
ActivitiExplorer? [Import]
RepositoryService? API を使う
repositoryService
.createDeployment()
.addClasspathResource("org/activiti/test/VacationRequest.bpmn20.xml")
.deploy();
配備されたプロセス定義の名称
{processDefinitionKey}:{processDefinitionVersion}:{generated-id}
@Deplpyment(resources = {"org/activiti/examples/bpmn/executionListener/ExecutionListenersFieldInjectionProc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class MyBusinessProcessTest {
@Rule
public ActivitiRule activitiRule = new ActivitiRule();
@Test
@Deployment
public void ruleUsageExample() {
RuntimeService runtimeService = activitiRule.getRuntimeService();
runtimeService.startProcessInstanceByKey("ruleUsage");
TaskService taskService = activitiRule.getTaskService();
Task task = taskService.createTaskQuery().singleResult();
assertEquals("My Task", task.getName());
taskService.complete(task.getId());
assertEquals(0, runtimeService.createProcessInstanceQuery().count());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
@WebServletContextListener
public class ProcessEnginesServletContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent servletContextEvent) {
ProcessEngines.init();
}
public void contextDestroyed(ServletContextEvent servletContextEvent) {
ProcessEngines.destroy();
}
}
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 18/46
processDefinitionKey? プロセス名
processDefinitionVersion? バージョン
generated-id は、⾃動採番の UID
独⾃ Java プログラム (Jata TaskListener) の配備
実⾏環境の Classpath に⼊れる
tomcat なら ${tomcat.home}/lib とか
7.標準 BPMN 2.0
Eclipse Activiti Desinger または、Activiti Explorer で作る
拡張⼦ .bpmn20.xml または .bpmn
BPMNの基本構造
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<definitions id="definitions"
targetNamespace="http://activiti.org/bpmn20"
xmlns:activiti="http://activiti.org/bpmn"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL">
<process id="financialReport" name="Monthly financial report reminder process">
<startEvent id="theStart" />
<sequenceFlow id='flow1' sourceRef='theStart' targetRef='writeReportTask' />
<userTask id="writeReportTask" name="Write monthly financial report" >
<documentation>
Write monthly financial report for publication to shareholders.
</documentation>
<potentialOwner>
<resourceAssignmentExpression>
<formalExpression>accountancy</formalExpression>
</resourceAssignmentExpression>
</potentialOwner>
</userTask>
<sequenceFlow id='flow2' sourceRef='writeReportTask' targetRef='verifyReportTask' />
<userTask id="verifyReportTask" name="Verify monthly financial report" >
<documentation>
Verify monthly financial report composed by the accountancy department.
This financial report is going to be sent to all the company shareholders.
</documentation>
<potentialOwner>
<resourceAssignmentExpression>
<formalExpression>management</formalExpression>
</resourceAssignmentExpression>
</potentialOwner>
</userTask>
<sequenceFlow id='flow3' sourceRef='verifyReportTask' targetRef='theEnd' />
<endEvent id="theEnd" />
</process>
</definitions>
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 19/46
ルート要素は <definitions>
その下に、<process> <error> <signal> <message> がくる
<process> 処理フロー定義
<error> エラー定義 ( <process> の中で、エラーを発⽣するときに指定する )
<signal> シグナル定義 ( <process> の中で、(全インスタンスに) シグナルを発⾏・受信するときに指定す
る。承認者が退職したので処理中フローを全部差し戻しとか )
<message> メッセージ定義 ( <process> の中で、メッセージを発⾏・受信するときに指定する。同時並⾏し
て実施中のサブフローを中⽌とか )
<process> の下に <Event> <Task> <Flow> がくる
<Event>
<startEvent> 開始点
ProcessInstance processInstance
= runtimeService.startProcessInstanceByKey("financialReport");
でプロセスを開始すると、<startEvent> からプロセスが始まる
<endEvent> 終了点
プロセスは <endEvent> までいくと終了する。終了したプロセスの実⾏履歴は History Service
(processEngine.getHistoryService?()) で取得できる
<Task>
<userTask> ユーザタスク
ユーザ⼊⼒画⾯
potentialOwner> で、実⾏可能なユーザ(または ロール)を指定できる。
実⾏権限ロールの⼈がタスクを個⼈指定で処理要求したいときには
List<Task> tasks = taskService.createTaskQuery().taskAssignee("fozzie").list();
for (Task task : tasks) {
if (....) {
taskService.claim(task.getId(), "fozzie");
}
}
プログラムでタスクを終わらせたい場合には
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 20/46
List<Task> tasks = taskService.createTaskQuery().taskAssignee("fozzie").list();
for (Task task : tasks) {
if (....) {
taskService.complete(task.getId());
}
}
<Flow>
<sequenceFlow> フロー
sorceRef targetRef <Event> <Task> id を設定して、処理の流れを作る
条件分岐は、sequenceFlow の⼀種
8.Activiti 拡張 BPMN 2.0
BPMN 規格⾃体に、BPMN を拡張できる仕様が備わっている
8.2.Event
Event は、Eclipse Activiti Designer のパレットから Drag&Drop すれば良い
Event の設定は、Activiti Designer 上の properties で編集すると BPMN (XML) に反映される
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 21/46
<timerEventDefinition?>
<?Event> の⼦要素にすると、指定したタイマーによって Event が発効する
Note. timers are only fired when the job or async executor is enabled (i.e.
jobExecutorActivate? or asyncExecutorActivate? needs to be set to true in the
activiti.cfg.xml, since the job and async executor are disabled by default).
https://en.wikipedia.org/wiki/ISO_8601 (⽇本語Wikipedia には、DurationIntervals の記述な
)
<errorEventDefinition?>
<startEvent> の⼦要素にすると、エラーの発⽣を契機に Event が発効する
<endEvent> の⼦要素にすると、その <endEvent> に到達した時に指定されたエラーでフローを終了する
Java Exception の発⽣を検知して <endEvent> に跳ぶのではなく、その <endEvent> に到達した時に指定
されたエラーでフローを終了する
<signalEventDefinition?>
シグナルは、全プロセスインスタンスに送られる。
承認担当者が、不正処理で馘になったので、処理中のワークフローを全部差し戻しとか
<intermediateThrowEvent?> でシグナルを発効する。
activiti:async="true" をつけると⾮同期になる
シグナルが発⾏すると、全プロセスインスタンスで <intermidiateCatchEvnet?> からのフローが始まる
プログラムからシグナルを強制発効する
RuntimeService.signalEventReceived(String signalName);
RuntimeService.signalEventReceived(String signalName, String executionId);
引き数が⼆つある⽅は、特定のインスタンスのみにシグナルを発効する。テストとかで使うのかな
シグナルを発⾏したプロセスインスタンスもプロセスを受信しちゃうんで、プロセスを発⾏した後に何かすることは出
来ないことに留意する
<messageEventDefinition?>
メッセージは、特定のプロセスに送られる。
BPMNのフローからメッセージを送ることはできない
<startEvent> の⼦要素にすると、メッセージの受信を契機に Event が発効する
<intermediateCatchEvent?> の⼦要素にすると、メッセージ受信を契機にそこからフローが始まる
プログラムからメッセージを発効する
フローをはじめる (メッセージ受信を契機に実⾏できるフローがあるだけでは、勝⼿にフローは実⾏されないことに
注意。どこかの Process Engine が実⾏する必要がある)
あるメッセージを契機にはじまるプロセスの⼀覧 (<startEvent> がメッセージ契機なプロセスの⼀覧)
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.messageEventSubscription("newCallCenterBooking")
.singleResult();
RuntimeService.messageEventReceived(String messageName, String executionId);
RuntimeService.messageEventReceived(String messageName, String executionId, HashMap<String, Object>
ProcessInstance.startProcessInstanceByMessage(String messageName);
ProcessInstance.startProcessInstanceByMessage(String messageName, Map<String, Object> processVariab
ProcessInstance.startProcessInstanceByMessage(String messageName, String businessKey, Map<String, O
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 22/46
あるメッセージを契機に特殊処理が⾛るプロセスの⼀覧 (<intermediateCatch> でメッセージを待っているプロ
セスインスタンスの⼀覧)
Execution execution = runtimeService.createExecutionQuery()
.messageEventSubscriptionName("paymentReceived")
.variableValueEquals("orderId", message.getOrderId())
.singleResult();
JMSなどを使って、外部システムのイベントを契機にフローを動かしたい時とかに使う
<terminateEventDefinition?>
<endEvnet> の⼦要素
平⾏して動いているフローが有った場合には強制終了して、プロセスインスタンスを完全に終了させる
<boundaryEvent>
Task に張り付いて、Task 内のイベントに基づいてフローを開始する
<timerEventDefinition?> をつけると、主処理とは別に Task 終了後⼀定時間してから起動するフローを書ける
<errorEventDefinition?> をつけると、Task / Sub process があるエラーで終わった場合に起動するフロー
を書ける
<signalEventDefinition?> をつけると、当該タスクの実効待中にシグナルを受信した時のフローを書ける
<messageEventDefinition?> をつけると、当該タスクの実効待中にメッセージを受信した時のフローを書ける
8.3 Sequence Flow
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 23/46
Sequence Flow は、Eclipse Activiti Designer では、遷移元の EventTaskGatewayをシングルクリック
した後に、[] (Create Connection) を遷移先に Drag すればできる。あるいは、シングルクリックメニューから
遷移先を作ると、⾃動的に Sequence Flow で結ばれている
Sequence Flow は、EventTaskGateway を結びつける
<sequenceFlow id="flow1" sourceRef="theStart" targetRef="theTask" />
sourceRef 属性 : 遷移元
targetRef 属性 : 遷移先
8.4 Gateways
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 24/46
Gateway は、Eclipse Activiti Designer のパレットから Drag&Drop すれば良い
<exclusiveGateway>
排他の分岐
⾏き先の <sequenceFlow> は、<conditionExpression> ⼦要素を持ち、評価式が true になる最初の
<sequenceFlow> に進む (⼀つの Flow にしか進まない)
<conditionExpression> xsi:type は、現時点では tFormalExpression? (EL) しか設定できない
1
2
<exclusiveGateway id="exclusiveGw" name="Exclusive Gateway" />
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 25/46
評価式は Eclipse Activiti Designer で、<sequenceFlow> をクリックして properties ペインで設定で
きる
この設定から⽣成される bpmn (xml)
<parallelGateway>
並⾏実⾏の分岐
⾏き先の <sequenceFlow> は、すべて同時に動き出す
<parallelGateway> が⾏き先な場合は、並⾏実⾏されている処理の待ち合わせになる
<sequenceFlow id="flow7" sourceRef="exclusivegateway1" targetRef="usertask3">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${val > 100}]]></conditionExpression>
</sequenceFlow>
3
4
5
6
7
8
9
10
11
12
13
<sequenceFlow id="flow2" sourceRef="exclusiveGw" targetRef="theTask1">
<conditionExpression xsi:type="tFormalExpression">${input == 1}</conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow3" sourceRef="exclusiveGw" targetRef="theTask2">
<conditionExpression xsi:type="tFormalExpression">${input == 2}</conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow4" sourceRef="exclusiveGw" targetRef="theTask3">
<conditionExpression xsi:type="tFormalExpression">${input == 3}</conditionExpression>
</sequenceFlow>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<startEvent id="theStart" />
<sequenceFlow id="flow1" sourceRef="theStart" targetRef="fork" />
<parallelGateway id="fork" />
<sequenceFlow sourceRef="fork" targetRef="receivePayment" />
<sequenceFlow sourceRef="fork" targetRef="shipOrder" />
<userTask id="receivePayment" name="Receive Payment" />
<sequenceFlow sourceRef="receivePayment" targetRef="join" />
<userTask id="shipOrder" name="Ship Order" />
<sequenceFlow sourceRef="shipOrder" targetRef="join" />
<parallelGateway id="join" />
<sequenceFlow sourceRef="join" targetRef="archiveOrder" />
<userTask id="archiveOrder" name="Archive Order" />
<sequenceFlow sourceRef="archiveOrder" targetRef="theEnd" />
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 26/46
<inclusiveGateway>
⾏き先の <sequenceFlow> は、<conditionExpression> ⼦要素を持ち、その評価式が true になる すべての
<sequenceFlow> が同時に動き出す (複数の Flow が並⾏実⾏される)
<inclusiveGateway> が⾏き先な場合は、並⾏実⾏されている処理の待ち合わせになる
<eventBasedGateway?>
⾏き先の <sequenceFlow> の、さらに⾏先は、<intermediateCatchEvent?> になっており、最初に受信した
イベントが⾏き先の <sequenceFlow> に進む (⼀つの Flow にしか進まない)
10分待ってシグナルが来なかったら次へ進むなど
19
20
<endEvent id="theEnd" />
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<startEvent id="theStart" />
<sequenceFlow id="flow1" sourceRef="theStart" targetRef="fork" />
<inclusiveGateway id="fork" />
<sequenceFlow sourceRef="fork" targetRef="receivePayment" >
<conditionExpression xsi:type="tFormalExpression">${paymentReceived == false}</conditionEx
</sequenceFlow>
<sequenceFlow sourceRef="fork" targetRef="shipOrder" >
<conditionExpression xsi:type="tFormalExpression">${shipOrder == true}</conditionExpressio
</sequenceFlow>
<userTask id="receivePayment" name="Receive Payment" />
<sequenceFlow sourceRef="receivePayment" targetRef="join" />
<userTask id="shipOrder" name="Ship Order" />
<sequenceFlow sourceRef="shipOrder" targetRef="join" />
<inclusiveGateway id="join" />
<sequenceFlow sourceRef="join" targetRef="archiveOrder" />
<userTask id="archiveOrder" name="Archive Order" />
<sequenceFlow sourceRef="archiveOrder" targetRef="theEnd" />
<endEvent id="theEnd" />
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<definitions id="definitions"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:activiti="http://activiti.org/bpmn"
targetNamespace="Examples">
<signal id="alertSignal" name="alert" />
<process id="catchSignal">
<startEvent id="start" />
<sequenceFlow sourceRef="start" targetRef="gw1" />
<eventBasedGateway id="gw1" />
<sequenceFlow sourceRef="gw1" targetRef="signalEvent" />
<sequenceFlow sourceRef="gw1" targetRef="timerEvent" />
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 27/46
8.5 Task
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<intermediateCatchEvent id="signalEvent" name="Alert">
<signalEventDefinition signalRef="alertSignal" />
</intermediateCatchEvent>
<intermediateCatchEvent id="timerEvent" name="Alert">
<timerEventDefinition>
<timeDuration>PT10M</timeDuration>
</timerEventDefinition>
</intermediateCatchEvent>
<sequenceFlow sourceRef="timerEvent" targetRef="exGw1" />
<sequenceFlow sourceRef="signalEvent" targetRef="task" />
<userTask id="task" name="Handle alert"/>
<exclusiveGateway id="exGw1" />
<sequenceFlow sourceRef="task" targetRef="exGw1" />
<sequenceFlow sourceRef="exGw1" targetRef="end" />
<endEvent id="end" />
</process>
</definitions>
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 28/46
8.5.1. User Task
<userTask>
ユーザの実⾏するタスク
<userTask id="theTask" name="Important task" />
配下の document に説明を書く。プログラムからは task.getDescription(); で取得可能
期限: activiti:dueDate 要素に ISO8601 date-time 形式 (yyyy-MM-ddThh:mm:ss) または time-duration
形式 (PT50M) で設定する
実⾏権限:
BPMN2.0規格では、<userTask> タグの配下に、<humanPerformer> または <potentialOwner> タグを⼊れ⼦
にして、そこでタスクを実⾏できるユーザやグループを定義する。この形式でも activiti は正しく動作する
activiti では、独⾃拡張として <userTask> タグに activiti:assigneeactiviti:candidateUsers
activiti:candidateGroups を定義できる
Eclipse Activiti Designer では、期限や権限は properties で編集できる。編集すると BPMN (XML) に反映さ
れる
8.5.2. Script Task
JSR-223 (Java Scripting API) で、BPMN内に定義された⽂字列のスクリプトを実⾏する。
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 29/46
フラグを⽴てるくらいなら使ってもいいかもね
ここに、がっつり処理ロジックを書いてもなかなかテストできないし、実⾏時に Syntax Error が起きるかもしれんし
プロセス変数の変更・設定
groovy を使う場合には、pom.xml
を追記する必要あり
8.5.3. Java Task
Javaコードを実⾏する
Activiti Spring コンテナ上で動いている場合には、Spring が管理している Bean lookup したり、その
任意のメソッドを実⾏できる。
JavaSE環境で実⾏するときには上記のように、クラス名をパッケージ名付きで指定する)
呼び出される Java コード
JavaDelegagte? を実装する
処理ロジックは void execute(DelegateExecution? execution) に記述する
DelegateExecution? からプロセススコープの (ACT_RU_VARIABLE テーブルに格納されている) 変数を取得・
変更できる cf. 4.5.Variables
パラメータの Injection
フィールド変数 text1text2 BPMN で指定した値を設定できる
エラー処理
1
2
3
4
5
6
7
8
<scriptTask id="theScriptTask" name="Execute script" scriptFormat="groovy">
<script>
sum = 0
for ( i in inputArray ) {
sum += i
}
</script>
</scriptTask>
1
2
3
4
<script>
def scriptVar = "test123"
execution.setVariable("myVar", scriptVar)
</script>
1
2
3
4
5
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.x.x<version>
</dependency>
1
2
3
<serviceTask id="javaService"
name="My Java Service Task"
activiti:class="org.activiti.MyJavaDelegate" />
1
2
3
4
5
6
7
8
9
public class MyJavaDelegate implements JavaDelegate {
public void execute(DelegateExecution execution) throws Exception {
String var = (String) execution.getVariable("input");
var = var.toUpperCase();
execution.setVariable("input", var);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
<serviceTask id="javaService" name="Java service invocation"
activiti:class="org.activiti.examples.bpmn.servicetask.ReverseStringsFieldInjected">
<extensionElements>
<activiti:field name="text1">
<activiti:expression>${genderBean.getGenderString(gender)}</activiti:expression>
</activiti:field>
<activiti:field name="text2">
<activiti:expression>Hello ${gender == 'male' ? 'Mr.' : 'Mrs.'} ${name}</activiti:express
</activiti:field>
</ extensionElements>
</ serviceTask>
1
2
3
4
<serviceTask id="servicetask1" name="Service Task" activiti:class="...">
<extensionElements>
<activiti:mapException errorCode="myErrorCode1"/>
</extensionElements>
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 30/46
例外が発⽣したら、エラーコード myErrorCode1 で終了
Exception の種類によってエラーコードを変える
Exception の親クラスを指定 (どの⼦クラスの例外が起きても、指定されたエラーコードをで終了する)
8.5.6. Email Task
activiti.cfg.xml で、SMTP サーバーの設定が必要
Activiti Explorer / REST API では、WEB-INF/classes/engine.properties
設定できるのは
activiti:field name="" 設定内容
to TO
from FROM
subject SUBJECT
cc CC
bcc BCC
charset ⽇本語なら iso-2022-jp やね
html HTML Mail 平⽂+EL で指定
text Text Mail 平⽂+EL で指定
htmlVar HTML Mail の全⽂が格納されているプロセス変数名
textVar Text Mail の全⽂が格納されているプロセス変数名
ignoreException 例外を無視
exceptionVariableName?ignoreException=true のとき、発⽣した Exception を格納するプロセス変数名
Eclipse Activiti Designer から設定可能
5 </serviceTask>
1
2
3
4
5
6
<serviceTask id="servicetask1" name="Service Task" activiti:class="...">
<extensionElements>
<activiti:mapException
errorCode="myErrorCode1">org.activiti.SomeException</activiti:mapException>
</extensionElements>
</serviceTask>
1
2
3
4
5
6
<serviceTask id="servicetask1" name="Service Task" activiti:class="...">
<extensionElements>
<activiti:mapException errorCode="myErrorCode1"
includeChildExceptions="true">org.activiti.SomeException</activiti:mapException>
</extensionElements>
</serviceTask>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<serviceTask id="mailtask1" name="Mail Task" activiti:type="mail">
<extensionElements>
<activiti:field name="from">
<activiti:string><![CDATA[order-shipping@thecompany.com]]></activiti:string>
</activiti:field>
<activiti:field name="to">
<activiti:expression><![CDATA[foo@example.com]]></activiti:expression>
</activiti:field>
<activiti:field name="subject">
<activiti:string><![CDATA[ENGLISH SUBJECT 日本語の件名]]></activiti:string>
</activiti:field>
<activiti:field name="charset">
<activiti:string><![CDATA[iso-2022-jp]]></activiti:string>
</activiti:field>
<activiti:field name="text">
<activiti:string><![CDATA[ENGLISH MESSAGE
日本語の本文]]></activiti:string>
</activiti:field>
</extensionElements>
</serviceTask>
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 31/46
⽇本語メールもOK (charset = iso-2022-jp にしておけば、あとは (commons-mail) やってくれる)
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 32/46
⽇本語部分は、iso-2022-jp (JISコード) base64 になっている
8.5.8. Camel Task (つかえない)
結局 Camel を実⾏する Java Class (Spring 管理下の Bean) を呼び出せるだけ
こうだったらよかったのに <実際にはこうなっていません!>
普通の Java Task から Camel を呼び出せば良いんでないかい
8.5.9. Manual Task
ユーザが Done を押すだけのタスク (ユーザがシステム外で何かやったことを確認するためのタスク)
8.5.10. Java Receive Task
1
2
3
4
5
6
7
<serviceTask id="i hope it" activiti:type="camel" >
<extensionElements>
<activiti:field name="from" stringValue="file:/a/b" />
<activiti:field name="to" stringValue=""log:edi_send" />
<activiti:field name="to" stringValue="ftp:/edi" />
</extensionElements>
</serviceTask>
1 <manualTask id="myManualTask" name="Call client for more information" />
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 33/46
シグナル待ちタスク
シグナル発⾏
8.5.11. Shell Task (つかえない)
ちゃんと動くけど、つかえない
Activiti Designer が未対応で、対応予定もなし https://forums.activiti.org/content/eclipse-
activiti-designer-and-shell-tasks
Activiti Desinger bpmn を編集すると <serviceTask> タグが消えてしまう!
Java Task で実装するのが良いだろう
8.15.12.Execution listener
プロセス開始、終了時の処理 (event="start/end")
bpmn
com.foo.ExecutionListenerOne?
旧バージョン (< 5.3) との互換性のため、
org.activiti.engine.impl.pvm.delegate.ExecutionListener? もあるが、そちらは使わない
イベントハンドラには、ExecutionListner? ではなく、JavaTask?
(org.activiti.engine.delegate.JavaDelegate?を継承したクラス) を指定してもよい
Flow 通過時の処理 (event なし)
bpmn
1 <receiveTask id="waitState" name="wait" />
1
2
3
4
5
6
7
8
ProcessInstance pi = runtimeService.startProcessInstanceByKey("receiveTask");
Execution execution = runtimeService.createExecutionQuery()
.processInstanceId(pi.getId())
.activityId("waitState")
.singleResult();
assertNotNull(execution);
runtimeService.signal(execution.getId());
1
2
3
4
5
6
7
8
9
10
<serviceTask id="shellEcho" activiti:type="shell" >
<extensionElements>
<activiti:field name="command" stringValue="cmd" />
<activiti:field name="arg1" stringValue="/c" />
<activiti:field name="arg2" stringValue="echo" />
<activiti:field name="arg3" stringValue="EchoTest" />
<activiti:field name="wait" stringValue="true" />
<activiti:field name="outputVariable" stringValue="resultVar" />
</extensionElements>
</serviceTask>
1
2
3
4
5
6
7
8
9
10
<process id="executionListenersProcess">
...
<extensionElements>
<activiti:executionListener class="com.foo.ExecutionListenerOne" event="start" />
</extensionElements>
...
<startEvent id="theStart">
<sequenceFlow sourceRef="theStart" ...
...
</process>
1
2
3
4
5
6
7
8
9
10
import org.activiti.engine.delegate.ExecutionListener;
import org.activiti.engine.delegate.ExecutionListenerExecution;
public class ExecutionListenerOne implements ExecutionListener {
public void notify(ExecutionListenerExecution execution) throws Exception {
execution.setVariable("variableSetInExecutionListener", "firstValue");
execution.setVariable("eventReceived", execution.getEventName());
}
}
1
2
3
4
5
6
<process id="executionListenersProcess">
...
<userTask id="firstTask" />
<sequenceFlow sourceRef="firstTask" targetRef="secondTask">
<extensionElements>
<activiti:executionListener class="com.foo.ExecutionListenerTwo" />
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 34/46
Flow には、event 属性がない (無視される)Flow には start end も無いんで
Flow のほかに、Gateway にも同様に Listener を設定できる
Task開始、終了時の処理 (event="start/end")
bpmn
bpmn から executionListener への Field Injection
bpmn
com.foo.FieldInjectedExecutionListener?
旧バージョン (< 5.3) との互換性のため、org.activiti.engine.impl.pvm.delegate.Expression もある
が、そちらは使わない
bpmn からプロセススコープの変数を Injection できる (ACT_RU_VARIABLE テーブルに格納されているプロセス固
有の変数 cf. 4.5.Variable
Unit Test では、RuntimeService? でプロセスを開始するときに、変数を設定してあげればいい
8.5.13. Task listener
User Task のイベント処理
event="create" (タスクが作られたとき)
event="assignment" (誰かにアサインされたとき)
event="complete" (完了したとき)
event="delete" (棄却されたとき)
bpmn
7
8
9
10
</extensionElements>
</sequenceFlow>
...
</process>
1
2
3
4
5
6
7
8
9
10
<process id="executionListenersProcess">
...
<userTask id="secondTask" >
<extensionElements>
<activiti:executionListener expression="com.foo.ExecutionListenerThree" event="end" />
</extensionElements>
</userTask>
<sequenceFlow sourceRef="secondTask" targetRef="thirdTask" />
...
</process>
1
2
3
4
5
6
7
8
9
10
11
<process id="executionListenersProcess">
<extensionElements>
<activiti:executionListener class="com.foo.FieldInjectedExecutionListener" event="start"
<activiti:field name="fixedValue" stringValue="Yes, I am " />
<activiti:field name="dynamicValue" expression="${myVar}" />
</activiti:executionListener>
</extensionElements>
...
</process>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import org.activiti.engine.delegate.ExecutionListener;
import org.activiti.engine.delegate.ExecutionListenerExecution;
import org.activiti.engine.delegate.Expression;
public class FieldInjectedExecutionListener implements ExecutionListener {
private Expression fixedValue;
private Expression dynamicValue;
public void notify(ExecutionListenerExecution execution) throws Exception {
execution.setVariable("var", fixedValue.getValue(execution).toString() + dynamicValue.ge
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Deployment(resources = {"org/activiti/examples/bpmn/executionListener/ExecutionListenersFieldIn
public void testExecutionListenerFieldInjection() {
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("myVar", "listening!");
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("executionListeners
Object varSetByListener = runtimeService.getVariable(processInstance.getId(), "var");
assertNotNull(varSetByListener);
assertTrue(varSetByListener instanceof String);
// Result is a concatenation of fixed injected field and injected expression
assertEquals("Yes, I am listening!", varSetByListener);
}
1 <process id="executionListenersProcess">
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 35/46
com.foo.MyTaskCreateListener?
8.5.14 Multi-instance (for each)
Task/Subprocessの繰り返し実⾏
まぁ、使うとしても JavaTask? だけだろうね
User Task とかで使うと複雑になりすぎる
Mail Task にも使えるけど... ⼤量の嫌がらせメール送るとか ...
bpmn
縦線は並列実⾏、横線はシーケンシャル実⾏
<multiInstanceLoopCharacteristics?> の属性、⼦要素
property note
isSequential true(並列実⾏可) / false(逐次実⾏)
loopCardinality 繰り返し数 (${}でプロセス変数の参照も可能)
completionCondition 終了条件 ${EL} でプロセス変数を評価する
タスク側では、⾃分が何番⽬の繰り返しなのかをプロセス変数で参照可能
property note
nrOfInstancfes?インスタンス数
nrOfActiveInstances?起動中のインスタンス数
nrOfCompletedInstances?終了したインスタンス数
loopCounter 現在実⾏中のインスタンス番号
サンプル実装
2
3
4
5
6
7
8
9
10
...
<userTask id="myTask" name="My Task" >
<extensionElements>
<activiti:taskListener class="com.foo.MyTaskCreateListener" event="create"/>
</extensionElements>
</userTask>
...
</process>
1
2
3
4
5
6
7
8
9
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;
public class MyTaskCreateListener implements TaskListener {
public void notify(DelegateTask delegateTask) {
// Custom logic goes here
}
}
1
2
3
4
5
6
7
8
9
10
11
<process id="MultiExam" name="Multi Exam" isExecutable="true">
<startEvent id="startevent1" name="Start"></startEvent>
<endEvent id="endevent1" name="End"></endEvent>
<serviceTask id="servicetask1" name="Service Task" activiti:class="com.snail.exam.MyJavaTask">
<multiInstanceLoopCharacteristics isSequential="false">
<loopCardinality>10</loopCardinality>
</multiInstanceLoopCharacteristics>
</serviceTask>
<sequenceFlow id="flow1" sourceRef="startevent1" targetRef="servicetask1"></sequenceFlow>
<sequenceFlow id="flow2" sourceRef="servicetask1" targetRef="endevent1"></sequenceFlow>
</process>
https://github.com/kagyuu/ActivitiExam/blob/master/src/main/java/com/snail/exam/MultiInstanceProcess.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.snail.exam;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.runtime.ProcessInstance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MultiInstanceProcess {
private static final Logger log = LoggerFactory.getLogger(MyProcess.class);
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 36/46
実⾏結果 (10回実⾏された)
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public static void main(String[] args) {
try {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
repositoryService.createDeployment()
.addClasspathResource("org/activiti/test/MultiInstance.bpmn")
.deploy();
log.info("Deployed");
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("MultiExa
log.info("Complete");
} catch (RuntimeException th) {
log.error("ERROR", th);
}
}
}
https://github.com/kagyuu/ActivitiExam/blob/master/src/main/java/com/snail/exam/MyJavaTask.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.snail.exam;
import java.util.Map;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyJavaTask implements JavaDelegate {
private static final Logger log = LoggerFactory.getLogger(MyJavaTask.class);
public void execute(DelegateExecution execution) throws Exception {
log.info("This is MyJavaTask");
for(Map.Entry entry : execution.getVariables().entrySet()) {
log.info("{}={}", entry.getKey(), entry.getValue());
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
16-05-18 23:49:36 [INFO ] Initializing process engine using configuration 'file:/Users/atsushi/E
16-05-18 23:49:36 [INFO ] initializing process engine for resource file:/Users/atsushi/EclipseWo
16-05-18 23:49:36 [INFO ] Loading XML bean definitions from resource loaded through InputStream
16-05-18 23:49:37 [INFO ] performing create on engine with resource org/activiti/db/create/activ
16-05-18 23:49:37 [INFO ] performing create on history with resource org/activiti/db/create/acti
16-05-18 23:49:37 [INFO ] performing create on identity with resource org/activiti/db/create/act
16-05-18 23:49:37 [INFO ] ProcessEngine default created
16-05-18 23:49:37 [INFO ] initialised process engine default
16-05-18 23:49:37 [INFO ] Processing resource org/activiti/test/MultiInstance.bpmn
16-05-18 23:49:37 [INFO ] Deployed
16-05-18 23:49:37 [INFO ] This is MyJavaTask
16-05-18 23:49:37 [INFO ] nrOfActiveInstances=10
16-05-18 23:49:37 [INFO ] loopCounter=0
16-05-18 23:49:37 [INFO ] nrOfInstances=10
16-05-18 23:49:37 [INFO ] nrOfCompletedInstances=0
16-05-18 23:49:38 [INFO ] This is MyJavaTask
16-05-18 23:49:38 [INFO ] nrOfActiveInstances=9
16-05-18 23:49:38 [INFO ] loopCounter=1
16-05-18 23:49:38 [INFO ] nrOfInstances=10
16-05-18 23:49:38 [INFO ] nrOfCompletedInstances=1
16-05-18 23:49:38 [INFO ] This is MyJavaTask
16-05-18 23:49:38 [INFO ] nrOfActiveInstances=8
16-05-18 23:49:38 [INFO ] loopCounter=2
16-05-18 23:49:38 [INFO ] nrOfInstances=10
16-05-18 23:49:38 [INFO ] nrOfCompletedInstances=2
16-05-18 23:49:38 [INFO ] This is MyJavaTask
16-05-18 23:49:38 [INFO ] nrOfActiveInstances=7
16-05-18 23:49:38 [INFO ] loopCounter=3
16-05-18 23:49:38 [INFO ] nrOfInstances=10
16-05-18 23:49:38 [INFO ] nrOfCompletedInstances=3
16-05-18 23:49:38 [INFO ] This is MyJavaTask
16-05-18 23:49:38 [INFO ] nrOfActiveInstances=6
16-05-18 23:49:38 [INFO ] loopCounter=4
16-05-18 23:49:38 [INFO ] nrOfInstances=10
16-05-18 23:49:38 [INFO ] nrOfCompletedInstances=4
16-05-18 23:49:38 [INFO ] This is MyJavaTask
16-05-18 23:49:38 [INFO ] nrOfActiveInstances=5
16-05-18 23:49:38 [INFO ] loopCounter=5
16-05-18 23:49:38 [INFO ] nrOfInstances=10
16-05-18 23:49:38 [INFO ] nrOfCompletedInstances=5
16-05-18 23:49:38 [INFO ] This is MyJavaTask
16-05-18 23:49:38 [INFO ] nrOfActiveInstances=4
16-05-18 23:49:38 [INFO ] loopCounter=6
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 37/46
8.6. Sub-Processes and Call Activities
ひとかたまりの Activiti Sub-Process としてまとめることができる
Activiti Explorer では、[Container] から SubProcess? EventSubProcess? を選ぶことができる
通常の sub process は、Task と同じように扱うことができる。sub process 全体にエラーイベントを貼り付け
ることもできる
event sub process は、Process 中のどこかで発⽣したイベントを契機に開始する
現時点では sub process にする意味はあまりない。
各業務共通の Sub-Processes を「共通bpmnファイル」にくくりだして、各業務bpmnファイル から参照する ...
というのなら意味がありそう
現時点ではそういう使い⽅に対応する予定なし https://forums.activiti.org/content/how-include-
other-bpmn-files
9. Form
Activiti Explorer は、bpmn 上の User Task Start Event からユーザ⼊⼒画⾯を作ってくれる
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
16-05-18 23:49:38 [INFO ] nrOfInstances=10
16-05-18 23:49:38 [INFO ] nrOfCompletedInstances=6
16-05-18 23:49:38 [INFO ] This is MyJavaTask
16-05-18 23:49:38 [INFO ] nrOfActiveInstances=3
16-05-18 23:49:38 [INFO ] loopCounter=7
16-05-18 23:49:38 [INFO ] nrOfInstances=10
16-05-18 23:49:38 [INFO ] nrOfCompletedInstances=7
16-05-18 23:49:38 [INFO ] This is MyJavaTask
16-05-18 23:49:38 [INFO ] nrOfActiveInstances=2
16-05-18 23:49:38 [INFO ] loopCounter=8
16-05-18 23:49:38 [INFO ] nrOfInstances=10
16-05-18 23:49:38 [INFO ] nrOfCompletedInstances=8
16-05-18 23:49:38 [INFO ] This is MyJavaTask
16-05-18 23:49:38 [INFO ] nrOfActiveInstances=1
16-05-18 23:49:38 [INFO ] loopCounter=9
16-05-18 23:49:38 [INFO ] nrOfInstances=10
16-05-18 23:49:38 [INFO ] nrOfCompletedInstances=9
16-05-18 23:49:38 [INFO ] Complete
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 38/46
User Task Start Event には、⼊⼒項⽬を指定できる
property note
id key項⽬。⼊⼒値は id をキーにしてプロセススコープの変数として保持される ((ACT_RU_VARIABLE
ーブルに格納される)
name 表⽰するラベル
type "string","long","enum","date","boolean"
value 初期値。プロセススコープの変数 (ACT_RU_VARIABLE テーブルに格納されているプロセス固有の変数)
EL式で参照可能
readable "true"/"false"
writable "true"/"false"
required "true"/"false"
type="enum" の時には次のように候補を定義する
GUI Activiti Explorer 前提なら From の話はここまでで OK
⾃前のワークフローGUIを作りたい時、bpmn 上の Form ⼊出⼒定義から動的に画⾯を作りたくなるだろう
FormService? にはそのための API がある
StartFormData FormService.getStartFormData(String processDefinitionId)
TaskFormdata FormService.getTaskFormData(String taskId)
StartFromData? を検索するキーは、processDefinitionId? (プロセス定義のID)TaskFormData? を検索する
キーは taskId (実⾏中のタスクのID)。考えて⾒れば当たり前。
StartFormData?.getFormProperties?()TaskFromData?.getFormProperties?()
List<FormProperty?> が返ってくる
<startEvent> <userTask> に定義できる⼊出⼒項⽬ <activiti:formProperty> の属性と同じね
⼊出⼒項⽬の型は FormType? 型で返される FormType?.getName() を使えば型名を⽂字列で取得できる
string (org.activiti.engine.impl.form.StringFormType?)
long (org.activiti.engine.impl.form.LongFormType?)
enum (org.activiti.engine.impl.form.EnumFormType?)
date (org.activiti.engine.impl.form.DateFormType?)
boolean (org.activiti.engine.impl.form.BooleanFormType?)
1
2
3
4
5
6
7
8
9
10
<startEvent>
<extensionElements>
<activiti:formProperty id="numberOfDays" name="Number of days"
value="${numberOfDays}" type="long" required="true"/>
<activiti:formProperty id="startDate" name="First day of holiday (dd-MM-yyy)"
value="${startDate}" datePattern="dd-MM-yyyy hh:mm" type="date" requi
<activiti:formProperty id="vacationMotivation" name="Motivation"
value="${vacationMotivation}" type="string" />
</extensionElements>
</userTask>
1
2
3
4
5
6
7
8
<userTask id="usertask1" name="User Task">
<extensionElements>
<activiti:formProperty id="sex" name="YOUR SEX" type="enum">
<activiti:value id="male" name="Male" />
<activiti:value id="female" name="Female" />
</activiti:formProperty>
</extensionElements>
</userTask>
1
2
3
4
5
6
7
8
9
10
public interface FormProperty {
FormService#submitStartFormData(String, java.util.Map)}
String getId();
String getName();
FormType getType();
String getValue();
boolean isReadable();
boolean isWritable();
boolean isRequired();
}
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 39/46
Vacation Request を読み込むサンプル
https://github.com/kagyuu/ActivitiExam/blob/master/src/main/java/com/snail/exam/FormProcess.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package com.snail.exam;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.form.FormProperty;
import org.activiti.engine.form.StartFormData;
import org.activiti.engine.form.TaskFormData;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FormProcess {
private static final Logger log = LoggerFactory.getLogger(FormProcess.class);
public static void main(String[] args) {
try {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// ----- 4.3.1. Deploying the process
log.info("--- #1. Deploying the process");
RepositoryService repositoryService = processEngine.getRepositoryService();
repositoryService.createDeployment()
.addClasspathResource("org/activiti/test/VacationRequest.bpmn20.xml")
.deploy();
// ----- 9. Forms (Read Start Form)
ProcessDefinition processDef = processEngine.getRepositoryService().createProcessDef
.processDefinitionKey("vacationRequest").singleResult();
log.info("Vaction Request PID={}", processDef.getId());
StartFormData startForm = processEngine.getFormService().getStartFormData(processDef
for (FormProperty prop : startForm.getFormProperties()) {
log.info("id={}, name={}, type={}, value={}, readable={}, required={}, writable=
, prop.getId(), prop.getName(), prop.getType(), prop.getValue()
, prop.isReadable(), prop.isRequired(), prop.isWritable());
}
// ----- 4.3.2. Starting a process instance
log.info("--- #3. Starting a process instance");
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("employeeName", "Kermit");
variables.put("numberOfDays", new Integer(4));
variables.put("startDate", DateUtils.parseDate("1999-12-31", "yyyy-MM-dd"));
variables.put("vacationMotivation", "I'm really tired!");
// the process to run
// id : <process id="vacationRequest">
// arguments : <activiti:formProperty>
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("vacation
// Fetch all tasks for the management group
TaskService taskService = processEngine.getTaskService();
List<Task> tasks = taskService.createTaskQuery().processDefinitionKeyLike("vacationR
for (Task task : tasks) {
TaskFormData taskForm = processEngine.getFormService().getTaskFormData(task.getI
for (FormProperty prop : taskForm.getFormProperties()) {
log.info("id={}, name={}, type={}, value={}, readable={}, required={}, writa
, prop.getId(), prop.getName(), prop.getType(), prop.getValue()
, prop.isReadable(), prop.isRequired(), prop.isWritable());
}
// Do task (reject application)
Map<String, Object> taskVariables = new HashMap<String, Object>();
taskVariables.put("vacationApproved", "false");
taskVariables.put("managerMotivation", "We have a tight deadline!");
taskService.complete(task.getId(), taskVariables);
}
} catch (Throwable th) {
log.error("ERROR", th);
}
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 40/46
実⾏結果
11.History
History Entities
HistoricProcessInstance?プロセスに関する情報
HistoricVariableInstance?プロセス変数に関する情報
HistoricActivityInstance?操作に関する情報
HistoricTaskInstance?タスク情報
HistoricDetail?Form Submit項⽬、プロセス変数の変更履歴
設定 activiti.cfg.xml
history
level note Prcess
Instance
Activity
Instance
From
Properties
Variable(
終状態)
Variable(
更履歴)
none 何も記録しない
activity ユーザ操作をすべて査証*1
✔ ✔
audit デフォルト設定。プロセス変
数の変更履歴を査証*2可能 ✔ ✔
full すべてを記録 ✔ ✔ ✔
API
HistoricProcessInstance?
String getBusinessKey?() The user provided unique reference to
this process instance.
String getDeleteReason?() Obtains the reason for the process
instance's deletion.
Long getDurationInMillis?() The difference between?getEndTime?()?
and?getStartTime?()?.
Date getEndTime?() The time the process was ended.
String getId() The process instance id (== as the id
for the run21:28:09process instance).
String getName() The name for the process instance.
String getProcessDefinitionId?() The process definition reference.
Map<String,Object> getProcessVariables?() Returns the process variables if
requested in the process instance
query. なんか何にも⼊っていない Map が返
される。プロセス変数は
88
89
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
16-05-19 01:22:08 [INFO ] Initializing process engine using configuration 'file:/Users/atsushi/E
16-05-19 01:22:08 [INFO ] initializing process engine for resource file:/Users/atsushi/EclipseWo
16-05-19 01:22:08 [INFO ] Loading XML bean definitions from resource loaded through InputStream
16-05-19 01:22:09 [INFO ] performing create on engine with resource org/activiti/db/create/activ
16-05-19 01:22:09 [INFO ] performing create on history with resource org/activiti/db/create/acti
16-05-19 01:22:09 [INFO ] performing create on identity with resource org/activiti/db/create/act
16-05-19 01:22:09 [INFO ] ProcessEngine default created
16-05-19 01:22:09 [INFO ] initialised process engine default
16-05-19 01:22:09 [INFO ] --- #1. Deploying the process
16-05-19 01:22:09 [INFO ] Processing resource org/activiti/test/VacationRequest.bpmn20.xml
16-05-19 01:22:10 [INFO ] Vaction Request PID=vacationRequest:1:4
16-05-19 01:22:10 [INFO ] id=numberOfDays, name=Number of days, type=org.activiti.engine.impl.fo
value=null, readable=true, required=true, writable=true,
16-05-19 01:22:10 [INFO ] id=startDate, name=First day of holiday (dd-MM-yyy), type=org.activiti
value=null, readable=true, required=true, writable=true,
16-05-19 01:22:10 [INFO ] id=vacationMotivation, name=Motivation, type=org.activiti.engine.impl.
readable=true, required=false, writable=true,
16-05-19 01:22:10 [INFO ] --- #3. Starting a process instance
16-05-19 01:22:10 [INFO ] id=vacationApproved, name=Do you approve this vacation, type=org.activ
value=null, readable=true, required=true, writable=true,
16-05-19 01:22:10 [INFO ] id=managerMotivation, name=Motivation, type=org.activiti.engine.impl.f
value=null, readable=true, required=false, writable=true,
1
2
3
4
5
<bean id="processEngineConfiguration"
class="org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration">
<property name="history" value="audit" />
...
</bean>
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 41/46
HistoricVariableInstance? からとればいい
だろう
String getStartActivitId?() The start activit.
Date getStartTime?() The time the process was started.
String getStartUserId?() The authenticated user that started
this process instance.
String getSuperProcessInstanceId?()
The process instance id of a potential
super process instance or null if no
super process instance exists.
String getTenantId?() The tenant identifier for the process
instance.
HistoricVariableInstance?
Date getCreateTime?() Returns the time when the variable was created.
String getId() The unique DB id
Date getLastUpdatedTime?() Returns the time when the value of the variable was
last updated.
String getProcessInstanceId?() The process instance reference.
String getTaskId?()
Object getValue()
String getVariableName?()
String getVariableTypeName?()
HistoricActivityInstance?
String getActivityId?() The unique identifier of the activity in the
process
String getActivityName?() The display name for the activity
String getActivityType?() The XML tag of the activity as in the process
file
String getAssignee() Assignee in case of user task activity
String getCalledProcessInstanceId?() The called process instance in case of call
activity
Long getDurationInMillis?() Difference between?getEndTime?()?and?
getStartTime?().
Date getEndTime?() Time when the activity instance ended
String getExecutionId?() Execution reference
String getId() The unique identifier of this historic activity
instance.
String getProcessDefinitionId?() Process definition reference
String getProcessInstanceId?() Process instance reference
Date getStartTime?() Time when the activity instance started
String getTaskId?() The corresponding task in case of task activity
String getTenantId?() Returns the tenant identifier for the historic
activity
HistoricDetail?
String getActivityInstanceId?() The activity reference in case this detail is related
to an activity instance.
String getExecutionId?() The identifier for the path of execution.
String getId() The unique DB id for this historic detail
String getProcessInstanceId?() The process instance reference.
String getTaskId?() The identifier for the task.
Date getTime() The time when this detail occurred
int getRevision()?
(Query の検索結果が HistoricVariableUpdate? extends
HistoricDetail? 型のとき)the revision of Process
variable
Object getValue()? (Query の検索結果が HistoricVariableUpdate? extends
HistoricDetail? 型のとき)Process variable
String getVariableName?()? (Query の検索結果が HistoricVariableUpdate? extends
HistoricDetail? 型のとき)
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 42/46
String getVariableTypeName?()? (Query の検索結果が HistoricVariableUpdate? extends
HistoricDetail? 型のとき)
String getPropertyId?()
(Query の検索結果が HistoricFormProperty? extends
HistoricDetail? 型のとき) the id or key of the Form
property
String getPropertyValue?() (Query の検索結果が HistoricFormProperty? extends
HistoricDetail? 型のとき)the Formsubmitted value
HistoricTaskInstance?
Date getClaimTime?() Time when the task was claimed.
String getDeleteReason?() The reason why this task was deleted {'completed',
'deleted', any other user defined string }.
Long getDurationInMillis?() Difference between getEndTime?() and getStartTime?() in
milliseconds.
Date getEndTime?() Time when the task was deleted or completed.
Date getStartTime?() Time when the task started.
Long getWorkTimeInMillis?() Difference between getEndTime?() and getClaimTime?() in
milliseconds.
サンプルプログラム (Vacation Request)
おなじみの Vacation Request
start で休暇申請
manager が承認する
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 43/46
サンプルコード
https://github.com/kagyuu/ActivitiExam/blob/master/src/main/java/com/snail/exam/HistoryProcess.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package com.snail.exam;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.activiti.engine.HistoryService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricDetail;
import org.activiti.engine.history.HistoricFormProperty;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricVariableInstance;
import org.activiti.engine.history.HistoricVariableUpdate;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HistoryProcess {
private static final Logger log = LoggerFactory.getLogger(HistoryProcess.class);
public static void main(String[] args) {
try {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// ----- 4.3.1. Deploying the process
log.info("--- #1. Deploying the process");
RepositoryService repositoryService = processEngine.getRepositoryService();
repositoryService.createDeployment().addClasspathResource("org/activiti/test/Va
.deploy();
log.info("Number of process definitions {}", repositoryService.createProcessDef
for (ProcessDefinition p : repositoryService.createProcessDefinitionQuery().lis
log.info("PROCESS DEF [id={},name={},key={}]", p.getId(), p.getName(), p.ge
}
// ----- 4.3.2. Starting a process instance
log.info("--- #2. Starting a process instance");
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("employeeName", "Kermit");
variables.put("numberOfDays", new Integer(4));
variables.put("startDate", DateUtils.parseDate("1999-12-31", "yyyy-MM-dd"));
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 44/46
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
variables.put("vacationMotivation", "I'm really tired!");
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("vac
log.info("Number of process instances: " + runtimeService.createProcessInstance
for (ProcessInstance p : runtimeService.createProcessInstanceQuery().list()) {
log.info("PROCESS INSTANCE [id={},pid={},pname={},pkey={}]", p.getId(), p.g
p.getProcessDefinitionName(), p.getProcessDefinitionKey());
}
log.info("--- #3. Completing tasks (Accept Request)");
// Fetch all tasks for the management group
TaskService taskService = processEngine.getTaskService();
List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("management
.processDefinitionKey("vacationRequest").list();
for (Task task : tasks) {
if (task.getTaskDefinitionKey().equals("handleRequest")) {
// Description is <documentation>.
log.info("TASK ACCEPT REQ [{}]", task.getDescription());
// Do task (reject application)
Map<String, Object> taskVariables = new HashMap<String, Object>();
taskVariables.put("vacationApproved", "true");
taskVariables.put("managerMotivation", "Okay, refresh yourself!");
taskService.complete(task.getId(), taskVariables);
}
}
// ----- 11. History
log.info("--- #4. History");
HistoryService historyService = processEngine.getHistoryService();
// 11.1.1. HistoricProcessInstanceQuery
List<HistoricProcessInstance> historicPorcessInstances = historyService.createH
.finished().orderByProcessInstanceDuration().desc().listPage(0, 10);
log.info("TERMINATED PROCESS = {}", historicPorcessInstances.size());
historicPorcessInstances.forEach(p -> {
log.info("PROCESS INSTANCE [id={},pid={},name={},variables_size={}]"
, p.getId()
, p.getProcessDefinitionId()
, p.getName()
, p.getProcessVariables().size());
p.getProcessVariables().forEach((k,v) -> {
log.info("{} = {}", k, v);
});
});
// 11.1.2. HistoricVariableInstanceQuery
List<HistoricVariableInstance> historicVariableInstances = historyService.creat
.orderByVariableName().asc().list();
log.info("VARIABLE SIZE = {}", historicVariableInstances.size());
historicVariableInstances.forEach(p -> {
log.info("VARIABLE [id={},pid={},task={},type={},name={},value={}]"
, p.getId()
, p.getProcessInstanceId()
, p.getTaskId()
, p.getVariableTypeName()
, p.getVariableName()
, p.getValue());
});
// 11.1.3. HistoricActivityInstanceQuery
List<HistoricActivityInstance> historicActivityInstances =historyService.create
.finished()
.orderByHistoricActivityInstanceEndTime().desc().list();
log.info("ACTIVITY SIZE = {}", historicActivityInstances.size());
historicActivityInstances.forEach(p -> {
log.info("ACTIVITY [id={},name={},task={},asignee={}]"
, p.getActivityId()
, p.getActivityName()
, p.getTaskId()
, p.getAssignee()
);
});
// 11.1.4. HistoricDetailQuery
List<HistoricDetail> historicDetails = historyService.createHistoricDetailQuery
log.info("DETAIL SIZE = {}", historicDetails.size());
historicDetails.forEach(p -> {
if (p instanceof HistoricFormProperty) {
log.info("FORM [pid={},taskid={},property_id={},value={}]"
, p.getProcessInstanceId()
, p.getTaskId()
, ((HistoricFormProperty)p).getPropertyId()
, ((HistoricFormProperty)p).getPropertyValue()
);
} else if (p instanceof HistoricVariableUpdate) {
log.info("VARIABLE [pid={},taskid={},revision={},name={},value={}]"
, p.getProcessInstanceId()
, p.getTaskId()
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 45/46
実⾏結果
HistoricProcessInstance? から Variable が取れないとか、謎仕様になっているけどまぁいいか
activiti.cfg.xml <property name="history" value="full" /> にすると DETAIL が表⽰される。
でも Form Property ではなくプロセス変数
プロセス変数周りは、細かい所⾊々と謎仕様が多いけどまぁいいか。⼀通りのことはできるし、必要になったら(プロ
セス監視画⾯をつくろうとか思い⽴ったら)もうちょっと細かい所検証する必要あり。まぁその時は REST API 使う
だろうけど
13. Activiti Explorer 14. Modeler
Java Activiti Explorer
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
, ((HistoricVariableUpdate)p).getRevision()
, ((HistoricVariableUpdate)p).getVariableName()
, ((HistoricVariableUpdate)p).getValue()
);
}
});
// 11.1.5. HistoricTaskInstanceQuery
List<HistoricTaskInstance> historicTaskInstances = historyService.createHistori
.finished()
.orderByHistoricTaskInstanceDuration().desc()
.listPage(0, 10);
log.info("TASK SIZE = {}", historicTaskInstances.size());
historicTaskInstances.forEach(p -> {
log.info("TASK [id={},name={},time={},asignee={}]"
, p.getId()
, p.getName()
, p.getCreateTime()
, p.getAssignee()
);
});
} catch (Throwable th) {
log.error("ERROR", th);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
16-05-23 21:34:18 [INFO ] Initializing process engine using configuration 'file:/Users/atsus
16-05-23 21:34:18 [INFO ] initializing process engine for resource file:/Users/atsushi/Eclip
16-05-23 21:34:18 [INFO ] Loading XML bean definitions from resource loaded through InputStr
16-05-23 21:34:19 [INFO ] performing create on engine with resource org/activiti/db/create/a
16-05-23 21:34:19 [INFO ] performing create on history with resource org/activiti/db/create/
16-05-23 21:34:19 [INFO ] performing create on identity with resource org/activiti/db/create
16-05-23 21:34:19 [INFO ] ProcessEngine default created
16-05-23 21:34:19 [INFO ] initialised process engine default
16-05-23 21:34:19 [INFO ] --- #1. Deploying the process
16-05-23 21:34:19 [INFO ] Processing resource org/activiti/test/VacationRequest.bpmn20.xml
16-05-23 21:34:21 [INFO ] Number of process definitions 1
16-05-23 21:34:21 [INFO ] PROCESS DEF [id=vacationRequest:1:4,name=Vacation request,key=vaca
16-05-23 21:34:21 [INFO ] --- #2. Starting a process instance
16-05-23 21:34:21 [INFO ] Number of process instances: 1
16-05-23 21:34:21 [INFO ] PROCESS INSTANCE [id=5,pid=vacationRequest:1:4,pname=Vacation requ
16-05-23 21:34:21 [INFO ] --- #3. Completing tasks (Accept Request)
16-05-23 21:34:21 [INFO ] TASK ACCEPT REQ [Kermit would like to take 4 day(s) of vacation (M
16-05-23 21:34:21 [INFO ] --- #4. History
16-05-23 21:34:21 [INFO ] TERMINATED PROCESS = 1
16-05-23 21:34:21 [INFO ] PROCESS INSTANCE [id=5,pid=vacationRequest:1:4,name=null,variables
16-05-23 21:34:21 [INFO ] VARIABLE SIZE = 6
16-05-23 21:34:21 [INFO ] VARIABLE [id=6,pid=5,task=null,type=string,name=employeeName,value
16-05-23 21:34:21 [INFO ] VARIABLE [id=15,pid=5,task=null,type=string,name=managerMotivation
16-05-23 21:34:21 [INFO ] VARIABLE [id=9,pid=5,task=null,type=integer,name=numberOfDays,valu
16-05-23 21:34:21 [INFO ] VARIABLE [id=10,pid=5,task=null,type=date,name=startDate,value=Fri
16-05-23 21:34:21 [INFO ] VARIABLE [id=14,pid=5,task=null,type=string,name=vacationApproved,
16-05-23 21:34:21 [INFO ] VARIABLE [id=8,pid=5,task=null,type=string,name=vacationMotivation
16-05-23 21:34:21 [INFO ] ACTIVITY SIZE = 5
16-05-23 21:34:21 [INFO ] ACTIVITY [id=theEnd1,name=null,task=null,asignee=null]
16-05-23 21:34:21 [INFO ] ACTIVITY [id=sendApprovalMail,name=Send confirmation e-mail,task=n
16-05-23 21:34:21 [INFO ] ACTIVITY [id=requestApprovedDecision,name=Request approved?,task=n
16-05-23 21:34:21 [INFO ] ACTIVITY [id=handleRequest,name=Handle vacation request,task=12,as
16-05-23 21:34:21 [INFO ] ACTIVITY [id=request,name=null,task=null,asignee=null]
16-05-23 21:34:21 [INFO ] DETAIL SIZE = 0
16-05-23 21:34:21 [INFO ] TASK SIZE = 1
16-05-23 21:34:21 [INFO ] TASK [id=12,name=Handle vacation request,time=Mon May 23 21:34:21
1
2
3
4
5
6
7
8
16-05-23 22:06:05 [INFO ] DETAIL SIZE = 7
16-05-23 22:06:05 [INFO ] VARIABLE [pid=5,taskid=null,revision=0,name=vacationMotivation,valu
16-05-23 22:06:05 [INFO ] VARIABLE [pid=5,taskid=null,revision=0,name=numberOfDays,value=4]
16-05-23 22:06:05 [INFO ] VARIABLE [pid=5,taskid=null,revision=0,name=startDate,value=Fri Dec
16-05-23 22:06:05 [INFO ] VARIABLE [pid=5,taskid=null,revision=0,name=vacationApproved,value=
16-05-23 22:06:05 [INFO ] VARIABLE [pid=5,taskid=null,revision=0,name=managerMotivation,value
16-05-23 22:06:05 [INFO ] VARIABLE [pid=5,taskid=null,revision=0,name=employeeName,value=null
16-05-23 22:06:05 [INFO ] VARIABLE [pid=5,taskid=null,revision=0,name=employeeName,value=Kerm
2018/7/4 Java Activiti User Guide Digest - @//メモ
https://hondou.homedns.org/pukiwiki/index.php?Java%20Activiti%20User%20Guide%20Digest 46/46
15. REST API
Java Activiti REST API
Java#Activiti
*1 audit
*2 audit
Last-modified: 2018-01-30 () 01:18:32 (154d)
Site admin: kagyuu
PukiWiki 1.4.6 Copyright © 2001-2005 PukiWiki Developers Team. License is GPL.
Based on "PukiWiki" 1.3 by yu-ji. Powered by PHP 5.3.3. HTML convert time: 3.017 sec.
ISBN10
ISBN13
4061426060
9784061426061

Navigation menu