diff --git a/.gitignore b/.gitignore index 902f43c8b7e..5dfb8e5bded 100644 --- a/.gitignore +++ b/.gitignore @@ -9,15 +9,10 @@ target .DS_Store .vscode *.bpmn/ -/userguide/src/en/index.html -userguide/src/en/output/ migration.html /modules/**/bin modules/flowable-app-rest/.extract modules/flowable-app-rest/src/main/resources/static/docs/specfile -userguide-dmn/src/en/output -userguide-form/src/en/output -userguide-cmmn/src/en/output docker/all-in-one/assets k8s/flowable/charts requirements.lock diff --git a/docs/docusaurus/docs/bpmn/ch03-Configuration.md b/docs/docusaurus/docs/bpmn/ch03-Configuration.md index 5102fab842e..cd7965bb664 100644 --- a/docs/docusaurus/docs/bpmn/ch03-Configuration.md +++ b/docs/docusaurus/docs/bpmn/ch03-Configuration.md @@ -374,13 +374,6 @@ Customizing the configuration of history storage is optional. This allows you to -## Async history configuration - -\[Experimental\] Since Flowable 6.1.0 the async history feature has been added. When async history is enabled, the historic data will be persisted by a history job executor, instead of synchronous persistence as part of the runtime execution persistence. -See [async history configuration](bpmn/ch10-History.md#async-history-configuration) for more details. - - - ## Exposing configuration beans in expressions and scripts By default, all beans that you specify in the flowable.cfg.xml configuration or in your own Spring configuration file are available to expressions and scripts. If you want to limit the visibility of beans in your configuration file, you can configure a property called beans in your process engine configuration. The beans property in ProcessEngineConfiguration is a map. When you specify that property, only beans specified in that map will be visible to expressions and scripts. The exposed beans will be exposed with the names as you specify in the map. diff --git a/docs/docusaurus/docs/bpmn/ch05a-Spring-Boot.md b/docs/docusaurus/docs/bpmn/ch05a-Spring-Boot.md index 87ae237a59d..c1bed727ab5 100644 --- a/docs/docusaurus/docs/bpmn/ch05a-Spring-Boot.md +++ b/docs/docusaurus/docs/bpmn/ch05a-Spring-Boot.md @@ -540,7 +540,7 @@ Here is a list of configuration properties that the Flowable Spring Boot support # Process https://github.com/flowable/flowable-engine/tree/main/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/process/FlowableProcessProperties.java flowable.process.definition-cache-limit=-1 # The maximum amount of process definitions available in the process definition cache. Per default it is -1 (all process definitions). - flowable.process.enable-safe-xml=true # Enables extra checks on the BPMN xml that is parsed. See https://www.flowable.org/docs/userguide/index.html#advanced.safe.bpmn.xml. Unfortunately, this feature is not available on some platforms (JDK 6, JBoss), hence you need to disable if your platform does not allow the use of StaxSource during XML parsing. + flowable.process.enable-safe-xml=true # Enables extra checks on the BPMN xml that is parsed. Unfortunately, this feature is not available on some platforms, hence you need to disable if your platform does not allow the use of StaxSource during XML parsing. flowable.process.servlet.load-on-startup=-1 # Load on startup of the Process dispatcher servlet. flowable.process.servlet.name=Flowable BPMN Rest API # The name of the Process servlet. flowable.process.servlet.path=/process-api # The context path for the Process rest servlet. @@ -558,7 +558,7 @@ Here is a list of configuration properties that the Flowable Spring Boot support # CMMN https://github.com/flowable/flowable-engine/tree/main/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/cmmn/FlowableCmmnProperties.java flowable.cmmn.deploy-resources=true # Whether to perform deployment of resources, default is 'true'. flowable.cmmn.deployment-name=SpringBootAutoDeployment # The name of the deployment for the CMMN resources. - flowable.cmmn.enable-safe-xml=true # Enables extra checks on the DMN xml that is parsed. See https://www.flowable.org/docs/userguide/index.html#advanced.safe.bpmn.xml. Unfortunately, this feature is not available on some platforms (JDK 6, JBoss), hence you need to disable if your platform does not allow the use of StaxSource during XML parsing. + flowable.cmmn.enable-safe-xml=true # Enables extra checks on the DMN xml that is parsed. Unfortunately, this feature is not available on some platforms, hence you need to disable if your platform does not allow the use of StaxSource during XML parsing. flowable.cmmn.enabled=true # Whether the CMMN engine needs to be started. flowable.cmmn.resource-location=classpath*:/cases/ # The location where the CMMN resources are located. flowable.cmmn.resource-suffixes=**.cmmn,**.cmmn11,**.cmmn.xml,**.cmmn11.xml # The suffixes for the resources that need to be scanned. @@ -578,7 +578,7 @@ Here is a list of configuration properties that the Flowable Spring Boot support # DMN https://github.com/flowable/flowable-engine/tree/main/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/dmn/FlowableDmnProperties.java flowable.dmn.deploy-resources=true # Whether to perform deployment of resources, default is 'true'. flowable.dmn.deployment-name=SpringBootAutoDeployment # The name of the deployment for the dmn resources. - flowable.dmn.enable-safe-xml=true # Enables extra checks on the DMN xml that is parsed. See https://www.flowable.org/docs/userguide/index.html#advanced.safe.bpmn.xml. Unfortunately, this feature is not available on some platforms (JDK 6, JBoss), hence you need to disable if your platform does not allow the use of StaxSource during XML parsing. + flowable.dmn.enable-safe-xml=true # Enables extra checks on the DMN xml that is parsed. Unfortunately, this feature is not available on some platforms, hence you need to disable if your platform does not allow the use of StaxSource during XML parsing. flowable.dmn.enabled=true # Whether the dmn engine needs to be started. flowable.dmn.history-enabled=true # Whether the history for the DMN engine should be enabled. flowable.dmn.resource-location=classpath*:/dmn/ # The location where the dmn resources are located. diff --git a/docs/docusaurus/docs/bpmn/ch13-Applications.md b/docs/docusaurus/docs/bpmn/ch13-Applications.md index f9b0b3aedb1..9e4ae9c8fb7 100644 --- a/docs/docusaurus/docs/bpmn/ch13-Applications.md +++ b/docs/docusaurus/docs/bpmn/ch13-Applications.md @@ -13,7 +13,7 @@ See [The Executable Jar Format](https://docs.spring.io/spring-boot/docs/current/ As mentioned before, the application can be deployed on a Tomcat server, and to get started this is probably the easiest approach when additional configuration settings are used. For this installation guide we’ll describe the installation of the application in a Tomcat server. -1. Download a recent stable version of [Apache Tomcat](http://tomcat.apache.org). It has to be Jakarta Servlet 6 compliant +1. Download a recent stable version of [Apache Tomcat](http://tomcat.apache.org). It has to be Jakarta Servlet 6 compliant (Tomcat 10 or later) 2. Download the latest stable [Flowable 7 version](http://www.flowable.org/downloads.html). diff --git a/docs/docusaurus/docs/oss-introduction.md b/docs/docusaurus/docs/oss-introduction.md index 5ccb0b79ab0..fb727ab3f77 100644 --- a/docs/docusaurus/docs/oss-introduction.md +++ b/docs/docusaurus/docs/oss-introduction.md @@ -21,7 +21,7 @@ The distribution contains most of the sources as JAR files. The source code for ### JDK 17+ -Flowable runs on a JDK higher than or equal to version 8. Go to [Oracle Java SE downloads](http://www.oracle.com/technetwork/java/javase/downloads/index.html) and click on button "Download JDK". There are installation instructions on that page as well. To verify that your installation was successful, run java -version on the command line. That should print the installed version of your JDK. +Flowable runs on a JDK higher than or equal to version 17. Go to [Oracle Java SE downloads](http://www.oracle.com/technetwork/java/javase/downloads/index.html) and click on button "Download JDK". There are installation instructions on that page as well. To verify that your installation was successful, run java -version on the command line. That should print the installed version of your JDK. ### Modeling diff --git a/docs/userguide/.gitignore b/docs/userguide/.gitignore deleted file mode 100644 index eb6cfbcacb6..00000000000 --- a/docs/userguide/.gitignore +++ /dev/null @@ -1,25 +0,0 @@ -target -*.iml -*.ipr -*.iws -.idea -.classpath -.project -.settings -.DS_Store -.vscode -*.bpmn/ -src/en/base/output -src/en/bpmn/output -src/en/cmmn/output -src/en/dmn/output -src/en/form/output -src/en/single/output - - -src/zh_CN/base/output -src/zh_CN/bpmn/output -src/zh_CN/cmmn/output -src/zh_CN/dmn/output -src/zh_CN/form/output -src/zh_CN/single/output \ No newline at end of file diff --git a/docs/userguide/README.md b/docs/userguide/README.md deleted file mode 100644 index a6aebab661a..00000000000 --- a/docs/userguide/README.md +++ /dev/null @@ -1,72 +0,0 @@ -About -------- - -This project regroups all userguide sources - -Currently it contains : - -* [BPMN](/src/en/bpmn) : Business Process Model and Notation User Guide -* [CMMN](/src/en/cmmn) : Case Management Model and Notation User Guide -* [DMN](/src/en/dmn) : Decision Model and Notation User Guide -* [FORM](/src/en/form) : Form engine User Guide -* [SINGLE (Beta Version)](/src/en/single) : Unified version of all previous documentation - -Tooling -------- - -Install Asciidoctor: http://asciidoctor.org/ - -We're using the 'pygments' library for syntax highlighting. This needs to be installed on your system too: -```ruby -gem install pygments.rb -``` - - -Generating the docs --------------------- - -**Using build.xml** - -Simply select run the *build.docs.[bpmn|cmmn|dmn|form|single|all]* goal and it will generate both a html & pdf version. -All generated files will be available in the root project **target** folder. - - -**From scripts folder** - -Go to the [scripts Folder](/scripts) -* Call the generate-all.sh [bpmn|cmmn|dmn|form|single] to generate for a single project both html & pdf version. -```bash -# Genate BPMN documentation in html & pdf format -> ./generate-all.sh bpmn -``` -* Call the generate-html.sh [bpmn|cmmn|dmn|form|single] to generate html. -```bash -# Genate Form documentation in html format -> ./generate-html.sh form -``` -* Call the generate-pdf.sh [bpmn|cmmn|dmn|form|single] to generate pdf. -```bash -# Genate DMN documentation in pdf format -> ./generate-pdf.sh dmn -``` - -**From each project folder** - -Use **./generate-html.sh** for html only and likewise **./generate-pdf.sh** for pdf only. - - -Docs on the docs ----------------- - -The html is generated using the **'index-html.adoc'** file per project. The pdf generation uses the **'index-pdf.adoc'** file per project. Both reference a shared **'index-common.adoc'** file for the actual content, but define different parameters in the preamble. - -When building the html doc, following files get included automatically: - -* **base/flowable.css** : this is the stylesheet for the docs. The css will be included inline in the html docs. -* **base/docinfo.html** : this file gets included at the top of the html file. It contains the tocbot library and a little script to initialize the dynamic table of contents. - - -NB -------- -We still use Ant as building tool because Asciidoctor Maven Plugin does not support the current level of quality for the generated documentation. We "still" -have to use asciidoc command line. diff --git a/docs/userguide/build.xml b/docs/userguide/build.xml deleted file mode 100644 index 457b0ed1d90..00000000000 --- a/docs/userguide/build.xml +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/userguide/scripts/clean.sh b/docs/userguide/scripts/clean.sh deleted file mode 100755 index 824ea2fc1cb..00000000000 --- a/docs/userguide/scripts/clean.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -if [ -z "$1" ] -then - echo -e "Usage: \n${0##*/} all \n${0##*/} bpmn \n${0##*/} cmmn \n${0##*/} dmn \n${0##*/} form" - exit 1 -fi - -if [ $1 == all ] -then - rm -rf ../src/en/single/output - rm -rf ../src/en/bpmn/output - rm -rf ../src/en/cmmn/output - rm -rf ../src/en/dmn/output - rm -rf ../src/en/form/output -else - rm -rf ../src/en/$1/output -fi diff --git a/docs/userguide/scripts/generate-all.sh b/docs/userguide/scripts/generate-all.sh deleted file mode 100755 index 25564ccbb5a..00000000000 --- a/docs/userguide/scripts/generate-all.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -if [ -z "$1" ] -then - echo -e "Usage: \n${0##*/} bpmn \n${0##*/} cmmn \n${0##*/} dmn \n${0##*/} form \n${0##*/} single" - exit 1 -fi - -if [ $1 == bpmn ] || [ $1 == cmmn ] || [ $1 == dmn ] || [ $1 == form ] || [ $1 == single ] -then - ./clean.sh $1 - ./generate-html.sh $1 - ./generate-pdf.sh $1 -else - echo -e "Usage: \n${0##*/} bpmn \n${0##*/} cmmn \n${0##*/} dmn \n${0##*/} form" - exit 1 -fi - - diff --git a/docs/userguide/scripts/generate-html.sh b/docs/userguide/scripts/generate-html.sh deleted file mode 100755 index 0a096702bce..00000000000 --- a/docs/userguide/scripts/generate-html.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -if [ -z "$1" ] -then - echo -e "Usage: \n${0##*/} bpmn \n${0##*/} cmmn \n${0##*/} dmn \n${0##*/} form \n${0##*/} single" - exit 1 -fi - -if [ $1 == bpmn ] || [ $1 == cmmn ] || [ $1 == dmn ] || [ $1 == form ] || [ $1 == single ] -then - cd ../src/en/$1 - ./generate-html.sh -else - echo -e "Usage: \n${0##*/} bpmn \n${0##*/} cmmn \n${0##*/} dmn \n${0##*/} form" - exit 1 -fi - - diff --git a/docs/userguide/scripts/generate-pdf.sh b/docs/userguide/scripts/generate-pdf.sh deleted file mode 100755 index 5a92dc9ca5f..00000000000 --- a/docs/userguide/scripts/generate-pdf.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -if [ -z "$1" ] -then - echo -e "Usage: \n${0##*/} bpmn \n${0##*/} cmmn \n${0##*/} dmn \n${0##*/} form \n${0##*/} single" - exit 1 -fi - -if [ $1 == bpmn ] || [ $1 == cmmn ] || [ $1 == dmn ] || [ $1 == form ] || [ $1 == single ] -then - cd ../src/en/$1 - ./generate-pdf.sh -else - echo -e "Usage: \n${0##*/} bpmn \n${0##*/} cmmn \n${0##*/} dmn \n${0##*/} form" - exit 1 -fi - - diff --git a/docs/userguide/src/zh_CN/base/docinfo.html b/docs/userguide/src/zh_CN/base/docinfo.html deleted file mode 100755 index 7042ec64987..00000000000 --- a/docs/userguide/src/zh_CN/base/docinfo.html +++ /dev/null @@ -1,73 +0,0 @@ - - - diff --git a/docs/userguide/src/zh_CN/base/flowable.css b/docs/userguide/src/zh_CN/base/flowable.css deleted file mode 100755 index 6fc2afdc123..00000000000 --- a/docs/userguide/src/zh_CN/base/flowable.css +++ /dev/null @@ -1,247 +0,0 @@ - -/* normalize.css */ - -button,hr,input{overflow:visible}audio,canvas,progress,video{display:inline-block}progress,sub,sup{vertical-align:baseline}html{font-family:sans-serif;line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0} menu,article,aside,details,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{}button,select{text-transform:none}[type=submit], [type=reset],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:ButtonText dotted 1px}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}[hidden],template{display:none}/*# sourceMappingURL=normalize.min.css.map */ - -/* tocbot 2.1.4 */ - -.toc{overflow-y:auto}.toc>ul{overflow:hidden;position:relative}.toc-list{margin:0;padding-left:10px}a.toc-link{color:currentColor;height:100%}.is-collapsible{max-height:1000px;overflow:hidden;transition:all 300ms ease-in-out}.is-collapsed{max-height:0}.is-position-fixed{position:fixed !important;top:0}.is-active-link{font-weight:700}.toc-link::before{background-color:#f9f9fb;content:' ';display:inline-block;height:inherit;left:8px;margin-top:-1px;position:absolute;width:2px}.is-active-link::before{background-color:#54BC4B} - - -/* Activiti Specific */ - -body { - color: #494d55; - font-size: 16px; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -html, body { - height: 100%; - width: 100%; - background: #f9f9f9; - font-family: "Helvetica Neue",Helvetica,Roboto,Arial,sans-serif; - color: #484848 -} - -.page-wrapper { - min-height: 100%; - /* equal to footer height */ - margin-bottom: -50px; -} - -.page-wrapper:after { - content: ""; - display: block; - height: 50px; -} - -#header { - position:fixed; - top:0px; - z-index:100000; - width:100%; -} - -#header > h1 { - background: #a0cc47; - color: #f9f9f9; - border-bottom: 2px solid #042944; - padding: 20px 0 20px 20px; - font-size: 40px; - font-weight: 800; - line-height: 1.1; - margin: 0; -} - -#header > h1:before { - background:url('images/logo.png'); - background-size: 337px 54px; background-repeat: no-repeat; - width: 337px; - height: 54px; - display:inline-block; - content:''; - margin-right: 30px; -} - -#author { - margin-left: 25%; - font-size: 40px; -} - -#content { - margin: 129px 0 0 27%; - padding: 10px 40px 0 20px; - padding-right: 40px; - line-height: 1.7; - width: 65%; - overflow-x: auto; -} - -h2, h3, h4, h5, h6 { - color: #00345a; -} - -h2 { - font-size: 26px; - margin-top: 0; - margin-bottom: 20px; - font-weight: bold; - padding-bottom: 10px; - border-bottom: 1px solid #d7d7d7; -} - -h3 { - font-size: 18px; - margin-top: 0; - margin-bottom: 0; - font-weight: bold; - padding-bottom: 10px; - /*border-bottom: 1px solid #d7d7d7;*/ -} - -h4 { - font-size: 16px; - font-weight: bold; -} - -h5 { - font-size: 14px; - font-weight: bold; -} - -h6, h7 { - font-size: 14px; - font-weight: bold; - margin-top: 0; - margin-bottom: 0; -} - -.sect1, .sect2 { - margin-bottom: 20px; -} - -.clear -{ - clear: both; -} - -.note, .listingblock, .literalblock{ - padding-left: 8px; - padding-right: 8px; - margin-bottom: 14px; - background-color: #f7f7f9; - border: 1px solid #e1e1e8; - border-radius: 4px; - color: #808080; -} - -table.tableblock { - width: 100%; - max-width: 100%; - margin-bottom: 20px; - background-color: transparent; - border-spacing: 0; - border-collapse: collapse; - border: 1px solid #ddd; - table-layout: fixed; -} - -table.tableblock>caption+thead>tr:first-child>td, table.tableblock>caption+thead>tr:first-child>th, table.tableblock>colgroup+thead>tr:first-child>td, table.tableblock>colgroup+thead>tr:first-child>th, table.tableblock>thead:first-child>tr:first-child>td, table.tableblock>thead:first-child>tr:first-child>th { - border-top: 0; -} - -table.tableblock > thead > tr > th { - border-bottom-color: #8bd6d8; -} - -table.tableblock>thead>tr>th { - vertical-align: bottom; - border-bottom: 1px solid #ddd; -} - -table.tableblock>tbody>tr>td, table.tableblock>tbody>tr>th, table.tableblock>tfoot>tr>td, table.tableblock>tfoot>tr>th, table.tableblock>thead>tr>td, table.tableblock>thead>tr>th { - padding: 8px; - line-height: 1.42857143; - vertical-align: top; - border-top: 1px solid #ddd; -} - -th { - text-align: left; -} - -table.tableblock > tbody > tr:nth-of-type(odd) { - background-color: #f5f5f5; -} - -table.tableblock > tbody > tr:nth-of-type(odd) { - background-color: #f9f9f9; -} - -td > p { - margin:0; -} - -td.content { - white-space: normal; -} - -pre, td, th { - white-space: pre-wrap; - white-space: -moz-pre-wrap; - white-space: -pre-wrap; - white-space: -o-pre-wrap; - word-wrap: break-word; -} - -img { - max-width: 100%; -} - -a { - color: #007387; -} - -a:hover { - color: #004c59; -} - -#toc-parent { - width: 25%; - float: left; - height: 100%; - overflow-y: auto; - position: fixed; - padding: 10px; - border-right: 1px solid #ccc; -} - -#generated-toc { - width: 100%; - height: 100%; - font-size: 16px; -} - -.toc-link { - text-decoration: none; -} - -.toc-list { - margin: 0 20px 0 10px; -} - -.toc-list-item { - padding: 4px 0 4px 0; -} - - -div.sect5 p { - margin-top: 0; - margin-bottom: 0; -} - -div.sect5 code { - font-family: "Helvetica Neue",Helvetica,Roboto,Arial,sans-serif; -} \ No newline at end of file diff --git a/docs/userguide/src/zh_CN/base/header-Introduction.adoc b/docs/userguide/src/zh_CN/base/header-Introduction.adoc deleted file mode 100755 index 8fde0eb9304..00000000000 --- a/docs/userguide/src/zh_CN/base/header-Introduction.adoc +++ /dev/null @@ -1,75 +0,0 @@ -[[license]] -=== 翻译(说明) - -由[分享牛Flowable中国社区] 翻译,任何意见建议,欢迎联系QQ:3152981878。 -如果想一起成为开源代码贡献人员,欢迎大家加入qq交流群为社区贡献添砖加瓦。qq贡献群:1023773998 - - -=== 协议 - -Flowable在link:$$http://www.apache.org/licenses/LICENSE-2.0.html$$[Apache V2 协议]下发布。 - -[[download]] - -=== 下载 - -link:$$http://www.flowable.org/downloads.html$$[http://www.flowable.org/downloads.html] -[[sources]] - -=== 源码 - -Flowable的发布包里包含了大部分源码,以JAR文件方式提供。Flowable的源码也可以通过以下链接获得: - link:$$https://github.com/flowable/flowable-engine$$[https://github.com/flowable/flowable-engine] - - -[[required.software]] - - -=== 必要的软件 - -==== JDK 8+ - -运行Flowable需要JDK 8或以上版本。可以访问 link:$$http://www.oracle.com/technetwork/java/javase/downloads/index.html$$[Oracle Java SE downloads页面] 点击“Download JDK”按钮获取。该页面上也有安装指导。安装完成后,可以执行 +java -version+ 。能看到JDK的版本信息就说明安装成功了。 - -==== IDE - -可以自行选择用于Flowable开发的IDE。如果想要使用Flowable Designer,则需要Eclipse Mars或Neon。 -到 link:$$http://www.eclipse.org/downloads/$$[Eclipse下载页面]选择Eclipse版本并下载。解压下载的文件, -然后执行++eclipse++文件夹下的eclipse文件。手册后续有专门一章介绍如何<>。 - - -[[reporting.problems]] - -=== 反馈问题 - -我们希望开发者在报告或提问之前,先看看link:$$http://www.catb.org/~esr/faqs/smart-questions.html$$[提问的智慧]。 - -看完提问的智慧,你可以在link:$$http://forums.flowable.org$$[用户论坛]提问、评论以及提交改进建议,也可以在link:$$https://github.com/flowable/flowable-engine/issues$$[我们的Github问题跟踪系统]创建bug报告。 - - -[[experimental]] - -=== 实验性功能 - -标记有**[实验性]**的章节介绍的功能还不够稳定。 - -++.impl.++包下的类都是内部实现类,不保证稳定。但是,在用户手册中作为配置参数介绍的类则是被官方支持的,可以保证稳定。 - - -[[internal]] - -=== 内部实现类 - -在JAR文件中,所有++.impl.++包下的类(比如++org.flowable.engine.impl.db++)都是实现类,只应在内部使用。实现类中的所有类或接口都不保证稳定。 - -[[_versioning_strategy]] -=== 版本策略 - -使用三个整数的形式标记版本:**MAJOR.MINOR.MICRO**。其中 **MAJOR**版本代表核心引擎的演进。**MINOR**版本代表新功能与新API。**MICRO**版本代表bug修复与改进。 - -总的来说,Flowable希望在**MINOR**与**MICRO**版本中,对所有非内部实现类保持“源代码兼容性”,即应用可以正确构建,且不改变语义。Flowable也希望在**MINOR**与**MICRO**版本中,保持“二进制兼容性”,即用新版本的Flowable直接替换老版本的Jar文件,仍然可以正常工作。 - -如果在**MINOR**版本中修改了API,将保留原有版本,并使用__@Deprecated__注解。这种废弃的API将在两个**MINOR**版本之后移除。 - -[[translator_info]] - diff --git a/docs/userguide/src/zh_CN/base/header-rest.adoc b/docs/userguide/src/zh_CN/base/header-rest.adoc deleted file mode 100755 index 38a7dbbbec4..00000000000 --- a/docs/userguide/src/zh_CN/base/header-rest.adoc +++ /dev/null @@ -1,246 +0,0 @@ -[[_general_flowable_rest_principles]] -=== Flowable REST一般原则 - -[[_installation_and_authentication]] -==== 安装与认证 - -Flowable为Flowable引擎提供了REST API,可以通过在servlet容器(如Apache Tomcat)中部署flowable-rest.war文件来安装。另外,也可以通过在应用中引入servlet(包括对应的映射),并将所有flowable-rest的依赖加入classpath的方式使用。 - -默认情况下Flowable引擎会连接至一个H2内存数据库。可以通过__WEB-INF/META-INF/flowable-app__文件夹下的flowable-app.properties文件修改数据库设置。REST API使用JSON格式( http://www.json.org ),并基于Spring MVC( http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html )构建。 - -默认情况下访问任何REST资源都需要具有__rest-access-api__权限的合法用户。如果需要任何合法用户都可以访问REST API,可以将__flowable.rest.app.authentication-mode__设置为__any-user__(这也是之前版本Flowable的默认设置)。 - -通过如下参数设置可以访问REST API的默认用户: - ----- -flowable.rest.app.admin.user-id=rest-admin -flowable.rest.app.admin.password=test -flowable.rest.app.admin.first-name=Rest -flowable.rest.app.admin.last-name=Admin ----- - -当REST应用启动时,如果用户不存在或无法找到,则会创建该用户。这个用户会被赋予访问REST API所需的__access-rest-api__权限。**请不要忘记修改这个用户的密码**。如果未设置__flowable.rest.app.admin.user-id__,则不会创建用户或权限。也因为此,在初始化完成后删除这些参数,并不会删除之前已经配置的用户或权限。 - -使用基础HTTP访问认证,因此在请求时,需要在HTTP-header中添加 __Authorization: Basic ...==__ 。也可以在请求url中包含用户名与密码(如 __http://username:password@localhost:8080/xyz__)。 - -**建议使用基础认证时,同时使用HTTPS。** - -[[_configuration_2]] -==== 配置 - -Flowable REST web应用使用Spring Java Configuration来启动Flowable引擎,使用Spring security定义基础认证安全,并为为特定的变量处理定义了变量转换。 -有少量参数可以通过修改WEB-INF/classes文件夹下的engine.properties文件定义。 -如果需要高级配置选项,可以在flowable-custom-context.xml文件中覆盖默认的Spring bean,这个文件也在WEB-INF/classes文件夹下。 -该文件中已经以注释形式提供了示例配置。也可以在该文件中定义一个新的命名为restResponsefactory的Spring bean,覆盖默认的RestResponseFactory,并使用自定义实现类。 - -[[restUsageInTomcat]] -==== 在Tomcat中使用 - - -由于link:$$http://tomcat.apache.org/tomcat-8.0-doc/security-howto.html$$[Tomcat中的默认安全参数],**默认不能使用转义斜线符(++%2F++与++%5C++)(将返回400)。**这可能会影响部署资源与其数据URL,因为URL可能包含转义斜线符。 - -当发现400异常结果时,可以设置下列系统参数: - -__-Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true__ - -最佳实践是(在post/put JSON时),在下面介绍的HTTP请求中,永远将**Accept**与**Content-Type**HTTP头设置为**application/json**。 - -[[_methods_and_return_codes]] -==== 方法与返回码 - -.HTTP方法与对应操作 -[options="header"] -|=============== -|方法|操作 -|+GET+|获取单个资源,或获取一组资源。 -|+POST+|创建一个新资源。在查询结构太复杂,不能放入GET请求的查询URL中时,也用于执行资源查询。 -|+PUT+|更新一个已有资源的参数。也用于调用已有资源提供的操作。 -|+DELETE+|删除一个已有资源。 - -|=============== - - -.HTTP方法响应码 -[options="header"] -|=============== -|响应|描述 -|++200 - Ok++|操作成功,返回响应(++GET++与++PUT++请求)。 -|++201 - 已创建++|操作成功,已经创建了实体,并在响应体中返回(++POST++请求)。 -|++204 - 无内容++|操作成功,已经删除了实体,因此没有返回的响应体(++DELETE++请求)。 -|++401 - 未认证++|操作失败。操作要求设置认证头。如果请求中有认证头,则提供的鉴证并不合法,或者用户未被授权进行该操作。 -|++403 - 禁止++|操作被禁止,且不应重试。这不是鉴证或授权的问题,而是说明不允许该操作。例如:无论任何用户或流程/任务的状态,删除一个运行中流程的任务是且永远是不允许的。 -|++404 - 未找到++|操作失败。请求的资源未找到。 -|++405 - 不允许的方法++|操作失败。使用的方法不能用于该资源。例如,更新(PUT)部署资源将返回++405++响应码。 -|++409 - 冲突++|操作失败。该操作导致更新一个已被其他操作更新的资源,因此本更新不再有效。也可以表示正在为一个集合创建一个资源,但该标识符已存在。 -|++415 - 不支持的媒体类型++|操作失败。请求提包含了不支持的媒体类型。也会发生在请求体JSON中包含了未知的属性或值,但没有可用的格式/类型来处理的情况。 -|++500 - 服务器内部错误++|操作失败。执行操作时发生了未知异常。响应体中包含了错误的细节。 - -|=============== - - -HTTP响应的media-type总是++application/json++,除非请求的是二进制内容(例如部署资源数据)。这时将使用内容的media-type。 - -[[_error_response_body]] -==== 错误响应体 - -当发生错误时(可能是客户端或服务器端的错误,4XX及5XX状态码),响应体会包含一个描述了发生的错误的对象。任务未找到时的404状态的例子: - -[source,json,linenums] ----- -{ - "statusCode" : 404, - "errorMessage" : "Could not find a task with id '444'." -} ----- - -[[_request_parameters]] -==== 请求参数 - -[[_url_fragments]] -===== URL片段 - -作为url的一部分的参数(例如,++http://host/flowable-rest/service/repository/deployments/{deploymentId}++中的deploymentId参数),如果包含特殊字符,则需要进行合适的转义(参见link:$$https://en.wikipedia.org/wiki/Percent-encoding$$[URL编码或百分号编码])。大多数框架都内建了这个功能,但要记得考虑它。特别是对可能包含斜线符的段落(例如部署资源),就必须要做转义。 - -[[_rest_url_query_parameters]] -===== Rest URL查询参数 - -作为查询字符串添加在URL中的参数(例如++http://host/flowable-rest/service/deployments?name=Deployment++中的name参数)可以使用下列类型。在相应的REST-API文档中也会提到: - - -.URL查询参数类型 -[options="header"] -|=============== -|类型|格式 -|String|纯文本参数。可以包含任何URL允许的合法字符。对于++XXXLike++参数,字符串可能会包含通配符++%++(需要进行URL编码)。可以进行like搜索,例如,'Tas%'将匹配所有以'Tas'开头的值。 -|Integer|整形参数。只能包含数字型非小数值,在-2.147.483.648至2.147.483.647之间。 -|Long|长整形参数。只能包含数字型非小数值,在-9.223.372.036.854.775.808至9.223.372.036.854.775.807之间。 -|Boolean|boolean型参数。可以为++true++或++false++。任何其他值都会导致'++405 - 错误请求++'响应码。 -|Date|日期型参数。使用ISO-8601日期格式(参考link:$$http://en.wikipedia.org/wiki/ISO_8601$$[wikipedia中的ISO-8601]),使用时间与日期部分(例如++2013-04-03T23:45Z++)。 - -|=============== - - -[[restJsonBody]] - - -===== JSON body 参数 - -.JSON参数类型 -[options="header"] -|=============== -|类型|格式 -|String|纯文本参数。对于++XXXLike++参数,字符串可能会包含通配符++%++。可以进行like搜索。例如,'Tas%'将匹配所有以'Tas'开头的值。 -|Integer|整形参数,使用JSON数字。只能包含数字型非小数值,在-2.147.483.648至2.147.483.647之间。 -|Long|长整形参数,使用JSON数字。只能包含数字型非小数值,在-9.223.372.036.854.775.808至9.223.372.036.854.775.807之间。 -|Date|日期型参数,使用JSON文本。使用ISO-8601日期格式(参考link:$$http://en.wikipedia.org/wiki/ISO_8601$$[wikipedia中的ISO-8601]),使用时间与日期组分(例如++2013-04-03T23:45Z++)。 - -|=============== - - -[[restPagingAndSort]] - - -===== 分页与排序 - - -分页与排序参数可以作为查询字符串加入URL中(例如++http://host/flowable-rest/service/deployments?sort=name++中的name参数)。 - -.JSON查询变量参数 -[options="header"] -|=============== -|参数|默认值|描述 -|sort|各查询实现不同|排序键的名字,在各查询实现中默认值与可用值都不同。 -|order|asc|排序顺序,可以是'asc'(顺序)或'desc'(逆序)。 -|start|0|对结果分页的参数。默认结果从0开始。 -|size|10|对结果分页的参数。默认大小为10. - -|=============== - -[[restQueryVariable]] - - -===== JSON查询变量格式 - -[source,json,linenums] ----- - -{ - "name" : "variableName", - "value" : "variableValue", - "operation" : "equals", - "type" : "string" -} ----- - - -.JSON查询变量参数 -[options="header"] -|=============== -|参数|必填|描述 -|name|否|包含在查询中的变量名。在有些使用'++equals++'的查询中可以为空,查询**任意变量名**为给定值的资源。 -|value|是|包含在查询中的变量值,需要使用给定类型的正确格式。 -|operator|是|查询使用的操作,可以为下列值:++equals, notEquals, equalsIgnoreCase, notEqualsIgnoreCase, lessThan, greaterThan, lessThanOrEquals, greaterThanOrEquals++与++like++。 -|type|否|所用变量的类型。当省略时,会从++value++参数推理类型。任何JSON文本值都使用是++string++类型,JSON boolean值使用++boolean++类型,JSON数字使用++long++或++integer++,取决于数字的大小。建议在有疑惑时明确指定类型。其他支持的类型列在下面。 - -|=============== - - -.默认查询JSON类型 -[options="header"] -|=============== -|类型名|描述 -|string|值处理转换为++java.lang.String++。 -|short|值处理转换为++java.lang.Integer++。 -|integer|值处理转换为++java.lang.Integer++。 -|long|值处理转换为++java.lang.Long++。 -|double|值处理转换为++java.lang.Double++。 -|boolean|值处理转换为++java.lang.Boolean++。 -|date|值处理转换为++java.util.Date++。JSON字符串将使用ISO-8601日期格式转换。 - -|=============== - - -[[restVariables]] - -===== 变量表示 - -读取与写入变量(执行选择)时,REST API都使用通用原则与JSON格式。变量的JSON表示为: - - -[source,json,linenums] ----- -{ - "name" : "variableName", - "value" : "variableValue", - "valueUrl" : "http://...", - "type" : "string" -} ----- - -.变量的JSON属性 -[options="header"] -|=============== -|参数|必填|描述 -|name|是|变量名。 -|value|否|变量的值。当写入变量且省略了++value++时,会使用++null++作为value。 -|valueUrl|否|当读取++binary++或++serializable++类型的变量时,这个属性将指向可用于获取原始二进制数据的URL。 -|type|否|变量的类型。查看下面的表格了解类型的更多信息。当写入变量且省略了这个值时,将使用请求的原始JSON属性类型推断,限制在++string++, ++double++, ++integer++与++boolean++中。建议总是包含类型,以确保不会错误推断类型。 - -|=============== - -.变量类型 -[options="header"] -|=============== -|类型名|描述 -|string|值按照++java.lang.String++处理。写入变量时使用原始JSON文本。 -|integer|值按照++java.lang.Integer++处理。按约定写入变量时使用JSON数字,失败则退回JSON文本。 -|short|值按照++java.lang.Short++处理。按约定写入变量时使用JSON数字,失败则退回JSON文本。 -|long|值按照++java.lang.Long++处理。按约定写入变量时使用JSON数字,失败则退回JSON文本。 -|double|值按照++java.lang.Double++处理。按约定写入变量时使用JSON数字,失败则退回JSON文本。 -|boolean|值按照++java.lang.Boolean++处理。按约定写入变量时使用JSON boolean。 -|date|值按照++java.util.Date++处理。写入变量时将转换为ISO-8601日期格式。 - -|=============== - - -可以使用自定义JSON表示,以支持额外的变量类型(既可以是简单值,也可以是复杂/嵌套的JSON对象)。通过扩展++org.flowable.rest.service.api.RestResponseFactory++的++initializeVariableConverters()++方法,可以添加额外的++org.flowable.rest.service.api.engine.variable.RestVariableConverter++类,用于将POJO转换为适合通过REST传输的格式,以及将REST值转换为POJO。实际转换JSON使用Jackson。 diff --git a/docs/userguide/src/zh_CN/base/images/li-chevron.png b/docs/userguide/src/zh_CN/base/images/li-chevron.png deleted file mode 100755 index 4e966354cba..00000000000 Binary files a/docs/userguide/src/zh_CN/base/images/li-chevron.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/base/images/logo.png b/docs/userguide/src/zh_CN/base/images/logo.png deleted file mode 100755 index ef9996664e7..00000000000 Binary files a/docs/userguide/src/zh_CN/base/images/logo.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/base/images/logo@2x.png b/docs/userguide/src/zh_CN/base/images/logo@2x.png deleted file mode 100755 index d3b55d38e59..00000000000 Binary files a/docs/userguide/src/zh_CN/base/images/logo@2x.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/ch02-GettingStarted.adoc b/docs/userguide/src/zh_CN/bpmn/ch02-GettingStarted.adoc deleted file mode 100755 index 21aecc39667..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch02-GettingStarted.adoc +++ /dev/null @@ -1,583 +0,0 @@ -[[_getting_started]] -== 开始 - -[[_what_is_flowable]] -=== Flowable是什么? - -Flowable是一个使用Java编写的轻量级业务流程引擎。Flowable流程引擎可用于部署BPMN 2.0流程定义(用于定义流程的行业XML标准), -创建这些流程定义的流程实例,进行查询,访问运行中或历史的流程实例与相关数据,等等。这个章节将用一个可以在你自己的开发环境中使用的例子,逐步介绍各种概念与API。 - -Flowable可以十分灵活地加入你的应用/服务/构架。可以将JAR形式发布的Flowable库加入应用或服务,来__嵌入__引擎。 -以JAR形式发布使Flowable可以轻易加入任何Java环境:Java SE;Tomcat、Jetty或Spring之类的servlet容器;JBoss或WebSphere之类的Java EE服务器,等等。 -另外,也可以使用Flowable REST API进行HTTP调用。也有许多Flowable应用(Flowable Modeler, Flowable Admin, Flowable IDM 与 Flowable Task),提供了直接可用的UI示例,可以使用流程与任务。 - -所有使用Flowable方法的共同点是核心引擎。核心引擎是一组服务的集合,并提供管理与执行业务流程的API。 -下面的教程从设置与使用核心引擎的介绍开始。后续章节都建立在之前章节中获取的知识之上。 - -* <>展示了以最简单的方式运行Flowable的方法:只使用Java SE的标准Java main方法。这里也会介绍许多核心概念与API。 -* <>章节展示了如何通过REST运行及使用相同的API。 -* <>章节将介绍直接可用的Flowable UI示例的基本方法。 - -[[_flowable_and_activiti]] -=== Flowable与Activiti - -Flowable是Activiti(Alfresco持有的注册商标)的fork。在下面的章节中,你会注意到包名,配置文件等等,都使用__flowable__。 - -[[getting.started.command.line]] -=== 构建命令行程序 - -[[_creating_a_process_engine]] -==== 创建流程引擎 - -在这个初步教程中,将构建一个简单的例子,以展示如何创建一个Flowable流程引擎,介绍一些核心概念,并展示如何使用API。 -截图时使用的是Eclipse,但实际上可以使用任何IDE。我们使用Maven获取Flowable依赖及管理构建,但是类似的任何其它方法也都可以使用(Gradle,Ivy,等等)。 - -我们将构建的例子是一个简单的__请假(holiday request)__流程: - -* __雇员(employee)__申请几天的假期 -* __经理(manager)__批准或驳回申请 -* 我们会模拟将申请注册到某个外部系统,并给雇员发送结果邮件 - -首先,通过__File -> New -> Other -> Maven Project__创建一个新的Maven项目 - -image::images/getting.started.new.maven.png[align="center"] - -在下一界面中,选中'__create a simple project (skip archetype selection)__' - -image::images/getting.started.new.maven2.png[align="center"] - -填入__'Group Id'__与__'Artifact id'__: - -image::images/getting.started.new.maven3.png[align="center"] - -这样就建立了空的Maven项目,然后添加两个依赖: - -* Flowable流程引擎。使我们可以创建一个ProcessEngine流程引擎对象,并访问Flowable API。 -* 一个内存数据库。本例中为H2,因为Flowable引擎在运行流程实例时,需要使用数据库来存储执行与历史数据。 -请注意H2依赖包含了数据库__及__驱动。如果使用其他数据库(例如PostgreSQL,MySQL等),需要添加对应的数据库驱动依赖。 - -在__pom.xml__文件中添加下列行: - -[source,xml,linenums] ----- - - - org.flowable - flowable-engine - 6.5.0.event-SNAPSHOT - - - com.h2database - h2 - 1.3.176 - - ----- - -如果由于某些原因,依赖JAR无法自动获取,可以右键点击项目,并选择'__Maven -> Update Project__'以强制手动刷新(一般不会需要这么操作)。 -在这个项目中的'__Maven Dependencies__'下,可以看到__flowable-engine__与许多其他(传递的)依赖。 - -创建一个新的Java类,并添加标准的Java main方法: - -[source,java,linenums] ----- -package org.flowable; - -public class HolidayRequest { - - public static void main(String[] args) { - - } - -} ----- - -首先要做的是初始化**ProcessEngine**流程引擎实例。这是一个线程安全的对象,因此通常只需要在一个应用中初始化一次。 -__ProcessEngine__由**ProcessEngineConfiguration**实例创建。该实例可以配置与调整流程引擎的设置。 -通常使用一个配置XML文件创建__ProcessEngineConfiguration__,但是(像在这里做的一样)也可以编程方式创建它。 -__ProcessEngineConfiguration__所需的最小配置,是数据库JDBC连接: - -[source,java,linenums] ----- -package org.flowable; - -import org.flowable.engine.ProcessEngine; -import org.flowable.engine.ProcessEngineConfiguration; -import org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration; - -public class HolidayRequest { - - public static void main(String[] args) { - ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration() - .setJdbcUrl("jdbc:h2:mem:flowable;DB_CLOSE_DELAY=-1") - .setJdbcUsername("sa") - .setJdbcPassword("") - .setJdbcDriver("org.h2.Driver") - .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE); - - ProcessEngine processEngine = cfg.buildProcessEngine(); - } - -} ----- - -在上面的代码中,第10行创建了一个__独立(standalone)__配置对象。这里的__'独立'__指的是引擎是完全独立创建及使用的(而不是在Spring环境中使用,这时需要使用__SpringProcessEngineConfiguration__类代替)。第11至14行中,传递了一个内存H2数据库实例的JDBC连接参数。 -重要:请注意这样的数据库在JVM重启后会消失。如果需要永久保存数据,需要切换为持久化数据库,并相应切换连接参数。 -第15行中,设置了__true__,确保在JDBC参数连接的数据库中,数据库表结构不存在时,会创建相应的表结构。 -另外,Flowable也提供了一组SQL文件,可用于手动创建所有表的数据库表结构。 - -然后使用这个配置创建**ProcessEngine**对象(第17行)。 - -这样就可以运行了。在Eclipse中最简单的方法是右键点击类文件,选择__Run As -> Java Application__ : - -image::images/getting.started.run.main.png[align="center"] - -应用运行没有问题,但也没有在控制台提供有用的信息,只有一条消息提示日志没有正确配置: - -image::images/getting.started.console.logging.png[align="center"] - -Flowable使用link:$$http://www.slf4j.org/$$[SLF4J]作为内部日志框架。在这个例子中,我们使用log4j作为SLF4J的实现。因此在pom.xml文件中添加下列依赖: - -[source,xml,linenums] ----- - - org.slf4j - slf4j-api - 1.7.21 - - - org.slf4j - slf4j-log4j12 - 1.7.21 - ----- - -Log4j需要一个配置文件。在__src/main/resources__文件夹下添加__log4j.properties__文件,并写入下列内容: - ----- -log4j.rootLogger=DEBUG, CA - -log4j.appender.CA=org.apache.log4j.ConsoleAppender -log4j.appender.CA.layout=org.apache.log4j.PatternLayout -log4j.appender.CA.layout.ConversionPattern= %d{hh:mm:ss,SSS} [%t] %-5p %c %x - %m%n ----- - -重新运行应用。应该可以看到关于引擎启动与创建数据库表结构的提示日志: - -image::images/getting.started.console.logging2.png[align="center"] - -这样就得到了一个启动可用的流程引擎。接下来为它提供一个流程! - -[[_deploying_a_process_definition]] -==== 部署流程定义 - -我们要构建的流程是一个非常简单的请假流程。Flowable引擎需要流程定义为BPMN 2.0格式,这是一个业界广泛接受的XML标准。 -在Flowable术语中,我们将其称为一个**流程定义(process definition)**。一个__流程定义__可以启动多个**流程实例(process instance)**。__流程定义__可以看做是重复执行流程的蓝图。 -在这个例子中,__流程定义__定义了请假的各个步骤,而一个__流程实例__对应某个雇员提出的一个请假申请。 - -BPMN 2.0存储为XML,并包含可视化的部分:使用标准方式定义了每个步骤类型(人工任务,自动服务调用,等等)如何呈现,以及如何互相连接。这样BPMN 2.0标准使技术人员与业务人员能用双方都能理解的方式交流业务流程。 - -我们要使用的流程定义为: - -image::images/getting.started.bpmn.process.png[align="center"] - -这个流程应该已经十分自我解释了。但为了明确起见,说明一下几个要点: - -* 我们假定启动流程需要提供一些信息,例如雇员名字、请假时长以及说明。当然,这些可以单独建模为流程中的第一步。 -但是如果将它们作为流程的“输入信息”,就能保证只有在实际请求时才会建立一个流程实例。否则(将提交作为流程的第一步),用户可能在提交之前改变主意并取消,但流程实例已经创建了。 -在某些场景中,就可能影响重要的指标(例如启动了多少申请,但还未完成),取决于业务目标。 -* 左侧的圆圈叫做**启动事件(start event)**。这是一个流程实例的起点。 -* 第一个矩形是一个**用户任务(user task)**。这是流程中人类用户操作的步骤。在这个例子中,经理需要批准或驳回申请。 -* 取决于经理的决定,**排他网关(exclusive gateway)** (带叉的菱形)会将流程实例路由至批准或驳回路径。 -* 如果批准,则需要将申请注册至某个外部系统,并跟着另一个用户任务,将经理的决定通知给申请人。当然也可以改为发送邮件。 -* 如果驳回,则为雇员发送一封邮件通知他。 - - -一般来说,这样的__流程定义__使用可视化建模工具建立,如Flowable Designer(Eclipse)或Flowable Web Modeler(Web应用)。 - -但在这里我们直接撰写XML,以熟悉BPMN 2.0及其概念。 - -与上面展示的流程图对应的BPMN 2.0 XML在下面显示。请注意这只包含了“流程部分”。如果使用图形化建模工具,实际的XML文件还将包含“可视化部分”,用于描述图形信息,如流程定义中各个元素的坐标(所有的图形化信息包含在XML的__BPMNDiagram__标签中,作为__definitions__标签的子元素)。 - -将下面的XML保存在__src/main/resources__文件夹下名为__holiday-request.bpmn20.xml__的文件中。 - -[source,xml,linenums] ----- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ----- - -第2至11行看起来挺吓人,但其实在大多数的流程定义中都是一样的。这是一种__样板文件__,需要与BPMN 2.0标准规范完全一致。 - -每一个步骤(在BPMN 2.0术语中称作**'活动(activity)'**)都有一个__id__属性,为其提供一个在XML文件中唯一的标识符。所有的__活动__都可以设置一个名字,以提高流程图的可读性。 - -__活动__之间通过**顺序流(sequence flow)**连接,在流程图中是一个有向箭头。在执行流程实例时,执行(execution)会从__启动事件__沿着__顺序流__流向下一个__活动__。 - -离开__排他网关(带有X的菱形)__的__顺序流__很特别:都以__表达式(expression)__的形式定义了__条件(condition)__ (见第25至32行)。当流程实例的执行到达这个__网关__时,会计算__条件__,并使用第一个计算为__true__的顺序流。这就是__排他__的含义:只选择一个。当然如果需要不同的路由策略,可以使用其他类型的网关。 - -这里用作条件的__表达式__为__${approved}__,这是__${approved == true}__的简写。变量'approved'被称作**流程变量(process variable)**。__流程变量__是持久化的数据,与流程实例存储在一起,并可以在流程实例的生命周期中使用。在这个例子里,我们需要在特定的地方(当经理用户任务提交时,或者以Flowable的术语来说,__完成(complete)__时)设置这个__流程变量__,因为这不是流程实例启动时就能获取的数据。 - -现在我们已经有了流程BPMN 2.0 XML文件,下来需要将它**'部署(deploy)'**到引擎中。__部署__一个流程定义意味着: - -* 流程引擎会将XML文件存储在数据库中,这样可以在需要的时候获取它。 -* 流程定义转换为内部的、可执行的对象模型,这样使用它就可以启动__流程实例__。 - -将流程定义__部署__至Flowable引擎,需要使用__RepositoryService__,其可以从__ProcessEngine__对象获取。使用__RepositoryService__,可以通过XML文件的路径创建一个新的__部署(Deployment)__,并调用__deploy()__方法实际执行: - -[source,java,linenums] ----- -RepositoryService repositoryService = processEngine.getRepositoryService(); -Deployment deployment = repositoryService.createDeployment() - .addClasspathResource("holiday-request.bpmn20.xml") - .deploy(); ----- - -我们现在可以通过API查询验证流程定义已经部署在引擎中(并学习一些API)。通过__RepositoryService__创建的__ProcessDefinitionQuery__对象实现。 - -[source,java,linenums] ----- -ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() - .deploymentId(deployment.getId()) - .singleResult(); -System.out.println("Found process definition : " + processDefinition.getName()); ----- - -[[_starting_a_process_instance]] -==== 启动流程实例 - -现在已经在流程引擎中__部署__了流程定义,因此可以使用这个__流程定义__作为“蓝图”启动__流程实例__。 - -要启动流程实例,需要提供一些初始化__流程变量__。一般来说,可以通过呈现给用户的表单,或者在流程由其他系统自动触发时通过REST API,来获取这些变量。在这个例子里,我们简化为使用java.util.Scanner类在命令行输入一些数据: - -[source,java,linenums] ----- -Scanner scanner= new Scanner(System.in); - -System.out.println("Who are you?"); -String employee = scanner.nextLine(); - -System.out.println("How many holidays do you want to request?"); -Integer nrOfHolidays = Integer.valueOf(scanner.nextLine()); - -System.out.println("Why do you need them?"); -String description = scanner.nextLine(); ----- - -接下来,我们使用__RuntimeService__启动一个__流程实例__。收集的数据作为一个__java.util.Map__实例传递,其中的键就是之后用于获取变量的标识符。这个流程实例使用__key__启动。这个__key__就是BPMN 2.0 XML文件中设置的__id__属性,在这个例子里是__holidayRequest__。 - -(请注意:除了使用key之外,在后面你还会看到有很多其他方式启动一个流程实例) - -[source,xml] ----- - ----- - -[source,java,linenums] ----- -RuntimeService runtimeService = processEngine.getRuntimeService(); - -Map variables = new HashMap(); -variables.put("employee", employee); -variables.put("nrOfHolidays", nrOfHolidays); -variables.put("description", description); -ProcessInstance processInstance = - runtimeService.startProcessInstanceByKey("holidayRequest", variables); ----- - -在流程实例启动后,会创建一个**执行(execution)**,并将其放在启动事件上。从这里开始,这个__执行__沿着顺序流移动到经理审批的用户任务,并执行用户任务行为。这个行为将在数据库中创建一个任务,该任务可以之后使用查询找到。用户任务是一个__等待状态(wait state)__,引擎会停止执行,返回API调用处。 - -[[_sidetrack_transactionality]] -==== 另一个话题:事务 - -在Flowable中,数据库事务扮演了关键角色,用于保证数据一致性,并解决并发问题。当调用Flowable API时,默认情况下,所有操作都是同步的,并处于同一个事务下。这意味着,当方法调用返回时,会启动并提交一个事务。 - -流程启动后,会有**一个数据库事务**从流程实例启动时持续到下一个__等待状态__。在这个例子里,指的是第一个用户任务。当引擎到达这个用户任务时,状态会持久化至数据库,提交事务,并返回API调用处。 - -在Flowable中,当一个流程实例运行时,总会有一个数据库事务从前一个__等待状态__持续到下一个__等待状态__。数据持久化之后,可能在数据库中保存很长时间,甚至几年,直到某个API调用使流程实例继续执行。请注意当流程处在等待状态时,不会消耗任何计算或内存资源,直到下一次APi调用。 - -在这个例子中,当第一个用户任务完成时,会启动一个数据库事务,从用户任务开始,经过排他网关(自动逻辑),直到第二个用户任务。或通过另一条路径直接到达结束。 - -[[_querying_and_completing_tasks]] -==== 查询与完成任务 - -在更实际的应用中,会为雇员及经理提供用户界面,让他们可以登录并查看任务列表。其中可以看到作为__流程变量__存储的流程实例数据,并决定如何操作任务。在这个例子中,我们通过执行API调用来模拟任务列表,通常这些API都是由UI驱动的服务在后台调用的。 - -我们还没有为用户任务配置办理人。我们想将第一个任务指派给"经理(managers)"组,而第二个用户任务指派给请假申请的提交人。因此需要为第一个任务添加__candidateGroups__属性: - -[source,xml] ----- - ----- - -并如下所示为第二个任务添加__assignee__属性。请注意我们没有像上面的'managers'一样使用静态值,而是使用一个流程变量动态指派。这个流程变量是在流程实例启动时传递的: - - -[source,xml] ----- - ----- - -要获得实际的任务列表,需要通过__TaskService__创建一个__TaskQuery__。我们配置这个查询只返回'managers'组的任务: - -[source,java,linenums] ----- -TaskService taskService = processEngine.getTaskService(); -List tasks = taskService.createTaskQuery().taskCandidateGroup("managers").list(); -System.out.println("You have " + tasks.size() + " tasks:"); -for (int i=0; i processVariables = taskService.getVariables(task.getId()); -System.out.println(processVariables.get("employee") + " wants " + - processVariables.get("nrOfHolidays") + " of holidays. Do you approve this?"); ----- - -运行结果像下面这样: - -image::images/getting.started.console.logging3.png[align="center"] - -经理现在就可以**完成任务**了。在现实中,这通常意味着由用户提交一个表单。表单中的数据作为__流程变量__传递。在这里,我们在完成任务时传递带有'approved'变量(这个名字很重要,因为之后会在顺序流的条件中使用!)的map来模拟: - -[source,java,linenums] ----- -boolean approved = scanner.nextLine().toLowerCase().equals("y"); -variables = new HashMap(); -variables.put("approved", approved); -taskService.complete(task.getId(), variables); ----- - -现在任务完成,并会在离开排他网关的两条路径中,基于'approved'流程变量选择一条。 - -[[getting.started.delegate]] -==== 实现JavaDelegate - -拼图还缺了一块:我们还没有实现申请通过后执行的自动逻辑。在BPMN 2.0 XML中,这是一个**服务任务(service task)**: - -[source,xml] ----- - ----- - -在现实中,这个逻辑可以做任何事情:向某个系统发起一个HTTP REST服务调用,或调用某个使用了好几十年的系统中的遗留代码。我们不会在这里实现实际的逻辑,而只是简单的日志记录__流程__。 - -创建一个新的类(在Eclipse里__File -> New -> Class__),填入__org.flowable__作为包名,__CallExternalSystemDelegate__作为类名。让这个类实现__org.flowable.engine.delegate.JavaDelegate__接口,并实现__execute__方法: - -[source,java,linenums] ----- -package org.flowable; - -import org.flowable.engine.delegate.DelegateExecution; -import org.flowable.engine.delegate.JavaDelegate; - -public class CallExternalSystemDelegate implements JavaDelegate { - - public void execute(DelegateExecution execution) { - System.out.println("Calling the external system for employee " - + execution.getVariable("employee")); - } - -} ----- - -当__执行__到达__服务任务__时,会初始化并调用BPMN 2.0 XML中所引用的类。 - -现在执行这个例子的时候,就会显示出日志信息,说明已经执行了自定义逻辑: - -image::images/getting.started.console.logging4.png[align="center"] - -[[_working_with_historical_data]] -==== 使用历史数据 - -选择使用Flowable这样的流程引擎的原因之一,是它可以自动存储所有流程实例的**审计数据**或**历史数据**。这些数据可以用于创建报告,深入展现组织运行的情况,瓶颈在哪里,等等。 - -例如,如果希望显示流程实例已经执行的时间,就可以从__ProcessEngine__获取__HistoryService__,并创建__历史活动(historical activities)__的查询。在下面的代码片段中,可以看到我们添加了一些额外的过滤条件: - -* 只选择一个特定流程实例的活动 -* 只选择已完成的活动 - -结果按照结束时间排序,代表其执行顺序。 - -[source,java,linenums] ----- -HistoryService historyService = processEngine.getHistoryService(); -List activities = - historyService.createHistoricActivityInstanceQuery() - .processInstanceId(processInstance.getId()) - .finished() - .orderByHistoricActivityInstanceEndTime().asc() - .list(); - -for (HistoricActivityInstance activity : activities) { - System.out.println(activity.getActivityId() + " took " - + activity.getDurationInMillis() + " milliseconds"); -} ----- - -再次运行例子,可以看到控制台中显示: - ----- -startEvent took 1 milliseconds -approveTask took 2638 milliseconds -decision took 3 milliseconds -externalSystemCall took 1 milliseconds ----- - -[[_conclusion]] -==== 小结 - -这个教程介绍了很多Flowable与BPMN 2.0的概念与术语,也展示了如何编程使用Flowable API。 - -当然,这只是个开始。下面的章节会更深入介绍许多Flowable引擎支持的选项与特性。其他章节介绍安装与使用Flowable引擎的不同方法,并详细介绍了所有可用的BPMN 2.0结构。 - -[[getting.started.rest]] -=== 开始使用Flowable REST API - -这个章节展示了与<>相同的例子:部署一个流程定义,启动一个流程实例,获取任务列表并完成一个任务。最好先快速浏览上一章节以了解所做的事情。 - -这一次,将使用Flowable REST API而不是Java API。你很快就会意识到REST API与Java API紧密关联。只要了解一个,就能很快学会另一个。 - -可以在<>章节找到Flowable REST API的完整细节。 - -[[_setting_up_the_rest_application]] -==== 安装REST应用 - -从flowable.org网站下载.zip文件后,可以在__wars__文件夹下找到REST应用。要运行这个WAR文件,需要一个servlet容器,例如link:$$http://tomcat.apache.org/$$[Tomcat]、link:$$http://www.eclipse.org/jetty/$$[Jetty]等。 - -使用Tomcat的步骤如下: - -* 下载并解压缩最新的Tomcat zip文件(在Tomcat网站中选择'Core'发行版)。 -* 将flowable-rest.war文件从解压的Flowable发行版的__wars__文件夹中复制到解压的Tomcat文件夹下的__webapps__文件夹下。 -* 使用命令行,转到Tomcat文件夹下的__bin__文件夹。 -* 执行'__./catalina run__'启动Tomcat服务器。 - -在服务启动过程中,会显示一些Flowable日志信息。在最后显示的一条类似'__INFO [main] org.apache.catalina.startup.Catalina.start Server startup in xyz ms__'的消息标志着服务器已经启动,可以接受请求。请注意默认情况下,使用H2内存数据库,这意味着数据在服务器重启后会丢失。 - -在下面的章节中,我们使用cURL展示各种REST调用。所有的REST调用默认都使用__基本认证__保护,所有的调用的用户都是 'rest-admin',密码为'test'。 - - -在启动后,通过执行下列命令验证应用运行正常: - ----- -curl --user rest-admin:test http://localhost:8080/flowable-rest/service/management/engine ----- - -如果能获得正确的json响应,则说明REST API已经启动并在工作。 - -[[_deploying_a_process_definition_2]] -==== 部署流程定义 - -第一步是部署一个流程定义。使用REST API时,需要将一个.bpmn20.xml文件(或对于多个流程引擎,一个.zip文件)作为'multipart/formdata'上传: - ----- -curl --user rest-admin:test -F "file=@holiday-request.bpmn20.xml" http://localhost:8080/flowable-rest/service/repository/deployments ----- - -要验证流程定义已经正确部署,可以请求流程定义的列表: - ----- -curl --user rest-admin:test http://localhost:8080/flowable-rest/service/repository/process-definitions ----- - -这将返回当前引擎中部署的所有流程定义的列表。 - -[[_start_a_process_instance]] -==== 启动流程实例 - -使用REST API启动一个流程实例与使用Java API很像:提供__key__作为流程定义的标识,并使用一个map作为初始化流程变量: - ----- -curl --user rest-admin:test -H "Content-Type: application/json" -X POST -d '{ "processDefinitionKey":"holidayRequest", "variables": [ { "name":"employee", "value": "John Doe" }, { "name":"nrOfHolidays", "value": 7 }]}' http://localhost:8080/flowable-rest/service/runtime/process-instances ----- - -将返回: - ----- -{"id":"43","url":"http://localhost:8080/flowable-rest/service/runtime/process-instances/43","businessKey":null,"suspended":false,"ended":false,"processDefinitionId":"holidayRequest:1:42","processDefinitionUrl":"http://localhost:8080/flowable-rest/service/repository/process-definitions/holidayRequest:1:42","activityId":null,"variables":[],"tenantId":"","completed":false} ----- - -[[_task_list_and_completing_a_task]] -==== 任务列表与完成任务 - -当流程实例启动后,第一个任务会指派给'managers'组。要获取这个组的所有任务,可以通过REST API进行任务查询: - ----- -curl --user rest-admin:test -H "Content-Type: application/json" -X POST -d '{ "candidateGroup" : "managers" }' http://localhost:8080/flowable-rest/service/query/tasks ----- - -这将返回'manager'组的所有任务的列表。 - -可以这样完成任务: - ----- -curl --user rest-admin:test -H "Content-Type: application/json" -X POST -d '{ "action" : "complete", "variables" : [ { "name" : "approved", "value" : true} ] }' http://localhost:8080/flowable-rest/service/runtime/tasks/25 ----- - -然而,很可能会产生如下的错误: - ----- -{"message":"Internal server error","exception":"couldn't instantiate class org.flowable.CallExternalSystemDelegate"} ----- - -这意味着引擎无法找到服务任务引用的__CallExternalSystemDelegate__类。要解决这个错误,需要将该类放在应用的classpath下(并需要重启应用)。按照<>的介绍创建该类,并将其打包为JAR,放在Tomcat的__webapps__目录下的flowable-rest目录下的__WEB-INF/lib__目录下。 diff --git a/docs/userguide/src/zh_CN/bpmn/ch03-Configuration.adoc b/docs/userguide/src/zh_CN/bpmn/ch03-Configuration.adoc deleted file mode 100755 index 3f4da310a51..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch03-Configuration.adoc +++ /dev/null @@ -1,801 +0,0 @@ -[[_configuration]] -== 配置 - -[[configuration]] - -=== 创建ProcessEngine - -Flowable流程引擎通过名为++flowable.cfg.xml++的XML文件进行配置。请注意这种方式与<>**不**一样。 - -获取++ProcessEngine++,最简单的方式是使用++org.flowable.engine.ProcessEngines++类: - -[source,java,linenums] ----- -ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine() ----- - -这样会从classpath寻找++flowable.cfg.xml++,并用这个文件中的配置构造引擎。下面的代码展示了一个配置的例子。后续章节会对配置参数进行详细介绍。 - -[source,xml,linenums] ----- - - - - - - - - - - - - - - - - - - ----- - -请注意这个配置XML文件实际上是一个Spring配置文件。**但这并不意味着Flowable只能用于Spring环境!**我们只是利用Spring内部的解析与依赖注入功能来简化引擎的构建过程。 - -也可以通过编程方式使用配置文件,来构造ProcessEngineConfiguration对象。也可以使用不同的bean id(例如第3行)。 - -[source,java,linenums] ----- -ProcessEngineConfiguration. - createProcessEngineConfigurationFromResourceDefault(); - createProcessEngineConfigurationFromResource(String resource); - createProcessEngineConfigurationFromResource(String resource, String beanName); - createProcessEngineConfigurationFromInputStream(InputStream inputStream); - createProcessEngineConfigurationFromInputStream(InputStream inputStream, String beanName); ----- - -也可以不使用配置文件,使用默认配置(参考<>获得更多信息)。 - - -[source,java,linenums] ----- -ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration(); -ProcessEngineConfiguration.createStandaloneInMemProcessEngineConfiguration(); ----- - -所有的++ProcessEngineConfiguration.createXXX()++方法都返回++ProcessEngineConfiguration++,并可以继续按需调整。调用++buildProcessEngine()++后,生成一个++ProcessEngine++: - -[source,java,linenums] ----- -ProcessEngine processEngine = ProcessEngineConfiguration.createStandaloneInMemProcessEngineConfiguration() - .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_FALSE) - .setJdbcUrl("jdbc:h2:mem:my-own-db;DB_CLOSE_DELAY=1000") - .setAsyncExecutorActivate(false) - .buildProcessEngine(); ----- - - - -[[configurationRoot]] - - -=== ProcessEngineConfiguration bean - - -++flowable.cfg.xml++文件中必须包含一个id为$$'processEngineConfiguration'$$的bean。 - -[source,xml,linenums] ----- - ----- - - -这个bean用于构建++ProcessEngine++。有多个类可以用于定义++processEngineConfiguration++。这些类用于不同的环境,并各自设置一些默认值。最佳实践是选择最匹配你环境的类,以便减少配置引擎需要的参数。目前可以使用的类为:[[configurationClasses]] - -* *org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration*:流程引擎独立运行。Flowable自行处理事务。在默认情况下,数据库检查只在引擎启动时进行(如果Flowable表结构不存在或表结构版本不对,会抛出异常)。 -* *org.flowable.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration*:这是一个便于使用单元测试的类。Flowable自行处理事务。默认使用H2内存数据库。数据库会在引擎启动时创建,并在引擎关闭时删除。使用这个类时,很可能不需要更多的配置(除了使用任务执行器或邮件等功能时)。 -* *org.flowable.spring.SpringProcessEngineConfiguration*:在流程引擎处于Spring环境时使用。查看<>章节了解更多信息。 -* *org.flowable.engine.impl.cfg.JtaProcessEngineConfiguration*:用于引擎独立运行,并使用JTA事务的情况。 - - -[[databaseConfiguration]] - -=== 配置数据库 - - -有两种方式配置Flowable引擎使用的数据库。第一种方式是定义数据库的JDBC参数: - -* *jdbcUrl*: 数据库的JDBC URL。 -* *jdbcDriver*: 对应数据库类型的驱动。 -* *jdbcUsername*: 用于连接数据库的用户名。 -* *jdbcPassword*: 用于连接数据库的密码。 - -通过提供的JDBC参数构造的数据源,使用默认的link:$$http://www.mybatis.org/$$[MyBatis]连接池设置。可用下列属性调整这个连接池(来自MyBatis文档): - -* *jdbcMaxActiveConnections*: 连接池能够容纳的最大活动连接数量。默认值为10. -* *jdbcMaxIdleConnections*: 连接池能够容纳的最大空闲连接数量。 -* *jdbcMaxCheckoutTime*: 连接从连接池“取出”后,被强制返回前的最大时间间隔,单位为毫秒。默认值为20000(20秒)。 -* *jdbcMaxWaitTime*: 这是一个底层设置,在连接池获取连接的时间异常长时,打印日志并尝试重新获取连接(避免连接池配置错误,导致没有异常提示)。默认值为20000(20秒)。 - -数据库配置示例: - -[source,xml,linenums] ----- - - - - ----- - -我们的跑分显示MyBatis连接池在处理大量并发请求时,并不是最经济或最具弹性的。因此,建议使用++javax.sql.DataSource++的实现,并将其注入到流程引擎配置中(如Hikari、Tomcat JDBC连接池,等等): - - -[source,xml,linenums] ----- - - - - - - - - - - - - ... - ----- - - -请注意Flowable发布时不包括用于定义数据源的库。需要自行把库放在classpath中。 - -无论使用JDBC还是数据源方式配置,都可以使用下列参数: - -* *databaseType*: 通常不需要专门设置这个参数,因为它可以从数据库连接信息中自动检测得出。只有在自动检测失败时才需要设置。可用值:{h2, mysql, oracle, postgres, mssql, db2}。这个选项会决定创建、删除与查询时使用的脚本。查看<>章节了解我们支持哪些类型的数据库。 -* *databaseSchemaUpdate*: 用于设置流程引擎启动关闭时使用的数据库表结构控制策略。 -** +false+ (默认): 当引擎启动时,检查数据库表结构的版本是否匹配库文件版本。版本不匹配时抛出异常。 -** ++true++: 构建引擎时,检查并在需要时更新表结构。表结构不存在则会创建。 -** ++create-drop++: 引擎创建时创建表结构,并在引擎关闭时删除表结构。 - -[[jndiDatasourceConfig]] - -=== 配置JNDI数据源 - -默认情况下,Flowable的数据库配置保存在每个web应用WEB-INF/classes文件夹下的db.properties文件中。有时这样并不合适,因为这需要用户修改Flowable源码中的db.properties文件并重新编译war包,或者在部署后解开war包并修改db.properties文件。 - - -通过使用JNDI(Java Naming and Directory Interface,Java命名和目录接口)获取数据库连接,连接就完全交由Servlet容器管理,并可以在WAR部署之外管理配置。同时也提供了比db.properties中更多的控制连接的参数。 - -[[jndi_configuration]] - -==== 配置 - -根据你使用的servlet容器应用不同,配置JNDI数据源的方式也不同。下面的介绍用于Tomcat,对于其他容器应用,请参考对应的文档。 - -Tomcat的JNDI资源配置在$CATALINA_BASE/conf/[enginename]/[hostname]/[warname].xml (对于Flowable UI通常会是$CATALINA_BASE/conf/Catalina/localhost/flowable-app.xml)。当应用第一次部署时,默认会从Flowable war包中复制context.xml。所以如果存在这个文件则需要替换。例如,如果需要将JNDI资源修改为应用连接MySQL而不是H2,需要如下修改: - - -[source,xml,linenums] ----- - - - - ----- - -[[_jndi_properties]] -==== JNDI参数 - -在Flowable UI的配置文件中使用下列参数配置JNDI数据源: - -* spring.datasource.jndi-name=: 数据源的JNDI名 -* datasource.jndi.resourceRef: 设置是否在J2EE容器中查找。也就是说,如果JNDI名中没有包含"java:comp/env/"前缀,是否需要添加它。默认为"true"。 - - -[[supporteddatabases]] - - -=== 支持的数据库 - -下面列出Flowable用于引用数据库的类型(区分大小写!)。 - -[[databaseTypes]] -[options="header"] -|=============== -|Flowable数据库类型|示例JDBC URL|备注 -|h2|jdbc:h2:tcp://localhost/flowable|默认配置的数据库 -|mysql|jdbc:mysql://localhost:3306/flowable?autoReconnect=true|已使用mysql-connector-java数据库驱动测试 -|oracle|jdbc:oracle:thin:@localhost:1521:xe| -|postgres|jdbc:postgresql://localhost:5432/flowable| -|db2|jdbc:db2://localhost:50000/flowable| -|mssql|jdbc:sqlserver://localhost:1433;databaseName=flowable (jdbc.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver) _OR_ jdbc:jtds:sqlserver://localhost:1433/flowable (jdbc.driver=net.sourceforge.jtds.jdbc.Driver)|已使用Microsoft JDBC Driver 4.0 (sqljdbc4.jar)与JTDS Driver测试 -|=============== - - -[[creatingDatabaseTable]] - -=== 创建数据库表 - -在你的数据库中创建数据库表,最简单的方法是: - -* 在classpath中添加flowable-engine JAR -* 添加合适的数据库驱动 -* 在classpath中添加Flowable配置文件(__flowable.cfg.xml__),指向你的数据库(参考<>) -* 执行__DbSchemaCreate__类的main方法 - -然而,通常只有数据库管理员可以在数据库中执行DDL语句,在生产环境中这也是最明智的选择。DDL的SQL脚本可以在Flowable下载页面或Flowable发布文件夹中找到,位于++database++子文件夹。引擎JAR (__flowable-engine-x.jar__)的__org/flowable/db/create__包中也有一份(__drop__文件夹存放删除脚本)。SQL文件的格式为: - ----- -flowable.{db}.{create|drop}.{type}.sql ----- - -其中__db__为<>,而__type__为: - -* *engine:* 引擎执行所需的表,必需。 -* *history:* 存储历史与审计信息的表。当历史级别设置为__none__时不需要。请注意不使用这些表会导致部分使用历史数据的功能失效(如任务备注)。 - -**MySQL用户请注意:**低于5.6.4的MySQL版本不支持timestamps或包含毫秒精度的日期。更糟的是部分版本会在创建类似的列时抛出异常,而另一些版本则不会。当使用自动创建/升级时,引擎在执行时会自动修改DDL语句。当使用DDL文件方式建表时,可以使用通用版本,或使用文件名包含__mysql55__的特殊版本(用于5.6.4以下的任何版本)。特殊版本的文件中不会使用毫秒精度的列类型。 - -具体地说,对于MySQL的版本: - -* *<5.6:* 不支持毫秒精度。可以使用DDL文件(使用包含__mysql55__的文件)。可以使用自动创建/升级。 -* *5.6.0 - 5.6.3:* 不支持毫秒精度。**不**可以使用自动创建/升级。建议升级为较新版本的数据库。如果确实需要,可以使用包含__mysql55__的DDL文件。 -* *5.6.4+:* 支持毫秒精度。可以使用DDL文件(默认的包含__mysql__的文件)。可以使用自动创建/升级。 - - -请注意如果在Flowable表已经创建/升级后,再升级MySQL数据库,则需要手工修改列类型! - - -[[database.tables.explained]] - - -=== 数据库表名说明 - -Flowable的所有数据库表都以**ACT_**开头。第二部分是说明表用途的两字符标示符。服务API的命名也大略符合这个规则。 - -* *ACT_RE_**: 'RE'代表++repository++。带有这个前缀的表包含“静态”信息,例如流程定义与流程资源(图片、规则等)。 -* *ACT_RU_**: 'RU'代表++runtime++。这些表存储运行时信息,例如流程实例(process instance)、用户任务(user task)、变量(variable)、作业(job)等。Flowable只在流程实例运行中保存运行时数据,并在流程实例结束时删除记录。这样保证运行时表小和快。 -* *ACT_HI_**: 'HI'代表++history++。这些表存储历史数据,例如已完成的流程实例、变量、任务等。 -* *ACT_GE_**: 通用数据。在多处使用。 - - -[[databaseUpgrade]] - - -=== 数据库升级 - -在升级前,请确保你已经(使用数据库的备份功能)备份了数据库。 - -默认情况下,每次流程引擎创建时会进行版本检查,通常是在你的应用或者Flowable web应用启动的时候。如果Flowable发现库版本与Flowable数据库表版本不同,会抛出异常。 - -要进行升级,首先需要将下列配置参数放入你的flowable.cfg.xml配置文件: - -[source,xml,linenums] ----- - - - - - - - - - ----- - -**同时,在classpath中加上合适的数据库驱动。**升级应用中的Flowable库,或者启动一个新版本的Flowable,并将它指向包含旧版本数据的数据库。将++databaseSchemaUpdate++设置为++true++。当Flowable发现库与数据库表结构不一致时,会自动将数据库表结构升级至新版本。 - -**也可以直接运行升级DDL语句。**也可以从Flowable下载页面获取升级数据库脚本并运行。 - -[[jobExecutorConfiguration]] - -=== 作业执行器(从6.0.1版本起) - -在Flowable V6中唯一可用的作业执行器,是Flowable V5中的异步执行器(async executor)。因为它为Flowable引擎提供了性能更好,对数据库也更友好的执行异步作业的方式。 -Flowable V5中的作业执行器(job executor)在V6中不再可用。可以在用户手册的高级章节找到更多信息。 - -此外,如果在Java EE 7下运行,容器还可以使用符合JSR-236标准的++ManagedAsyncJobExecutor++来管理线程。要启用这个功能,需要在配置中如下加入线程工厂: - -[source,xml,linenums] ----- - - - - - - - - - ----- - -如果没有设置线程工厂,ManagedAsyncJobExecutor实现会退化为默认实现(AsyncJobExecutor)。 - -[[_job_executor_activation]] -=== 启用作业执行器 - -++AsyncExecutor++是管理线程池的组件,用于触发定时器与其他异步任务。也可以使用其他实现(如使用消息队列,参见用户手册的高级章节)。 - -默认情况下,++AsyncExecutor++并未启用,也不会启动。如下配置使异步执行器与Flowable引擎一同启动: - -[source,xml,linenums] ----- - ----- - -asyncExecutorActivate这个参数使Flowable引擎在启动同时启动异步执行器。 - -[[mailServerConfiguration]] - - -=== 配置邮件服务器 - -配置邮件服务器是可选的。Flowable支持在业务流程中发送电子邮件。发送电子邮件需要配置有效的SMTP邮件服务器。查看<>了解配置选项。 - - -[[historyConfiguration]] - - -=== 配置历史 - -历史存储的配置是可选的。你可以通过调整配置控制<>。查看<>章节了解更多细节。 - -[source,xml,linenums] ----- - ----- - - -[[asyncHistoryConfiguration]] - - -=== 配置异步历史 - -[实验性] 从Flowable 6.1.0起,添加了异步历史功能。当启用异步历史时,历史数据将由历史任务执行器负责持久化,而不是与运行时执行持久化同步保存。 -查看<>章节了解更多细节。 - -[source,xml,linenums] ----- - ----- - - -[[exposingConfigurationBeans]] - - -=== 配置在表达式与脚本中可用的bean - -默认情况下,所有通过++flowable.cfg.xml++或你自己的Spring配置文件声明的bean,都可以在表达式与脚本中使用。如果你希望限制配置文件中bean的可见性,可以使用流程引擎配置的++beans++参数。++ProcessEngineConfiguration++中的++beans++参数是一个map。当你配置这个参数时,只有在这个map中声明的bean可以在表达式与脚本中使用。bean会使用你在map中指定的名字暴露。 - - -[[processDefinitionCacheConfiguration]] - - -=== 配置部署缓存 - -鉴于流程定义信息不会改变,为了避免每次使用流程定义时都读取数据库,所有的流程定义都会(在解析后)被缓存。默认情况下,这个缓存没有限制。要限制流程定义缓存,加上如下的参数 - -[source,xml,linenums] ----- - ----- - - -设置这个参数,会将默认的hashmap缓存替换为LRU缓存,以进行限制。当然,参数的“最佳”取值,取决于总的流程定义数量,以及实际使用的流程定义数量。 - - -也可以注入自己的缓存实现。必须是一个实现了++org.flowable.engine.impl.persistence.deploy.DeploymentCache++接口的bean: - -[source,xml,linenums] ----- - - - ----- - - -类似的,可以使用名为++knowledgeBaseCacheLimit++与++knowledgeBaseCache++的参数配置规则缓存(rules cache)。只有在流程中使用规则任务(rules task)时才需要设置。 - - -[[loggingConfiguration]] - - -=== 日志 - -所有的日志(Flowable、Spring、MyBatis等)都通过SLF4J路由,并允许你自行选择日志实现。 - -**默认情况下,Flowable引擎依赖中不提供SFL4J绑定JAR。你需要自行将其加入你的项目,以便使用所选的日志框架。**如果没有加入实现JAR,SLF4J会使用NOP-logger。这时除了一条警告外,不会记录任何日志。可以从link:$$http://www.slf4j.org/codes.html#StaticLoggerBinder$$[http://www.slf4j.org/codes.html#StaticLoggerBinder]了解关于绑定的更多信息。 - -可以像这样(这里使用Log4j)使用Maven添加依赖,请注意你还需要加上版本: - -[source,xml,linenums] ----- - - org.slf4j - slf4j-log4j12 - ----- - - -Flowable-UI与Flowable-rest web应用配置为使用Log4j绑定。运行所有flowable-*模块的测试时也会使用Log4j。 - -**重要提示:当使用classpath中带有commons-logging的容器时:**为了将spring的日志路由至SLF4j,需要使用桥接(参考link:$$http://www.slf4j.org/legacy.html#jclOverSLF4J$$[http://www.slf4j.org/legacy.html#jclOverSLF4J])。如果你的容器提供了commons-logging实现,请按照link:$$http://www.slf4j.org/codes.html#release$$[http://www.slf4j.org/codes.html#release]页面的指示调整。 - - -使用Maven的示例(省略了版本): - -[source,xml,linenums] ----- - - org.slf4j - jcl-over-slf4j - ----- - - -[[MDC]] - - -=== 映射诊断上下文 - - -Flowable支持SLF4J的映射诊断上下文特性。下列基本信息会与需要日志记录的信息一起,传递给底层日志实现: - -* processDefinition Id 作为 mdcProcessDefinitionID -* processInstance Id 作为 mdcProcessInstanceID -* execution Id 作为 mdcExecutionId - -默认情况下这些信息都不会被日志记录,但可以通过配置logger,按照你想要的格式,与其他日志信息一起显示。例如在Log4j中进行如下简单的格式定义,就可以让logger显示上述信息: - -[source,properties,linenums] ----- -log4j.appender.consoleAppender.layout.ConversionPattern=ProcessDefinitionId=%X{mdcProcessDefinitionID} -executionId=%X{mdcExecutionId} mdcProcessInstanceID=%X{mdcProcessInstanceID} mdcBusinessKey=%X{mdcBusinessKey} %m%n ----- - -如果需要使用日志中包含的信息进行实时监测(如使用日志分析器),就会很有帮助。 - - -[[eventDispatcher]] - - -=== 事件处理器 - -Flowable引擎中的事件机制可以让你在引擎中发生多种事件的时候得到通知。查看<>了解可用的事件。 - -可以只为特定种类的事件注册监听器,而不是在任何类型的事件发送时都被通知。可以<>添加引擎全局的事件监听器,<>添加引擎全局的事件监听器,也可以<>添加事件监听器。 - -所有被分发的事件都是++org.flowable.engine.common.api.delegate.event.FlowableEvent++的子类。事件(在可用时)提供++type++, +executionId+, ++processInstanceId++与++processDefinitionId++。部分事件含有关于发生事件的上下文信息。关于事件包含的附加信息,请参阅<>。 - -[[eventDispatcherListener]] - - -==== 实现事件监听器 - -对事件监听器的唯一要求,是要实现++org.flowable.engine.delegate.event.FlowableEventListener++接口。下面是一个监听器实现的例子,它将接收的所有事件打印至标准输出,并对作业执行相关的事件特别处理: - -[source,java,linenums] ----- -public class MyEventListener implements FlowableEventListener { - - @Override - public void onEvent(FlowableEvent event) { - switch (event.getType()) { - - case JOB_EXECUTION_SUCCESS: - System.out.println("A job well done!"); - break; - - case JOB_EXECUTION_FAILURE: - System.out.println("A job has failed..."); - break; - - default: - System.out.println("Event received: " + event.getType()); - } - } - - @Override - public boolean isFailOnException() { - // onEvent方法中的逻辑并不重要,可以忽略日志失败异常…… - - return false; - } -} ----- - - -++isFailOnException()++方法决定了当事件分发后,++onEvent(..)++方法抛出异常时的行为。若返回++false++,忽略异常;若返回++true++,异常不会被忽略而会被上抛,使当前执行的命令失败。如果事件是API调用(或其他事务操作,例如作业执行)的一部分,事务将被回滚。如果事件监听器中并不是重要的业务操作,建议返回++false++。 - -Flowable提供了少量基础实现,以简化常用的事件监听器使用场景。它们可以被用作监听器的示例或基类: - -* *org.flowable.engine.delegate.event.BaseEntityEventListener*: 事件监听器基类,可用来监听实体(entity)相关事件,特定或所有实体的事件都可以。它隐藏了类型检测,提供了4个需要覆盖的方法:++onCreate(..)++, ++onUpdate(..)++与++onDelete(..)++在实体创建、更新及删除时调用;对所有其他实体相关事件,++onEntityEvent(..)++会被调用。 - - - -[[eventDispatcherConfiguration]] - - -==== 配置与使用 - -在流程引擎中配置的事件监听器会在流程引擎启动时生效,引擎重启后也会保持有效。 - -++eventListeners++参数为++org.flowable.engine.delegate.event.FlowableEventListener++类实例的列表(list)。与其他地方一样,你可以声明内联bean定义,也可以用++ref++指向已有的bean。下面的代码片段在配置中添加了一个事件监听器,无论任何类型的事件分发时,都会得到通知: - -[source,xml,linenums] ----- - - ... - - - - - - ----- - -要在特定类型的事件分发时得到通知,使用++typedEventListeners++参数,值为map。map的key为逗号分隔的事件名字列表(或者一个事件的名字),取值为++org.flowable.engine.delegate.event.FlowableEventListener++实例的列表。下面的代码片段在配置中添加了一个事件监听器,它会在作业执行成功或失败时得到通知: - -[source,xml,linenums] ----- - - ... - - - - - - - - - - ----- - - -事件分发的顺序由加入监听器的顺序决定。首先,所有普通(++eventListeners++参数定义的)事件监听器按照在++list++里的顺序被调用;之后,如果分发的是某类型的事件,则(++typedEventListeners++ 参数定义的)该类型监听器被调用。 - - -[[eventDispatcherConfigurationRuntime]] - -==== 在运行时添加监听器 - -可以使用API(++RuntimeService++)为引擎添加或删除事件监听器: - -[source,java,linenums] ----- - -/** - * 新增一个监听器,会在所有事件发生时被通知。 - * @param listenerToAdd 要新增的监听器 - */ -void addEventListener(FlowableEventListener listenerToAdd); - -/** - * 新增一个监听器,在给定类型的事件发生时被通知。 - * @param listenerToAdd 要新增的监听器 - * @param types 监听器需要监听的事件类型 - */ -void addEventListener(FlowableEventListener listenerToAdd, FlowableEventType... types); - -/** - * 从分发器中移除指定监听器。该监听器将不再被通知,无论该监听器注册为监听何种类型。 - * @param listenerToRemove 要移除的监听器 - */ - void removeEventListener(FlowableEventListener listenerToRemove); ----- - -请注意,运行时新增的监听器**在引擎重启后不会保持。** - - -[[eventDispatcherConfigurationProcessDefinition]] - - -==== 为流程定义增加监听器 - -可以为某一流程定义增加监听器。只有与该流程定义相关,或使用该流程定义启动的流程实例相关的事件,才会调用这个监听器。监听器实现可以用完全限定类名(fully qualified classname)定义;也可以定义为表达式,该表达式需要能被解析为实现监听器接口的bean;也可以配置为抛出消息(message)/信号(signal)/错误(error)的BPMN事件。 - - -[[_listeners_executing_user_defined_logic]] -===== 执行用户定义逻辑的监听器 - -下面的代码片段为流程定义增加了2个监听器。第一个监听器接收任何类型的事件,使用完全限定类名定义。第二个监听器只在作业成功执行或失败时被通知,使用流程引擎配置中++beans++参数定义的bean作为监听器。 - -[source,xml,linenums] ----- - - - - - - - ... - - ----- - -实体相关的事件也可以在流程定义中增加监听器,只有在特定实体类型的事件发生时得到通知。下面的代码片段展示了如何设置。可以响应实体的所有事件(第一个例子),或只响应实体的特定类型事件(第二个例子)。 - - -[source,xml,linenums] ----- - - - - - - - ... - - ----- - -++entityType++可用的值有:++attachment++(附件), ++comment++(备注), ++execution++(执行), ++identity-link++(身份关联), ++job++(作业), ++process-instance++(流程实例), ++process-definition++(流程定义), ++task++(任务)。 - -[[_listeners_throwing_bpmn_events]] - -===== 抛出BPMN事件的监听器 - -处理分发的事件的另一个方法,是抛出BPMN事件。请牢记在心,只有特定种类的Flowable事件类型,抛出BPMN事件才合理。例如,在流程实例被删除时抛出BPMN事件,会导致错误。下面的代码片段展示了如何在流程实例中抛出信号,向外部流程(全局)抛出信号,在流程实例中抛出消息事件,以及在流程实例中抛出错误事件。这里不使用++class++或++delegateExpression++,而要使用++throwEvent++属性,以及一个附加属性,用于指定需要抛出的事件类型。 - -[source,xml,linenums] ----- - - - - - ----- - -[source,xml,linenums] ----- - - - - - ----- - - -[source,xml,linenums] ----- - - - - - ----- - -[source,xml,linenums] ----- - - - - - ----- - -如果需要使用额外的逻辑判断是否需要抛出BPMN事件,可以扩展Flowable提供的监听器类。通过在你的子类中覆盖++isValidEvent(FlowableEvent event)++,可以阻止抛出BPMN事件。相关的类为++org.flowable.engine.test.api.event.SignalThrowingEventListenerTest++, ++org.flowable.engine.impl.bpmn.helper.MessageThrowingEventListener++与++org.flowable.engine.impl.bpmn.helper.ErrorThrowingEventListener++. - -[[_notes_on_listeners_on_a_process_definition]] -===== 关于流程定义监听器的说明 - -* 事件监听器只能作为++extensionElements++的子元素,声明在++process++元素上。不能在个别节点(activity)上定义(事件)监听器。 -* ++delegateExpression++中的表达式,与其他表达式(例如在网关中的)不一样,不可以访问执行上下文。只能够引用在流程引擎配置中++beans++参数定义的bean;或是在使用spring(且没有定义beans参数)时,引用任何实现了监听器接口的spring bean。 -* 使用监听器的++class++属性时,只会创建唯一一个该类的实例。请确保监听器实现不依赖于成员变量,或确保多线程/上下文的使用安全。 -* 如果++events++属性使用了不合法的事件类型,或者使用了不合法的++throwEvent++值,会在流程定义部署时抛出异常(导致部署失败)。如果++class++或++delegateExecution++指定了不合法的值(不存在的类,不存在的bean引用,或者代理类没有实现监听器接口),在流程启动(或该流程定义的第一个有效事件分发给这个监听器)时,会抛出异常。请确保引用的类在classpath中,并且保证表达式能够解析为有效的实例。 - - -[[eventDispatcherCustomEvents]] - -==== 通过API分发事件 - - -可以通过API提供事件分发机制,向任何在引擎中注册的监听器分发自定义事件。建议(但不强制)只分发++CUSTOM++类型的++FlowableEvents++。使用++RuntimeService++分发事件: - -[source,java,linenums] ----- - -/** - * 将给定事件分发给所有注册监听器。 - * @param event 要分发的事件。 - * - * @throws FlowableException 当分发事件发生异常,或者{@link FlowableEventDispatcher}被禁用。 - * @throws FlowableIllegalArgumentException 当给定事件不可分发 - */ - void dispatchEvent(FlowableEvent event); ----- - -[[eventDispatcherEventTypes]] - - -==== 支持的事件类型 - -下表列出引擎中的所有事件类型。每种类型对应++org.flowable.engine.common.api.delegate.event.FlowableEventType++中的一个枚举值。 - - -[[eventTypes]] -.Supported events -[options="header"] -|=============== -|事件名称|说明|事件类 -|ENGINE_CREATED|本监听器所属的流程引擎已经创建,并可以响应API调用。|+org.flowable...FlowableEvent+ -|ENGINE_CLOSED|本监听器所属的流程引擎已经关闭,不能再对该引擎进行API调用。|+org.flowable...FlowableEvent+ -|ENTITY_CREATED|新的实体已经创建。该实体包含在本事件里。|+org.flowable...FlowableEntityEvent+ -|ENTITY_INITIALIZED|新的实体已经创建并完全初始化。如果任何子实体作为该实体的一部分被创建,本事件会在子实体创建/初始化后触发,与 +$$ENTITY_CREATE$$+ 事件相反。|+org.flowable...FlowableEntityEvent+ -|ENTITY_UPDATED|实体已经更新。该实体包含在本事件里。|+org.flowable...FlowableEntityEvent+ -|ENTITY_DELETED|实体已经删除。该实体包含在本事件里。|+org.flowable...FlowableEntityEvent+ -|ENTITY_SUSPENDED|实体已经暂停。该实体包含在本事件里。ProcessDefinitions(流程定义), ProcessInstances(流程实例)与Tasks(任务)会分发本事件。|+org.flowable...FlowableEntityEvent+ -|ENTITY_ACTIVATED|实体已经激活。该实体包含在本事件里。ProcessDefinitions, ProcessInstances与Tasks会分发本事件。|+org.flowable...FlowableEntityEvent+ -|JOB_EXECUTION_SUCCESS|作业已经成功执行。该作业包含在本事件里。|+org.flowable...FlowableEntityEvent+ -|JOB_EXECUTION_FAILURE|作业执行失败。该作业与异常包含在本事件里。|+org.flowable...FlowableEntityEvent+ 及 +org.flowable...FlowableExceptionEvent+ -|JOB_RETRIES_DECREMENTED|作业重试次数已经由于执行失败而减少。该作业包含在本事件里。|+org.flowable...FlowableEntityEvent+ -|TIMER_SCHEDULED|已创建一个定时作业,并预计在未来时间点执行。|+org.flowable...FlowableEntityEvent+ -|TIMER_FIRED|定时器已经触发。|+org.flowable...FlowableEntityEvent+ -|JOB_CANCELED|作业已经取消。该作业包含在本事件里。作业会由于API调用取消,任务完成导致关联的边界定时器取消,也会由于新流程定义的部署而取消。|+org.flowable...FlowableEntityEvent+ -|ACTIVITY_STARTED|节点开始执行|+org.flowable...FlowableActivityEvent+ -|ACTIVITY_COMPLETED|节点成功完成|+org.flowable...FlowableActivityEvent+ -|ACTIVITY_CANCELLED|节点将要取消。节点的取消有三个原因(MessageEventSubscriptionEntity, SignalEventSubscriptionEntity, TimerEntity)。|+org.flowable...FlowableActivityCancelledEvent+ -|ACTIVITY_SIGNALED|节点收到了一个信号|+org.flowable...FlowableSignalEvent+ -|ACTIVITY_MESSAGE_RECEIVED|节点收到了一个消息。事件在节点接收消息前分发。节点接收消息后,会为该节点分发 +$$ACTIVITY_SIGNAL$$+ 或 +$$ACTIVITY_STARTED$$+ 事件,取决于其类型(边界事件,或子流程启动事件)。|+org.flowable...FlowableMessageEvent+ -|ACTIVITY_MESSAGE_WAITING|一个节点已经创建了一个消息事件订阅,并正在等待接收消息。|+org.flowable...FlowableMessageEvent+ -|ACTIVITY_MESSAGE_CANCELLED|一个节点已经取消了一个消息事件订阅,因此接收这个消息不会再触发该节点。|+org.flowable...FlowableMessageEvent+ -|ACTIVITY_ERROR_RECEIVED|节点收到了错误事件。在节点实际处理错误前分发。该事件的++activityId++为处理错误的节点。如果错误成功传递,后续会为节点发送 +$$ACTIVITY_SIGNALLED$$+ 或 +$$ACTIVITY_COMPLETE$$+ 消息。|+org.flowable...FlowableErrorEvent+ -|UNCAUGHT_BPMN_ERROR|抛出了未捕获的BPMN错误。流程没有该错误的处理器。该事件的++activityId++为空。|+org.flowable...FlowableErrorEvent+ -|ACTIVITY_COMPENSATE|节点将要被补偿(compensate)。该事件包含将要执行补偿的节点id。|+org.flowable...FlowableActivityEvent+ -|MULTI_INSTANCE_ACTIVITY_STARTED|多实例节点开始执行|+org.flowable...FlowableMultiInstanceActivityEvent+ -|MULTI_INSTANCE_ACTIVITY_COMPLETED|多实例节点成功完成|+org.flowable...FlowableMultiInstanceActivityEvent+ -|MULTI_INSTANCE_ACTIVITY_CANCELLED|多实例节点将要取消。多实例节点的取消有三个原因(MessageEventSubscriptionEntity, SignalEventSubscriptionEntity, TimerEntity)。|+org.flowable...FlowableMultiInstanceActivityCancelledEvent+ -|VARIABLE_CREATED|流程变量已经创建。本事件包含变量名、取值,及关联的执行和任务(若有)。|+org.flowable...FlowableVariableEvent+ -|VARIABLE_UPDATED|变量已经更新。本事件包含变量名、取值,及关联的执行和任务(若有)。|+org.flowable...FlowableVariableEvent+ -|VARIABLE_DELETED|变量已经删除。本事件包含变量名、最后取值,及关联的执行和任务(若有)。|+org.flowable...FlowableVariableEvent+ -|TASK_ASSIGNED|任务已经分派给了用户。该任务包含在本事件里。|+org.flowable...FlowableEntityEvent+ -|TASK_CREATED|任务已经创建。本事件在 +$$ENTITY_CREATE$$+ 事件之后分发。若该任务是流程的一部分,本事件会在任务监听器执行前触发。|+org.flowable...FlowableEntityEvent+ -|TASK_COMPLETED|任务已经完成。本事件在 +$$ENTITY_DELETE$$+ 事件前分发。若该任务是流程的一部分,本事件会在流程前进之前触发,并且会跟随一个 +$$ACTIVITY_COMPLETE$$+ 事件,指向代表该任务的节点。|+org.flowable...FlowableEntityEvent+ -|PROCESS_CREATED|流程实例已经创建。已经设置所有的基础参数,但还未设置变量。|+org.flowable...FlowableEntityEvent+ -|PROCESS_STARTED|流程实例已经启动。在启动之前创建的流程时分发。PROCESS_STARTED事件在相关的ENTITY_INITIALIZED事件,以及设置变量之后分发。|+org.flowable...FlowableEntityEvent+ -|PROCESS_COMPLETED|流程实例已经完成。在最后一个节点的 +$$ACTIVITY_COMPLETED $$+ 事件后分发。当流程实例没有任何路径可以继续时,流程结束。|+org.flowable...FlowableEntityEvent+ -|PROCESS_COMPLETED_WITH_TERMINATE_END_EVENT| 流程已经到达终止结束事件(terminate end event)并结束。|+org.flowable...FlowableProcessTerminatedEvent+ -|PROCESS_CANCELLED|流程已经被取消。在流程实例从运行时中删除前分发。流程实例由API调用++RuntimeService.deleteProcessInstance++取消。|+org.flowable...FlowableCancelledEvent+ -|MEMBERSHIP_CREATED|用户已经加入组。本事件包含了相关的用户和组的id。|+org.flowable...FlowableMembershipEvent+ -|MEMBERSHIP_DELETED|用户已经从组中移出。本事件包含了相关的用户和组的id。|+org.flowable...FlowableMembershipEvent+ -|MEMBERSHIPS_DELETED|组的所有用户将被移出。本事件在用户移出前抛出,因此关联关系仍然可以访问。因为性能原因,不会再为每个被移出的用户抛出 +$$MEMBERSHIP_DELETED$$+ 事件。|+org.flowable...FlowableMembershipEvent+ - -|=============== - - -引擎中所有的 +$$ENTITY_\*$$+ 事件都与实体关联。下表列出每个实体分发的实体事件: - -* *+$$ENTITY_CREATED, ENTITY_INITIALIZED, ENTITY_DELETED$$+*: 附件(Attachment),备注(Comment),部署(Deployment),执行(Execution),组(Group),身份关联(IdentityLink),作业(Job),模型(Model),流程定义(ProcessDefinition),流程实例(ProcessInstance),任务(Task),用户(User)。 -* *+$$ENTITY_UPDATED$$+*: 附件,部署,执行,组,身份关联,作业,模型,流程定义,流程实例,任务,用户。 -* *+$$ENTITY_SUSPENDED, ENTITY_ACTIVATED$$+*: 流程定义,流程实例/执行,任务。 - - -[[eventDispatcherRemarks]] - - -==== 附加信息 - - -**监听器只会响应其所在引擎分发的事件。**因此如果在同一个数据库上运行不同的引擎,则只有该监听器注册的引擎生成的事件,才会分发给该监听器。其他引擎生成的事件不会分发给这个监听器,而不论这些引擎是否运行在同一个JVM下。 - -某些事件类型(与实体相关)暴露了目标实体。按照事件类型的不同,有些实体不能被更新(如实体删除事件中的实体)。如果可能的话,请使用事件暴露的++EngineServices++来安全地操作引擎。即使这样,更新、操作事件中暴露的实体仍然需要小心。 - -历史不会分发实体事件,因为它们都有对应的运行时实体分发事件。 - diff --git a/docs/userguide/src/zh_CN/bpmn/ch04-API.adoc b/docs/userguide/src/zh_CN/bpmn/ch04-API.adoc deleted file mode 100755 index 250773f4ddd..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch04-API.adoc +++ /dev/null @@ -1,450 +0,0 @@ -[[chapterApi]] - -== Flowable API - -[[apiEngine]] - - -=== 流程引擎API与服务 - -引擎API是与Flowable交互的最常用手段。总入口点是++ProcessEngine++。像<>章节中介绍的一样,ProcessEngine可以使用多种方式创建。使用ProcessEngine,可以获得各种提供工作流/BPM方法的服务。ProcessEngine与服务对象都是线程安全的,因此可以在服务器中保存并共用同一个引用。 - - -image::images/api.services.png[align="center"] - -[source,java,linenums] ----- -ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); - -RuntimeService runtimeService = processEngine.getRuntimeService(); -RepositoryService repositoryService = processEngine.getRepositoryService(); -TaskService taskService = processEngine.getTaskService(); -ManagementService managementService = processEngine.getManagementService(); -IdentityService identityService = processEngine.getIdentityService(); -HistoryService historyService = processEngine.getHistoryService(); -FormService formService = processEngine.getFormService(); -DynamicBpmnService dynamicBpmnService = processEngine.getDynamicBpmnService(); ----- - -在++ProcessEngines.getDefaultProcessEngine()++第一次被调用时,将初始化并构建流程引擎,之后的重复调用都会返回同一个流程引擎。可以通过++ProcessEngines.init()++创建流程引擎,并由++ProcessEngines.destroy()++关闭流程引擎。 - -ProcessEngines会扫描++flowable.cfg.xml++与++flowable-context.xml++文件。对于++flowable.cfg.xml++文件,流程引擎会以标准Flowable方式构建引擎:++ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(inputStream).buildProcessEngine()++。对于++flowable-context.xml++文件,流程引擎会以Spring的方式构建:首先构建Spring应用上下文,然后从该上下文中获取流程引擎。 - -所有的服务都是无状态的。这意味着你可以很容易的在集群环境的多个节点上运行Flowable,使用同一个数据库,而不用担心上一次调用实际在哪台机器上执行。不论在哪个节点执行,对任何服务的任何调用都是幂等(idempotent)的。 - -**RepositoryService**很可能是使用Flowable引擎要用的第一个服务。这个服务提供了管理与控制++部署(deployments)++与++流程定义(process definitions)++的操作。在这里简单说明一下,流程定义是BPMN 2.0流程对应的Java对象,体现流程中每一步的结构与行为。++部署++是Flowable引擎中的包装单元,一个部署中可以包含多个BPMN 2.0 XML文件及其他资源。开发者可以决定在一个部署中包含的内容,可以是单个流程的BPMN 2.0 XML文件,也可以包含多个流程及其相关资源(如'hr-processes'部署可以包含所有与人力资源流程相关的的东西)。++RepositoryService++可用于++部署++这样的包。部署意味着将它上传至引擎,引擎将在储存至数据库之前检查与分析所有的流程。在部署操作后,可以在系统中使用这个部署包,部署包中的所有流程都可以启动。 - -此外,这个服务还可以: - -* 查询引擎现有的部署与流程定义。 -* 暂停或激活部署中的某些流程,或整个部署。暂停意味着不能再对它进行操作,激活刚好相反,重新使它可以操作。 -* 获取各种资源,比如部署中保存的文件,或者引擎自动生成的流程图。 -* 获取POJO版本的流程定义。它可以用Java而不是XML的方式查看流程。 - -与提供静态信息(也就是不会改变,至少不会经常改变的信息)的++RepositoryService++相反,**RuntimeService**用于启动流程定义的新流程实例。前面介绍过,++流程定义++中定义了流程中不同步骤的结构与行为。流程实例则是流程定义的实际执行过程。同一时刻,一个流程定义通常有多个运行中的实例。++RuntimeService++也用于读取与存储++流程变量++。流程变量是流程实例中的数据,可以在流程的许多地方使用(例如排他网关经常使用流程变量判断流程下一步要走的路径)。++RuntimeService++还可以用于查询流程实例与执行(Execution)。执行也就是BPMN 2.0中 +$$'token'$$+ 的概念。通常执行是指向流程实例当前位置的指针。最后,还可以在流程实例等待外部触发时使用++RuntimeService++,使流程可以继续运行。流程有许多++等待状态(wait states)++,++RuntimeService++服务提供了许多操作用于“通知”流程实例:已经接收到外部触发,流程实例可以继续运行。 - - -对于像Flowable这样的BPM引擎来说,核心是需要人类用户操作的任务。所有任务相关的东西都组织在**TaskService**中,例如: - -* 查询分派给用户或组的任务 -* 创建__独立运行(standalone)__任务。这是一种没有关联到流程实例的任务。 -* 决定任务的执行用户(assignee),或者将用户通过某种方式与任务关联。 -* 认领(claim)与完成(complete)任务。认领是指某人决定成为任务的执行用户,也即他将会完成这个任务。完成任务是指“做这个任务要求的工作”,通常是填写某个表单。 - -**IdentityService**很简单。它用于管理(创建,更新,删除,查询……)组与用户。请注意,Flowable实际上在运行时并不做任何用户检查。例如任务可以分派给任何用户,而引擎并不会验证系统中是否存在该用户。这是因为Flowable有时要与LDAP、Active Directory等服务结合使用。 - -**FormService**是可选服务。也就是说Flowable没有它也能很好地运行,而不必牺牲任何功能。这个服务引入了__开始表单(start form)__与__任务表单(task form)__的概念。 __开始表单__是在流程实例启动前显示的表单,而__任务表单__是用户完成任务时显示的表单。Flowable可以在BPMN 2.0流程定义中定义这些表单。表单服务通过简单的方式暴露这些数据。再次重申,表单不一定要嵌入流程定义,因此这个服务是可选的。 - -**HistoryService**暴露Flowable引擎收集的所有历史数据。当执行流程时,引擎会保存许多数据(可配置),例如流程实例启动时间、谁在执行哪个任务、完成任务花费的事件、每个流程实例的执行路径,等等。这个服务主要提供查询这些数据的能力。 - -**ManagementService**通常在用Flowable编写用户应用时不需要使用。它可以读取数据库表与表原始数据的信息,也提供了对作业(job)的查询与管理操作。Flowable中很多地方都使用作业,例如定时器(timer),异步操作(asynchronous continuation),延时暂停/激活(delayed suspension/activation)等等。后续会详细介绍这些内容。 - - -**DynamicBpmnService**可用于修改流程定义中的部分内容,而不需要重新部署它。例如可以修改流程定义中一个用户任务的办理人设置,或者修改一个服务任务中的类名。 - -参考link:$$http://www.flowable.org/docs/javadocs/index.html$$[javadocs]了解服务操作与引擎API的更多信息。 - -[[_exception_strategy]] -=== 异常策略 - -Flowable的异常基类是++org.flowable.engine.FlowableException++,这是一个非受检异常(unchecked exception)。在任何API操作时都可能会抛出这个异常,link:$$http://www.flowable.org/docs/javadocs/index.html$$[javadoc]提供了每个方法可能抛出的异常。例如,从++TaskService++中摘录: - -[source,java,linenums] ----- -/** - * 当任务成功执行时调用。 - * @param taskId 需要完成的任务id,不能为null。 - * @throws FlowableObjectNotFoundException 若给定id找不到任务。 - */ - void complete(String taskId); ----- - -在上例中,如果所用的id找不到任务,就会抛出异常。并且,由于javadoc中**明确要求taskId不能为null,因此如果传递了++null++值,会抛出++FlowableIllegalArgumentException++异常**。 - -尽管我们想避免过大的异常层次结构,但在特定情况下仍然会抛出下述异常子类。所有流程执行与API调用中发生的错误,如果不符合下面列出的异常,会统一抛出++FlowableExceptions++。 - -* ++FlowableWrongDbException++: 当Flowable引擎检测到数据库表结构版本与引擎版本不匹配时抛出。 -* ++FlowableOptimisticLockingException++: 当对同一数据实体的并发访问导致数据存储发生乐观锁异常时抛出。 -* ++FlowableClassLoadingException++: 当需要载入的类(如JavaDelegate, TaskListener, ...)无法找到,或载入发生错误时抛出。 -* ++FlowableObjectNotFoundException++: 当请求或要操作的对象不存在时抛出。 -* ++FlowableIllegalArgumentException++: 当调用Flowable API时使用了不合法的参数时抛出。可能是引擎配置中的不合法值,或者是API调用传递的不合法参数,也可能是流程定义中的不合法值。 -* ++FlowableTaskAlreadyClaimedException++: 当对已被认领的任务调用++taskService.claim(...)++时抛出。 - - -[[queryAPI]] - - -=== 查询API - -从引擎中查询数据有两种方式:查询API与原生(native)查询。查询API可以使用链式API,通过编程方式进行类型安全的查询。你可以在查询中增加各种条件(所有条件都用做AND逻辑),也可以明确指定排序方式。下面是示例代码: - -[source,java,linenums] ----- -List tasks = taskService.createTaskQuery() - .taskAssignee("kermit") - .processVariableValueEquals("orderId", "0815") - .orderByDueDate().asc() - .list(); ----- - -有时需要更复杂的查询,例如使用OR操作符查询,或者使用查询API不能满足查询条件要求。我们为这种需求提供了可以自己写SQL查询的原生查询。返回类型由使用的查询对象决定,数据会映射到正确的对象中(Task、ProcessInstance、Execution,等等)。查询在数据库中进行,因此需要使用数据库中定义的表名与列名。这需要了解内部数据结构,因此建议小心使用原生查询。数据库表名可以通过API读取,这样可以将依赖关系减到最小。 - -[source,java,linenums] ----- -List tasks = taskService.createNativeTaskQuery() - .sql("SELECT * FROM " + managementService.getTableName(Task.class) + - " T WHERE T.NAME_ = #{taskName}") - .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_ = T1.ID_") - .count(); ----- - -[[apiVariables]] - -=== 变量 - -流程实例按步骤执行时,需要使用一些数据。在Flowable中,这些数据称作__变量(variable)__,并会存储在数据库中。变量可以用在表达式中(例如在排他网关中用于选择正确的出口路径),也可以在Java服务任务(service task)中用于调用外部服务(例如为服务调用提供输入或结果存储),等等。 - -流程实例可以持有变量(称作__流程变量 process variables__);用户任务以及__执行(executions)__——流程当前活动节点的指针——也可以持有变量。流程实例可以持有任意数量的变量,每个变量存储为__ACT_RU_VARIABLE__数据库表的一行。 - - -所有的__startProcessInstanceXXX__方法都有一个可选参数,用于在流程实例创建及启动时设置变量。例如,在__RuntimeService__中: - -[source,java,linenums] ----- -ProcessInstance startProcessInstanceByKey(String processDefinitionKey, Map variables); ----- - -也可以在流程执行中加入变量。例如,(_RuntimeService_): - -[source,java,linenums] ----- -void setVariable(String executionId, String variableName, Object value); -void setVariableLocal(String executionId, String variableName, Object value); -void setVariables(String executionId, Map variables); -void setVariablesLocal(String executionId, Map variables); ----- - -请注意可以为给定执行(请记住,流程实例由一颗执行的树(tree of executions)组成)设置__局部(local)__变量。局部变量将只在该执行中可见,对执行树的上层则不可见。这可以用于 数据不应该暴露给流程实例的其他执行,或者变量在流程实例的不同路径中有不同的值(例如使用并行路径时)的情况。 - -可以用下列方法读取变量。请注意__TaskService__中有类似的方法。这意味着任务与执行一样,可以持有局部变量,其生存期为任务持续的时间。 - - -[source,java,linenums] ----- -Map getVariables(String executionId); -Map getVariablesLocal(String executionId); -Map getVariables(String executionId, Collection variableNames); -Map getVariablesLocal(String executionId, Collection variableNames); -Object getVariable(String executionId, String variableName); - T getVariable(String executionId, String variableName, Class variableClass); ----- - -变量通常用于<>、<>、执行(execution)、任务监听器(tasklisteners)、脚本(scripts)等等。在这些结构中,提供了当前的__execution__或__task__对象,可用于变量的设置、读取。简单示例如下: - -[source,java,linenums] ----- -execution.getVariables(); -execution.getVariables(Collection variableNames); -execution.getVariable(String variableName); - -execution.setVariables(Map variables); -execution.setVariable(String variableName, Object value); ----- - -请注意也可以使用上例中方法的__局部变量__版本。 - -由于历史(与向后兼容)原因,当调用上述任何方法时,引擎会从数据库中取出**所有**变量。也就是说,如果你有10个变量,使用__getVariable("myVariable")__获取其中的一个,实际上其他9个变量也会从数据库取出并缓存。这并不坏,因为后续的调用可以不必再读取数据库。比如,如果流程定义包含三个连续的服务任务(因此它们在同一个数据库事务里),在第一个服务任务里通过一次调用获取全部变量,也许比在每个服务任务里分别获取需要的变量要好。请注意对读取与设置变量**都是这样**。 - -当然,如果使用大量变量,或者你希望精细控制数据库查询与流量,上述的做法就不合适了。我们引入了可以更精细控制的方法。这个方法有一个可选的参数,告诉引擎是否需要读取并缓存所有变量: - -[source,java,linenums] ----- -Map getVariables(Collection variableNames, boolean fetchAllVariables); -Object getVariable(String variableName, boolean fetchAllVariables); -void setVariable(String variableName, Object value, boolean fetchAllVariables); ----- - -当__fetchAllVariables__参数为__true__时,行为与上面描述的完全一样:读取或设置一个变量时,所有的变量都将被读取并缓存。 - -而当参数值为__false__时,会使用明确的查询,其他变量不会被读取或缓存。只有指定的变量的值会被缓存并用于后续使用。 - - -[[apiTransientVariables]] - -=== 瞬时变量 - -瞬时变量(Transient variable)类似普通变量,只是不会被持久化。通常来说,瞬时变量用于高级使用场景。如果不明确,还是使用普通流程变量为好。 - -瞬时变量具有下列特性: - -* 瞬时变量完全不存储历史。 -* 与__普通__变量类似,设置瞬时变量时会存入__最上层父__中。这意味着在一个执行中设置一个变量时,瞬时变量实际上会存储在流程实例执行中。与普通变量类似,可以使用__局部(local)__的对应方法,将变量设置为某个执行或任务的局部变量。 -* 瞬时变量只能在下一个“等待状态”之前访问。之后该变量即消失。等待状态意味着流程实例会持久化至数据存储中。请注意在这个定义中,__异步__活动也是“等待状态”! -* 只能使用__setTransientVariable(name, value)__设置瞬时变量,但是调用__getVariable(name)__也会返回瞬时变量(也有__getTransientVariable(name)__方法,它只会返回瞬时变量)。这是为了简化表达式的撰写,并保证已有逻辑可以使用这两种类型的变量。 -* 瞬时变量__屏蔽(shadow)__同名的持久化变量。也就是说当一个流程实例中设置了同名的持久化变量与瞬时变量时,__getVariable("someVariable")__会返回瞬时变量的值。 - -在大多数可以使用普通变量的地方,都可以获取、设置瞬时变量: - -* 在__JavaDelegate__实现中的__DelegateExecution__内 -* 在__ExecutionListener__实现中的__DelegateExecution__内,以及在__TaskListener__实现中的__DelegateTask__内 -* 通过__execution__对象在脚本任务内 -* 通过RuntimeService启动流程实例时 -* 完成任务时 -* 调用__runtimeService.trigger__方法时 - - -瞬时变量相关的方法遵循普通流程变量方法的命名约定: - -[source,java,linenums] ----- -void setTransientVariable(String variableName, Object variableValue); -void setTransientVariableLocal(String variableName, Object variableValue); -void setTransientVariables(Map transientVariables); -void setTransientVariablesLocal(Map transientVariables); - -Object getTransientVariable(String variableName); -Object getTransientVariableLocal(String variableName); - -Map getTransientVariables(); -Map getTransientVariablesLocal(); - -void removeTransientVariable(String variableName); -void removeTransientVariableLocal(String variableName); ----- - -下面的BPMN流程图展示了一个典型例子: - -image::images/api.transient.variable.example.png[align="center"] - -假设'Fetch Data(获取数据)'服务任务调用某个远程服务(例如使用REST)。也假设需要其需要一些配置参数,并需要在启动流程实例时提供。同时,这些配置参数对于历史审计并不重要,因此我们将它们作为瞬时变量传递: - -[source,java,linenums] ----- -ProcessInstance processInstance = runtimeService.createProcessInstanceBuilder() - .processDefinitionKey("someKey") - .transientVariable("configParam01", "A") - .transientVariable("configParam02", "B") - .transientVariable("configParam03", "C") - .start(); ----- - -请注意在到达用户任务并持久化之前,都可以使用这些瞬时变量。例如,在'Additional Work(额外工作)'用户任务中它们就不再可用。也请注意如果'Fetch Data'是异步的,则瞬时变量在该步骤之后也不再可用。 - - -'Fetch Data'(的简化版本)可以像是: - -[source,java,linenums] ----- -public static class FetchDataServiceTask implements JavaDelegate { - public void execute(DelegateExecution execution) { - String configParam01 = (String) execution.getVariable(configParam01); - // ... - - RestResponse restResponse = executeRestCall(); - execution.setTransientVariable("response", restResponse.getBody()); - execution.setTransientVariable("status", restResponse.getStatus()); - } -} ----- - -'Process Data(处理数据)'可以获取response瞬时变量,解析并将其相关数据存储在实际流程变量中,因为之后还需要使用它们。 - -离开排他网关的顺序流上的条件表达式,不关注使用的是持久化还是瞬时变量(在这个例子中__status__是瞬时变量): - -[source,xml,linenums] ----- -${status == 200} ----- - -[[apiExpressions]] - - -=== 表达式 - -Flowable使用UEL进行表达式解析。UEL代表__Unified Expression Language__,是EE6规范的一部分(查看link:$$http://docs.oracle.com/javaee/6/tutorial/doc/gjddd.html$$[EE6规范]了解更多信息)。 - -表达式可以用于<>、<>、<> 与 <>等。尽管有值表达式与方法表达式这两种不同的表达式,Flowable通过抽象,使它们都可以在需要++表达式++的地方使用。 - -* **值表达式 Value expression**: 解析为一个值。默认情况下,所有流程变量都可以使用。(若使用Spring)所有的Spring bean也可以用在表达式里。例如: - ----- -${myVar} -${myBean.myProperty} ----- - -* **方法表达式 Method expression**: 调用一个方法,可以带或不带参数。**当调用不带参数的方法时,要确保在方法名后添加空括号(以避免与值表达式混淆)。**传递的参数可以是字面值(literal value),也可以是表达式,它们会被自动解析。例如: - ----- -${printer.print()} -${myBean.addNewOrder('orderName')} -${myBean.doSomething(myVar, execution)} ----- - -请注意,表达式支持解析(及比较)原始类型(primitive)、bean、list、array与map。 -Note that these expressions support resolving primitives (including comparing them), beans, lists, arrays and maps. - -除了所有流程变量外,还有一些默认对象可在表达式中使用: - -* ++execution++: +DelegateExecution++,持有正在运行的执行的额外信息。 -* ++task++: ++DelegateTask++持有当前任务的额外信息。**请注意:只在任务监听器的表达式中可用。** -* ++authenticatedUserId++: 当前已验证的用户id。如果没有已验证的用户,该变量不可用。 - -更多实际使用例子,请查看<>、<>、<>、<>或者<>等章节。 - - -[[apiUnitTesting]] - -=== 单元测试 - -业务流程是软件项目的必要组成部分,也需要使用测试一般应用逻辑的方法——单元测试——测试它们。Flowable是嵌入式的Java引擎,因此为业务流程编写单元测试就同编写一般的单元测试一样简单。 - -Flowable支持JUnit 3及4的单元测试风格。按照JUnit 3的风格,必须扩展(extended)++org.flowable.engine.test.FlowableTestCase++。它通过保护(protected)成员变量提供对ProcessEngine与服务的访问。在测试的++setup()++中,processEngine会默认使用classpath中的++flowable.cfg.xml++资源初始化。如果要指定不同的配置文件,请覆盖__getConfigurationResource()__方法。当使用相同的配置资源时,流程引擎会静态缓存,用于多个单元测试。 - -通过扩展++FlowableTestCase++,可以使用++org.flowable.engine.test.Deployment++注解测试方法。在测试运行前,会部署与测试类在同一个包下的格式为++testClassName.testMethod.bpmn20.xml++的资源文件。在测试结束时,会删除这个部署,包括所有相关的流程实例、任务,等等。也可以使用++Deployment++注解显式指定资源位置。查看该类以获得更多信息。 - -综上所述,JUnit 3风格的测试看起来类似: - -[source,java,linenums] ----- -public class MyBusinessProcessTest extends FlowableTestCase { - - @Deployment - public void testSimpleProcess() { - runtimeService.startProcessInstanceByKey("simpleProcess"); - - Task task = taskService.createTaskQuery().singleResult(); - assertEquals("My Task", task.getName()); - - taskService.complete(task.getId()); - assertEquals(0, runtimeService.createProcessInstanceQuery().count()); - } -} ----- - -要使用JUnit 4的风格书写单元测试并达成同样的功能,必须使用++org.flowable.engine.test.FlowableRule++ Rule。这样能够通过它的getter获得流程引擎与服务。对于++FlowableTestCase++(上例),包含++@Rule++就可以使用++org.flowable.engine.test.Deployment++注解(参见上例解释其用途及配置),并且会自动在classpath中寻找默认配置文件。当使用相同的配置资源时,流程引擎会静态缓存,以用于多个单元测试。 - -下面的代码片段展示了JUnit 4风格的测试与++FlowableRule++的用法。 - -[source,java,linenums] ----- -public class MyBusinessProcessTest { - - @Rule - public FlowableRule flowableRule = new FlowableRule(); - - @Test - @Deployment - public void ruleUsageExample() { - RuntimeService runtimeService = flowableRule.getRuntimeService(); - runtimeService.startProcessInstanceByKey("ruleUsage"); - - TaskService taskService = flowableRule.getTaskService(); - Task task = taskService.createTaskQuery().singleResult(); - assertEquals("My Task", task.getName()); - - taskService.complete(task.getId()); - assertEquals(0, runtimeService.createProcessInstanceQuery().count()); - } -} ----- - -[[apiDebuggingUnitTest]] - - -=== 调试单元测试 - -当使用H2内存数据库进行单元测试时,下面的方法可以让你在调试过程中方便地检查Flowable数据库中的数据。截图来自Eclipse,但其他IDE方式相似。 - -假设我们的单元测试的某处放置了__断点(breakpoint)__(在Eclipse里可以通过在代码左侧条上双击实现): - -image::images/api.test.debug.breakpoint.png[align="center"] - -如果我们在__debug__模式(在测试类中右键,选择“Run as”,然后选择“JUnit test”)下运行单元测试,测试进程会在断点处暂停,这样我们就可以在右上窗口中查看测试中的变量。 - -image::images/api.test.debug.view.png[align="center"] - -要检查Flowable的数据,打开__Display__窗口(如果没有找到这个窗口,打开 Window->Show View->Other,然后选择__Display__),并键入(可以使用代码补全)++org.h2.tools.Server.createWebServer("-web").start()++ - -image::images/api.test.debug.start.h2.server.png[align="center"] - -选中刚键入的行并右键点击。然后选择'Display'(或者用快捷键执行) - -image::images/api.test.debug.start.h2.server.2.png[align="center"] - -现在打开浏览器并访问link:$$http://localhost:8082$$[http://localhost:8082],填入内存数据库的JDBC URL(默认为++jdbc:h2:mem:flowable++),然后点击connect按钮。 - -image::images/api.test.debug.h2.login.png[align="center"] - -这样就可以看到Flowable的数据。便于理解单元测试执行流程的方式。 - -image::images/api.test.debug.h2.tables.png[align="center"] - - - -[[apiProcessEngineInWebApp]] - - -=== Web应用中的流程引擎 - -++ProcessEngine++是线程安全的类,可以很容易地在多个线程间共享。在web应用中,这意味着可以在容器启动时创建引擎,并在容器关闭时关闭引擎。 - -下面的代码片段展示了如何在Servlet环境中,通过++ServletContextListener++初始化与销毁流程引擎。 - - -[source,java,linenums] ----- -public class ProcessEnginesServletContextListener implements ServletContextListener { - - public void contextInitialized(ServletContextEvent servletContextEvent) { - ProcessEngines.init(); - } - - public void contextDestroyed(ServletContextEvent servletContextEvent) { - ProcessEngines.destroy(); - } - -} ----- - -++contextInitialized++方法会调用++ProcessEngines.init()++。它会在classpath中查找++flowable.cfg.xml++资源文件,并为每个文件分别创建++ProcessEngine++(如果多个JAR都包含配置文件)。如果在classpath中有多个这样的资源文件,请确保它们使用不同的引擎名。需要使用流程引擎时,可以这样获取: - -[source,java,linenums] ----- -ProcessEngines.getDefaultProcessEngine() ----- - -或者 - -[source,java,linenums] ----- -ProcessEngines.getProcessEngine("myName"); ----- - -当然,就像<>章节中介绍的,还可以使用各种不同的方式创建流程引擎。 - -context-listener的++contextDestroyed++方法会调用++ProcessEngines.destroy()++。它会妥善关闭所有已初始化的流程引擎。 diff --git a/docs/userguide/src/zh_CN/bpmn/ch05-Spring.adoc b/docs/userguide/src/zh_CN/bpmn/ch05-Spring.adoc deleted file mode 100755 index d1a0e429082..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch05-Spring.adoc +++ /dev/null @@ -1,328 +0,0 @@ -[[springintegration]] - -== 集成Spring - -尽管完全可以脱离Spring使用Flowable,我们仍提供了很多非常好的集成特性,并将在这一章节介绍。 - -=== ProcessEngineFactoryBean - -可以将++ProcessEngine++配置为普通的Spring bean。入口是++org.flowable.spring.ProcessEngineFactoryBean++类。这个bean处理流程引擎配置,并创建流程引擎。所以在Spring中创建与设置的参数与<>章节中介绍的相同。Spring集成所用的配置与引擎bean为: - -[source,xml,linenums] ----- - - ... - - - - - - ----- - -请注意++processEngineConfiguration++ bean现在使用++org.flowable.spring.SpringProcessEngineConfiguration++类。 - -[[_transactions]] -=== 事务 - -我们会逐步说明(Flowable)发行版里,Spring示例中的++SpringTransactionIntegrationTest++。下面是我们示例中使用的Spring配置文件(SpringTransactionIntegrationTest-context.xml)。下面的小节包含了dataSource(数据源),transactionManager(事务管理器),processEngine(流程引擎)以及Flowable引擎服务。 - -将DataSource传递给++SpringProcessEngineConfiguration++(使用“dataSource”参数)时,Flowable会在内部使用++org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy++对得到的数据源进行包装(wrap)。这是为了保证从数据源获取的SQL连接与Spring的事务可以协同工作。这样也就不需要在Spring配置中对数据源进行代理(proxy)。但仍然可以将代理++TransactionAwareDataSourceProxy++传递给++SpringProcessEngineConfiguration++——在这种情况下,不会再进行包装。 - -**请确保如果自行在Spring配置中声明了++TransactionAwareDataSourceProxy++,则不要将它用在已经配置Spring事务的资源上(例如DataSourceTransactionManager与JPATransactionManager。它们需要未经代理的数据源)。** - -[source,xml,linenums] ----- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -... ----- - -这个Spring配置文件也包含了在这个示例中要用到的bean与配置: - -[source,xml,linenums] ----- - - ... - - - - - - - - - ----- - -可以使用任何Spring支持的方式创建应用上下文(application context)。在这个例子中,可以使用classpath中的XML资源配置来创建Spring应用上下文: - - -[source,java,linenums] ----- -ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext( - "org/flowable/examples/spring/SpringTransactionIntegrationTest-context.xml"); ----- - -或者在单元测试中: - -[source,java,linenums] ----- -@ContextConfiguration( - "classpath:org/flowable/spring/test/transaction/SpringTransactionIntegrationTest-context.xml") ----- - -然后就可以获取服务bean,并调用它们的方法。ProcessEngineFactoryBean会为服务加上额外的拦截器(interceptor),并为Flowable服务方法设置Propagation.REQUIRED事务级别。这样,我们就可以使用repositoryService部署流程: - -[source,java,linenums] ----- -RepositoryService repositoryService = - (RepositoryService) applicationContext.getBean("repositoryService"); -String deploymentId = repositoryService - .createDeployment() - .addClasspathResource("org/flowable/spring/test/hello.bpmn20.xml") - .deploy() - .getId(); - ----- - -还有另一种方法也可以使用。如果userBean.hello()方法在Spring事务中,Flowable服务方法调用就会加入这个事务。 - -[source,java,linenums] ----- -UserBean userBean = (UserBean) applicationContext.getBean("userBean"); -userBean.hello(); ----- - -UserBean看起来像下面这样。请记着在上面的Spring bean配置中,我们已经将repositoryService注入了userBean。 - -[source,java,linenums] ----- -public class UserBean { - - /** 已经由Spring注入 */ - private RuntimeService runtimeService; - - @Transactional - public void hello() { - // 可以在你的领域模型(domain model)中进行事务操作, - // 它会与Flowable RuntimeService的startProcessInstanceByKey - // 合并在同一个事务里 - runtimeService.startProcessInstanceByKey("helloProcess"); - } - - public void setRuntimeService(RuntimeService runtimeService) { - this.runtimeService = runtimeService; - } -} ----- - -[[springExpressions]] - - -=== 表达式 - -当使用ProcessEngineFactoryBean时,默认BPMN流程中所有的<>都可以“看见”所有的Spring bean。可以通过配置的map,限制表达式能使用的bean,甚至可以完全禁止表达式使用bean。下面的例子只暴露了一个bean(printer),可以使用“printer”作为key访问。**要完全禁止表达式使用bean,可以将SpringProcessEngineConfiguration的‘beans’参数设为空list。如果不设置‘beans’参数,则上下文中的所有bean都将可以使用。** - -[source,xml,linenums] ----- - - ... - - - - - - - - ----- - -这样就可以在表达式中使用这个bean了。例如,SpringTransactionIntegrationTest ++hello.bpmn20.xml++展示了如何通过UEL方法表达式(method expression)调用Spring bean: - -[source,xml,linenums] ----- - - - - - - - - - - - - - - - ----- - -其中++Printer++为: - -[source,java,linenums] ----- -public class Printer { - - public void printMessage() { - System.out.println("hello world"); - } -} ----- - -Spring bean配置(上面已经展示过)为: - -[source,xml,linenums] ----- - - ... - - - - ----- - -[[_automatic_resource_deployment]] -=== 自动部署资源 - -集成Spring也提供了部署资源的特殊方式。在流程引擎配置中,可以指定一组资源。当创建流程引擎时,会扫描并部署这些资源。可以用过滤器阻止重复部署:只有当资源确实发生变化时,才会重新部署至Flowable数据库。在Spring容器经常重启(例如测试时)的时候,这很有用。 - -这里有个例子: - -[source,xml,linenums] ----- - - ... - - - - - - ----- - -默认情况下,上面的配置方式会将符合这个过滤器的所有资源组织在一起,作为Flowable引擎的一个部署。重复检测过滤器将作用于整个部署,避免重复地部署未改变资源。有时这不是你想要的。例如,如果用这种方式部署了一组资源,即使只有其中的一个资源发生了改变,整个部署都会被视作已改变,因此这个部署中所有的所有流程定义都会被重新部署。这将导致每个流程定义都会刷新版本号(流程定义id会变化),即使实际上只有一个流程发生了变化。 - -可以使用++SpringProcessEngineConfiguration++中的额外参数+deploymentMode+,定制部署的方式。这个参数定义了对于一组符合过滤器的资源,组织部署的方式。默认这个参数有3个可用值: - -* ++default++: 将所有资源组织在一个部署中,整体用于重复检测过滤。这是默认值,在未设置这个参数时也会用这个值。 -* ++single-resource++: 为每个资源创建一个单独的部署,并用于重复检测过滤。如果希望单独部署每一个流程定义,并且只有在它发生变化时才创建新的流程定义版本,就应该使用这个值。 -* ++resource-parent-folder++: 为同一个目录下的资源创建一个单独的部署,并用于重复检测过滤。这个参数值可以为大多数资源创建独立的部署。同时仍可以通过将部分资源放在同一个目录下,将它们组织在一起。这里有一个将++deploymentMode++设置为++single-resource++的例子: - - -[source,xml,linenums] ----- - - ... - - - ----- - -如果上述++deploymentMode++的参数值不能满足要求,还可以自定义组织部署的行为。创建++SpringProcessEngineConfiguration++的子类,并覆盖++getAutoDeploymentStrategy(String deploymentMode)++方法。这个方法用于确定对给定的++deploymentMode++参数值,应使用何种部署策略。 - - -[[springUnitTest]] - - -=== 单元测试 - -与Spring集成后,业务流程可以非常简单地使用标准的 <>进行测试。下面的例子展示了如何通过典型的基于Spring的单元测试,对业务流程进行测试: - -[source,java,linenums] ----- -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration("classpath:org/flowable/spring/test/junit4/springTypicalUsageTest-context.xml") -public class MyBusinessProcessTest { - - @Autowired - private RuntimeService runtimeService; - - @Autowired - private TaskService taskService; - - @Autowired - @Rule - public FlowableRule flowableSpringRule; - - @Test - @Deployment - public void simpleProcessTest() { - runtimeService.startProcessInstanceByKey("simpleProcess"); - Task task = taskService.createTaskQuery().singleResult(); - assertEquals("My Task", task.getName()); - - taskService.complete(task.getId()); - assertEquals(0, runtimeService.createProcessInstanceQuery().count()); - - } -} ----- - -请注意要让这个例子可以正常工作,需要在Spring配置中定义__org.flowable.engine.test.FlowableRule__ bean(在上面的例子中通过@Autowire注入)。 - - -[source,xml,linenums] ----- - - - - ----- - - -[[_jpa_with_hibernate_4_2_x]] -=== 通过Hibernate 4.2.x使用JPA - -要在Flowable引擎的服务任务或者监听器逻辑中使用Hibernate 4.2.x JPA,需要添加Spring ORM的额外依赖。对Hibernate 4.1.x或更低则不需要。需要添加的依赖为: - -[source,xml,linenums] ----- - - org.springframework - spring-orm - ${org.springframework.version} - ----- - - diff --git a/docs/userguide/src/zh_CN/bpmn/ch05a-Spring-Boot.adoc b/docs/userguide/src/zh_CN/bpmn/ch05a-Spring-Boot.adoc deleted file mode 100755 index ce9e0129614..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch05a-Spring-Boot.adoc +++ /dev/null @@ -1,1045 +0,0 @@ - -[[springSpringBoot]] - - -=== Spring Boot - -Spring Boot是一个应用框架。按照link:$$http://projects.spring.io/spring-boot/$$[其官网]的介绍,可以__轻松地创建独立运行的,生产级别的,基于Spring的应用,并且可以“直接运行”。它基于约定大于配置的原则使用Spring框架与第三方库,使你可以轻松地开始使用。大多数Spring Boot应用只需要很少的Spring配置__。 - -要获得更多关于Spring Boot的信息,请查阅link:$$http://projects.spring.io/spring-boot/$$[http://projects.spring.io/spring-boot/] - -Flowable与Spring Boot的集成是我们与Spring的提交者共同开发的。 - -[[_compatibility]] -==== 兼容性 - -Flowable使用同一个starter支持Spring Boot 2.0及1.5。主要支持Spring Boot 2.0。所以监控(actuator) endpoint只支持2.0。Flowable的starter直接引用Spring Boot starter,所以如果需要使用1.5版的Spring Boot starter,需要自行定义。 - -[[_getting_started_2]] -==== 开始 - -Spring Boot提倡约定大于配置。要开始工作,只需在项目中添加__flowable-spring-boot-starter__或__flowable-spring-boot-starter-rest__依赖。如果不需要引入所有的引擎,可以查看其它的<>。 -如使用Maven: - - -[source,xml,linenums] ----- - - org.flowable - flowable-spring-boot-starter - ${flowable.version} - ----- - -就这么简单。这个依赖会自动向classpath添加正确的Flowable与Spring依赖。现在可以编写Spring Boot应用了: - -[source,java,,linenums] ----- -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication(proxyBeanMethods = false) -public class MyApplication { - - public static void main(String[] args) { - SpringApplication.run(MyApplication.class, args); - } - -} ----- - -Flowable需要数据库来存储数据。运行上面的代码会得到异常提示,指出需要在classpath中添加数据库驱动依赖。现在添加H2数据库依赖: - -[source,xml,linenums] ----- - - com.h2database - h2 - 1.4.197 - ----- - -应用这次可以启动了。你会看到类似这样的输出: - ----- - . ____ _ __ _ _ - /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ -( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ - \\/ ___)| |_)| | | | | || (_| | ) ) ) ) - ' |____| .__|_| |_|_| |_\__, | / / / / - =========|_|==============|___/=/_/_/_/ - :: Spring Boot :: (v2.0.0.RELEASE) - -MyApplication : Starting MyApplication on ... -MyApplication : No active profile set, falling back to default profiles: default -ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@4fdfa676: startup date [Wed Mar 28 12:04:00 CEST 2018]; root of context hierarchy -o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) -o.apache.catalina.core.StandardService : Starting service [Tomcat] -org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.28 -o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext -o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 3085 ms -o.s.b.w.servlet.ServletRegistrationBean : Servlet dispatcherServlet mapped to [/] -o.s.b.w.servlet.ServletRegistrationBean : Servlet Flowable IDM Rest API mapped to [/idm-api/*] -o.s.b.w.servlet.ServletRegistrationBean : Servlet Flowable Form Rest API mapped to [/form-api/*] -o.s.b.w.servlet.ServletRegistrationBean : Servlet Flowable DMN Rest API mapped to [/dmn-api/*] -o.s.b.w.servlet.ServletRegistrationBean : Servlet Flowable Content Rest API mapped to [/content-api/*] -o.s.b.w.servlet.ServletRegistrationBean : Servlet Flowable CMMN Rest API mapped to [/cmmn-api/*] -o.s.b.w.servlet.ServletRegistrationBean : Servlet Flowable BPMN Rest API mapped to [/process-api/*] -o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*] -o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*] -o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*] -o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*] -uration$$EnhancerBySpringCGLIB$$3d0c70ac : No deployment resources were found for autodeployment -uration$$EnhancerBySpringCGLIB$$8131eb1a : No deployment resources were found for autodeployment -o.f.e.i.c.ProcessEngineConfigurationImpl : Found 5 Engine Configurators in total: -o.f.e.i.c.ProcessEngineConfigurationImpl : class org.flowable.spring.configurator.SpringIdmEngineConfigurator (priority:100000) -o.f.e.i.c.ProcessEngineConfigurationImpl : class org.flowable.dmn.spring.configurator.SpringDmnEngineConfigurator (priority:200000) -o.f.e.i.c.ProcessEngineConfigurationImpl : class org.flowable.form.spring.configurator.SpringFormEngineConfigurator (priority:300000) -o.f.e.i.c.ProcessEngineConfigurationImpl : class org.flowable.content.spring.configurator.SpringContentEngineConfigurator (priority:400000) -o.f.e.i.c.ProcessEngineConfigurationImpl : class org.flowable.cmmn.spring.configurator.SpringCmmnEngineConfigurator (priority:500000) -o.f.e.i.c.ProcessEngineConfigurationImpl : Executing beforeInit() of class org.flowable.spring.configurator.SpringIdmEngineConfigurator (priority:100000) -o.f.e.i.c.ProcessEngineConfigurationImpl : Executing beforeInit() of class org.flowable.dmn.spring.configurator.SpringDmnEngineConfigurator (priority:200000) -o.f.e.i.c.ProcessEngineConfigurationImpl : Executing beforeInit() of class org.flowable.form.spring.configurator.SpringFormEngineConfigurator (priority:300000) -o.f.e.i.c.ProcessEngineConfigurationImpl : Executing beforeInit() of class org.flowable.content.spring.configurator.SpringContentEngineConfigurator (priority:400000) -o.f.e.i.c.ProcessEngineConfigurationImpl : Executing beforeInit() of class org.flowable.cmmn.spring.configurator.SpringCmmnEngineConfigurator (priority:500000) -com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting... -com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed. -o.f.e.i.c.ProcessEngineConfigurationImpl : Executing configure() of class org.flowable.spring.configurator.SpringIdmEngineConfigurator (priority:100000) -.d.AbstractSqlScriptBasedDbSchemaManager : performing create on identity with resource org/flowable/idm/db/create/flowable.h2.create.identity.sql -o.f.idm.engine.impl.IdmEngineImpl : IdmEngine default created -o.f.e.i.c.ProcessEngineConfigurationImpl : Executing configure() of class org.flowable.dmn.spring.configurator.SpringDmnEngineConfigurator (priority:200000) -o.f.dmn.engine.impl.DmnEngineImpl : DmnEngine default created -o.f.e.i.c.ProcessEngineConfigurationImpl : Executing configure() of class org.flowable.form.spring.configurator.SpringFormEngineConfigurator (priority:300000) -o.f.form.engine.impl.FormEngineImpl : FormEngine default created -o.f.e.i.c.ProcessEngineConfigurationImpl : Executing configure() of class org.flowable.content.spring.configurator.SpringContentEngineConfigurator (priority:400000) -o.f.c.engine.ContentEngineConfiguration : Content file system root : ... -o.f.c.engine.impl.ContentEngineImpl : ContentEngine default created -o.f.e.i.c.ProcessEngineConfigurationImpl : Executing configure() of class org.flowable.cmmn.spring.configurator.SpringCmmnEngineConfigurator (priority:500000) -o.f.cmmn.engine.CmmnEngineConfiguration : Found 1 Engine Configurators in total: -o.f.cmmn.engine.CmmnEngineConfiguration : class org.flowable.cmmn.engine.impl.cfg.IdmEngineConfigurator (priority:100000) -o.f.cmmn.engine.CmmnEngineConfiguration : Executing beforeInit() of class org.flowable.cmmn.engine.impl.cfg.IdmEngineConfigurator (priority:100000) -o.f.cmmn.engine.CmmnEngineConfiguration : Executing configure() of class org.flowable.cmmn.engine.impl.cfg.IdmEngineConfigurator (priority:100000) -o.f.idm.engine.impl.IdmEngineImpl : IdmEngine default created -o.f.cmmn.engine.impl.CmmnEngineImpl : CmmnEngine default created -o.f.engine.impl.ProcessEngineImpl : ProcessEngine default created -o.f.j.s.i.a.AbstractAsyncExecutor : Starting up the async job executor [org.flowable.spring.job.service.SpringAsyncExecutor]. -o.f.j.s.i.a.AcquireAsyncJobsDueRunnable : starting to acquire async jobs due -o.f.j.s.i.a.AcquireTimerJobsRunnable : starting to acquire async jobs due -o.f.j.s.i.a.ResetExpiredJobsRunnable : starting to reset expired jobs -o.f.e.impl.cmd.ValidateV5EntitiesCmd : Total of v5 deployments found: 0 -s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@4fdfa676: startup date [Wed Mar 28 12:04:00 CEST 2018]; root of context hierarchy -s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(jakarta.servlet.http.HttpServletRequest) -s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(jakarta.servlet.http.HttpServletRequest,jakarta.servlet.http.HttpServletResponse) -o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] -o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] -o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] -o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup -o.s.j.e.a.AnnotationMBeanExporter : Bean with name 'dataSource' has been autodetected for JMX exposure -o.s.j.e.a.AnnotationMBeanExporter : Located MBean 'dataSource': registering with JMX server as MBean [com.zaxxer.hikari:name=dataSource,type=HikariDataSource] -o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase -20 -o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 0 -o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 20 -o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' -flowable.Application : Started Application in 18.235 seconds (JVM running for 19.661) ----- - -只是在classpath中添加依赖,并使用__@SpringBootAplication__注解,就会在幕后发生很多事情: - -* 自动创建了内存数据库(因为classpath中有H2驱动),并传递给Flowable流程引擎配置 -* 创建并暴露了Flowable的ProcessEngine、CmmnEngine、DmnEngine、FormEngine、ContentEngine及IdmEngine bean -* 所有的Flowable服务都暴露为Spring bean -* 创建了Spring Job Executor - -并且: - -* __processes__目录下的任何BPMN 2.0流程定义都会被自动部署。创建__processes__目录,并在其中创建示例流程定义(命名为__one-task-process.bpmn20.xml__)。 -* __cases__目录下的任何CMMN 1.1事例都会被自动部署。 -* __forms__目录下的任何Form定义都会被自动部署。 - -[source,xml,linenums] ----- - - - - - - - - - - - - ----- - -然后添加下列代码,以测试部署是否生效。__CommandLineRunner__是一个特殊的Spring bean,在应用启动时执行: - -[source,java,linenums] ----- -@SpringBootApplication(proxyBeanMethods = false) -public class MyApplication { - - public static void main(String[] args) { - SpringApplication.run(MyApplication.class, args); - } - - @Bean - public CommandLineRunner init(final RepositoryService repositoryService, - final RuntimeService runtimeService, - final TaskService taskService) { - - return new CommandLineRunner() { - @Override - public void run(String... strings) throws Exception { - System.out.println("Number of process definitions : " - + repositoryService.createProcessDefinitionQuery().count()); - System.out.println("Number of tasks : " + taskService.createTaskQuery().count()); - runtimeService.startProcessInstanceByKey("oneTaskProcess"); - System.out.println("Number of tasks after process start: " - + taskService.createTaskQuery().count()); - } - }; - } -} ----- - -会得到这样的输出: - ----- -Number of process definitions : 1 -Number of tasks : 0 -Number of tasks after process start : 1 ----- - -[[_changing_the_database_and_connection_pool]] -==== 更换数据源与连接池 - -上面也提到过,Spring Boot的约定大于配置。默认情况下,如果classpath中只有H2,就会创建内存数据库,并传递给Flowable流程引擎配置。 - -只要添加一个数据库驱动的依赖并提供数据库URL,就可以更换数据源。例如,要切换到MySQL数据库: - -[source,linenums] ----- -spring.datasource.url=jdbc:mysql://127.0.0.1:3306/flowable-spring-boot?characterEncoding=UTF-8 -spring.datasource.username=flowable -spring.datasource.password=flowable ----- - -从Maven依赖中移除H2,并在classpath中添加MySQL驱动: - -[source,xml,linenums] ----- - - mysql - mysql-connector-java - 5.1.45 - ----- - -这次应用启动后,可以看到使用了MySQL作为数据库(并使用HikariCP连接池框架): - ----- -org.flowable.engine.impl.db.DbSqlSession : performing create on engine with resource org/flowable/db/create/flowable.mysql.create.engine.sql -org.flowable.engine.impl.db.DbSqlSession : performing create on history with resource org/flowable/db/create/flowable.mysql.create.history.sql -org.flowable.engine.impl.db.DbSqlSession : performing create on identity with resource org/flowable/db/create/flowable.mysql.create.identity.sql ----- - -多次重启应用,会发现任务的数量增加了(H2内存数据库在关闭后会丢失,而MySQL不会)。 - -关于配置数据源的更多信息,可以在Spring Boot的参考手册中link:$$https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-sql.html#boot-features-configure-datasource$$[Configure a DataSource(配置数据源)]章节查看。 - -[[_rest_support]] -==== REST 支持 - -通常会在嵌入的Flowable引擎之上,使用REST API(用于与公司的不同服务交互)。Spring Boot让这变得很容易。在classpath中添加下列依赖: - -[source,xml,linenums] ----- - - org.springframework.boot - spring-boot-starter-web - ${spring.boot.version} - ----- - -创建一个新的Spring服务类,并创建两个方法:一个用于启动流程,另一个用于获得给定任务办理人的任务列表。在这里只是简单地包装了Flowable调用,但在实际使用场景中会比这复杂得多。 - - -[source,java,linenums] ----- -@Service -public class MyService { - - @Autowired - private RuntimeService runtimeService; - - @Autowired - private TaskService taskService; - - @Transactional - public void startProcess() { - runtimeService.startProcessInstanceByKey("oneTaskProcess"); - } - - @Transactional - public List getTasks(String assignee) { - return taskService.createTaskQuery().taskAssignee(assignee).list(); - } - -} ----- - -现在可以用__@RestController__来注解类,以创建REST endpoint。在这里我们简单地调用上面定义的服务。 - -[source,java,linenums] ----- -@RestController -public class MyRestController { - - @Autowired - private MyService myService; - - @PostMapping(value="/process") - public void startProcessInstance() { - myService.startProcess(); - } - - @RequestMapping(value="/tasks", method= RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE) - public List getTasks(@RequestParam String assignee) { - List tasks = myService.getTasks(assignee); - List dtos = new ArrayList(); - for (Task task : tasks) { - dtos.add(new TaskRepresentation(task.getId(), task.getName())); - } - return dtos; - } - - static class TaskRepresentation { - - private String id; - private String name; - - public TaskRepresentation(String id, String name) { - this.id = id; - this.name = name; - } - - public String getId() { - return id; - } - public void setId(String id) { - this.id = id; - } - public String getName() { - return name; - } - public void setName(String name) { - this.name = name; - } - - } - -} ----- - -Spring Boot会自动扫描组件,并找到我们添加在应用类上的__@Service__与__@RestController__。再次运行应用,现在可以与REST API交互了。例如使用cURL: - - ----- -curl http://localhost:8080/tasks?assignee=kermit -[] - -curl -X POST http://localhost:8080/process -curl http://localhost:8080/tasks?assignee=kermit -[{"id":"10004","name":"my task"}] ----- - -[[_jpa_support]] -==== JPA 支持 - -要为Spring Boot中的Flowable添加JPA支持,增加下列依赖: - -[source,xml,linenums] ----- - - org.flowable - flowable-spring-boot-starter - ${flowable.version} - - - org.springframework.boot - spring-boot-starter-data-jpa - ${spring-boot.version - ----- - -这会加入JPA用的Spring配置以及bean。默认使用Hibernate作为JPA提供者。 - -创建一个简单的实体类: - -[source,java,linenums] ----- -@Entity -class Person { - - @Id - @GeneratedValue - private Long id; - - private String username; - - private String firstName; - - private String lastName; - - private Date birthDate; - - public Person() { - } - - public Person(String username, String firstName, String lastName, Date birthDate) { - this.username = username; - this.firstName = firstName; - this.lastName = lastName; - this.birthDate = birthDate; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public Date getBirthDate() { - return birthDate; - } - - public void setBirthDate(Date birthDate) { - this.birthDate = birthDate; - } -} ----- - -默认情况下,如果没有使用内存数据库则不会自动创建数据库表。在classpath中创建__application.properties__文件并加入下列参数: - ----- -spring.jpa.hibernate.ddl-auto=update ----- - -添加下列类: - -[source,java,linenums] ----- -@Repository -public interface PersonRepository extends JpaRepository { - - Person findByUsername(String username); -} ----- - -这是一个Spring repository,提供了直接可用的增删改查。我们添加了通过username查找Person的方法。Spring会基于约定自动实现它(也就是使用names属性)。 - -现在进一步增强我们的服务: - -* 在类上添加__@Transactional__。请注意,通过上面添加的JPA依赖,之前使用的DataSourceTransactionManager会自动替换为JpaTransactionManager。 -* __startProcess__增加了任务办理人入参,用于查找Person,并将Person JPA对象作为流程变量存入流程实例。 -* 添加了创建示例用户的方法。CommandLineRunner使用它打桩数据库。 - -[source,java,linenums] ----- -@Service -@Transactional -public class MyService { - - @Autowired - private RuntimeService runtimeService; - - @Autowired - private TaskService taskService; - - @Autowired - private PersonRepository personRepository; - - public void startProcess(String assignee) { - - Person person = personRepository.findByUsername(assignee); - - Map variables = new HashMap(); - variables.put("person", person); - runtimeService.startProcessInstanceByKey("oneTaskProcess", variables); - } - - public List getTasks(String assignee) { - return taskService.createTaskQuery().taskAssignee(assignee).list(); - } - - public void createDemoUsers() { - if (personRepository.findAll().size() == 0) { - personRepository.save(new Person("jbarrez", "Joram", "Barrez", new Date())); - personRepository.save(new Person("trademakers", "Tijs", "Rademakers", new Date())); - } - } - -} ----- - -CommandLineRunner现在为: - -[source,java,linenums] ----- -@Bean -public CommandLineRunner init(final MyService myService) { - - return new CommandLineRunner() { - public void run(String... strings) throws Exception { - myService.createDemoUsers(); - } - }; -} ----- - -RestController也有小改动(只展示新方法),以配合上面的修改。HTTP POST使用body传递办理人用户名: - -[source,java,linenums] ----- -@RestController -public class MyRestController { - - @Autowired - private MyService myService; - - @PostMapping(value="/process") - public void startProcessInstance(@RequestBody StartProcessRepresentation startProcessRepresentation) { - myService.startProcess(startProcessRepresentation.getAssignee()); - } - - ... - - static class StartProcessRepresentation { - - private String assignee; - - public String getAssignee() { - return assignee; - } - - public void setAssignee(String assignee) { - this.assignee = assignee; - } - } ----- - -最后,为了试用Spring-JPA-Flowable集成,我们在流程定义中,将Person JPA对象的ID指派为任务办理人: - -[source,xml,linenums] ----- - ----- - -现在可以在POST body中提供用户名,启动一个新的流程实例: - ----- -curl -H "Content-Type: application/json" -d '{"assignee" : "jbarrez"}' http://localhost:8080/process ----- - -可以使用Person id获取任务列表: - ----- -curl http://localhost:8080/tasks?assignee=1 - -[{"id":"12505","name":"my task"}] ----- - -[[springBootActuatorEndpoint]] -==== Flowable Actuator Endpoint - -Flowable提供了Spring Boot Actuator Endpoint,以提供正在运行的流程的信息。 -默认情况下 `flowable` 端点映射至 `/actuator/flowable` 。 -Spring Boot默认只通过web暴露少许端点(例如:在 `spring-boot-starter-actuator:2.5.4` 中, Spring Boot 默认只通过web暴露了 `health` 端点。更多有关于 Spring Boot 默认暴露的端点的信息,请参考 link:$$https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator.endpoints.exposing$$[https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator.endpoints.exposing] )。要通过web使用 `flowable` 端点,需要在 `application.properties` 中添加 `management.endpoints.web.exposure.include=flowable` (注意: `org.flowable.spring.boot.EndpointAutoConfiguration` 类没有使用 `@ConditionalOnAvailableEndpoint` 注解检查 `flowable` 的端点是否同时被启用和被暴露。所以为了通过web使用 `flowable` 端点,你只需要在配置文件中添加 `management.endpoints.web.exposure.include=flowable` 或 `management.endpoints.web.exposure.include=*` 即可)。 - -`curl http://localhost:8080/actuator/flowable` - -[source,json] ----- - -{ - "completedTaskCountToday": 0, - "deployedProcessDefinitions": [ - "oneTaskProcess (v1)" - ], - "processDefinitionCount": 1, - "cachedProcessDefinitionCount": 0, - "runningProcessInstanceCount": { - "oneTaskProcess (v1)": 0 - }, - "completedTaskCount": 2, - "completedActivities": 3, - "completedProcessInstanceCount": { - "oneTaskProcess (v1)": 0 - }, - "openTaskCount": 0 -} ----- - - -要了解Spring Boot Actuator的更多信息,可以在Spring Boot参考手册中查看link:$$https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html$$[Production Ready Endpoint(生产可用的端点)]。 - -[[springBootInfoContributor]] -==== Flowable Info Contributor - -Flowable也提供了Spring Boot的 `InfoContributor` : - -`curl http://localhost:8080/actuator/info` - -[source,json] ----- -{ - "flowable": { - "version": "6.3.0.1" - } -} ----- - -[[springBootFlowableProperties]] -==== 配置Flowable应用 - -Flowable会自动配置用于控制Spring Boot的参数与配置。参见Spring Boot参考手册中的link:$$https://docs.spring.io/spring-boot/docs/current/reference/html/howto-properties-and-configuration.html$$[Properties and Configuration(参数与配置)]。 - -下面是Flowable Spring Boot支持的配置参数列表。 - -[source,properties,indent=0,subs="verbatim,attributes,macros"] ----- - -# =================================================================== -# Common Flowable Spring Boot Properties -# 通用Flowable Spring Boot参数 -# -# This sample file is provided as a guideline. Do NOT copy it in its -# entirety to your own application. ^^^ -# 本示例文件只作为指导。请不要直接拷贝至你自己的应用中。 -# =================================================================== - -# Core (Process) {sc-flowable-boot}/FlowableProperties.java[FlowableProperties] -# 核心(流程) -flowable.check-process-definitions=true # 是否需要自动部署流程定义。 -flowable.custom-mybatis-mappers= # 需要添加至引擎的自定义Mybatis映射的FQN。 -flowable.custom-mybatis-x-m-l-mappers= # 需要添加至引擎的自定义Mybatis XML映射的路径。 -flowable.database-schema= # 如果数据库返回的元数据不正确,可以在这里设置schema用于检测/生成表。 -flowable.database-schema-update=true # 数据库schema更新策略。 -flowable.db-history-used=true # 是否要使用db历史。 -flowable.deployment-name=SpringBootAutoDeployment # 自动部署的名称。 -flowable.history-level=audit # 要使用的历史级别。 -flowable.process-definition-location-prefix=classpath*:/processes/ # 自动部署时查找流程的目录。 -flowable.process-definition-location-suffixes=**.bpmn20.xml,**.bpmn # 'processDefinitionLocationPrefix'路径下需要部署的文件的后缀(扩展名)。 - -# Process {sc-flowable-boot}/process/FlowableProcessProperties.java[FlowableProcessProperties] -# 流程 -flowable.process.definition-cache-limit=-1 # 流程定义缓存中保存流程定义的最大数量。默认值为-1(缓存所有流程定义)。 -flowable.process.enable-safe-xml=true # 在解析BPMN XML文件时进行额外检查。参见 https://www.flowable.org/docs/userguide/index.html#advanced.safe.bpmn.xml 。不幸的是,部分平台(JDK 6,JBoss)上无法使用这个功能,因此如果你所用的平台在XML解析时不支持StaxSource,需要禁用这个功能。 -flowable.process.servlet.load-on-startup=-1 # 启动时加载Process servlet。 -flowable.process.servlet.name=Flowable BPMN Rest API # Process servlet的名字。 -flowable.process.servlet.path=/process-api # Process servelet的context path。 - -# Process Async Executor -# 流程异步执行器 -flowable.process.async-executor-activate=true # 是否启用异步执行器。 -flowable.process.async.executor.async-job-lock-time-in-millis=300000 # 异步作业在被异步执行器取走后的锁定时间(以毫秒计)。在这段时间内,其它异步执行器不会尝试获取及锁定这个任务。 -flowable.process.async.executor.default-async-job-acquire-wait-time-in-millis=10000 # 异步作业获取线程在进行下次获取查询前的等待时间(以毫秒计)。只在当次没有取到新的异步作业,或者只取到很少的异步作业时生效。默认值 = 10秒。 -flowable.process.async.executor.default-queue-size-full-wait-time-in-millis=0 # 异步作业(包括定时器作业与异步执行)获取线程在队列满时,等待执行下次查询的等待时间(以毫秒计)。默认值为0(以向后兼容) -flowable.process.async.executor.default-timer-job-acquire-wait-time-in-millis=10000 # 定时器作业获取线程在进行下次获取查询前的等待时间(以毫秒计)。只在当次没有取到新的定时器作业,或者只取到很少的定时器作业时生效。默认值 = 10秒。 -flowable.process.async.executor.max-async-jobs-due-per-acquisition=1 # (译者补)单次查询的异步作业数量。默认值为1,以降低乐观锁异常的可能性。除非你知道自己在做什么,否则请不要修改这个值。 -flowable.process.async.executor.retry-wait-time-in-millis=500 # ???(译者补不了了) -flowable.process.async.executor.timer-lock-time-in-millis=300000 # 定时器作业在被异步执行器取走后的锁定时间(以毫秒计)。在这段时间内,其它异步执行器不会尝试获取及锁定这个任务。 - - -# CMMN {sc-flowable-boot}/cmmn/FlowableCmmnProperties.java[FlowableCmmnProperties] -flowable.cmmn.deploy-resources=true # 是否部署资源。默认值为'true'。 -flowable.cmmn.deployment-name=SpringBootAutoDeployment # CMMN资源部署的名字。 -flowable.cmmn.enable-safe-xml=true # 在解析CMMN XML文件时进行额外检查。参见 https://www.flowable.org/docs/userguide/index.html#advanced.safe.bpmn.xml 。不幸的是,部分平台(JDK 6,JBoss)上无法使用这个功能,因此如果你所用的平台在XML解析时不支持StaxSource,需要禁用这个功能。 -flowable.cmmn.enabled=true # 是否启用CMMN引擎。 -flowable.cmmn.resource-location=classpath*:/cases/ # CMMN资源的路径。 -flowable.cmmn.resource-suffixes=**.cmmn,**.cmmn11,**.cmmn.xml,**.cmmn11.xml # 需要扫描的资源后缀名。 -flowable.cmmn.servlet.load-on-startup=-1 # 启动时加载CMMN servlet。 -flowable.cmmn.servlet.name=Flowable CMMN Rest API # CMMN servlet的名字。 -flowable.cmmn.servlet.path=/cmmn-api # CMMN servlet的context path。 - -# CMMN Async Executor -# CMMN异步执行器 -flowable.cmmn.async-executor-activate=true # 是否启用异步执行器。 -flowable.cmmn.async.executor.async-job-lock-time-in-millis=300000 # 异步作业在被异步执行器取走后的锁定时间(以毫秒计)。在这段时间内,其它异步执行器不会尝试获取及锁定这个任务。 -flowable.cmmn.async.executor.default-async-job-acquire-wait-time-in-millis=10000 # 异步作业获取线程在进行下次获取查询前的等待时间(以毫秒计)。只在当次没有取到新的异步作业,或者只取到很少的异步作业时生效。默认值 = 10秒。 -flowable.cmmn.async.executor.default-queue-size-full-wait-time-in-millis=0 # 异步作业(包括定时器作业与异步执行)获取线程在队列满时,等待执行下次查询的等待时间(以毫秒计)。默认值为0(以向后兼容) -flowable.cmmn.async.executor.default-timer-job-acquire-wait-time-in-millis=10000 # 定时器作业获取线程在进行下次获取查询前的等待时间(以毫秒计)。只在当次没有取到新的定时器作业,或者只取到很少的定时器作业时生效。默认值 = 10秒。 -flowable.cmmn.async.executor.max-async-jobs-due-per-acquisition=1 # (译者补)单次查询的异步作业数量。默认值为1,以降低乐观锁异常的可能性。除非你知道自己在做什么,否则请不要修改这个值。 -flowable.cmmn.async.executor.retry-wait-time-in-millis=500 #(译者补不了了) -flowable.cmmn.async.executor.timer-lock-time-in-millis=300000 # 定时器作业在被异步执行器取走后的锁定时间(以毫秒计)。在这段时间内,其它异步执行器不会尝试获取及锁定这个任务。 - -# Content {sc-flowable-boot}/content/FlowableContentProperties.java[FlowableContentProperties] -flowable.content.enabled=true # 是否启动Content引擎。 -flowable.content.servlet.load-on-startup=-1 # 启动时加载Content servlet。 -flowable.content.servlet.name=Flowable Content Rest API # Content servlet的名字。 -flowable.content.servlet.path=/content-api # Content servlet的context path。 -flowable.content.storage.create-root=true # 如果根路径不存在,是否需要创建? -flowable.content.storage.root-folder= # 存储content文件(如上传的任务附件,或表单文件)的根路径。 - -# DMN {sc-flowable-boot}/dmn/FlowableDmnProperties.java[FlowableDmnProperties] -flowable.dmn.deploy-resources=true # 是否部署资源。默认为'true'。 -flowable.dmn.deployment-name=SpringBootAutoDeployment # DMN资源部署的名字。 -flowable.dmn.enable-safe-xml=true # 在解析DMN XML文件时进行额外检查。参见 https://www.flowable.org/docs/userguide/index.html#advanced.safe.bpmn.xml 。不幸的是,部分平台(JDK 6,JBoss)上无法使用这个功能,因此如果你所用的平台在XML解析时不支持StaxSource,需要禁用这个功能。 -flowable.dmn.enabled=true # 是否启用DMN引擎。 -flowable.dmn.history-enabled=true # 是否启用DMN引擎的历史。 -flowable.dmn.resource-location=classpath*:/dmn/ # DMN资源的路径。 -flowable.dmn.resource-suffixes=**.dmn,**.dmn.xml,**.dmn11,**.dmn11.xml # 需要扫描的资源后缀名。 -flowable.dmn.servlet.load-on-startup=-1 # 启动时加载DMN servlet。 -flowable.dmn.servlet.name=Flowable DMN Rest API # DMN servlet的名字。 -flowable.dmn.servlet.path=/dmn-api # DMN servlet的context path。 -flowable.dmn.strict-mode=true # 如果希望避免抉择表命中策略检查导致失败,可以将本参数设置为false。如果检查发现了错误,会直接返回错误前一刻的中间结果。 - -# Form {sc-flowable-boot}/form/FlowableFormProperties.java[FlowableFormProperties] -flowable.form.deploy-resources=true # 是否部署资源。默认为'true'。 -flowable.form.deployment-name=SpringBootAutoDeployment # Form资源部署的名字。 -flowable.form.enabled=true # 是否启用Form引擎。 -flowable.form.resource-location=classpath*:/forms/ # Form资源的路径。 -flowable.form.resource-suffixes=**.form # 需要扫描的资源后缀名。 -flowable.form.servlet.load-on-startup=-1 # 启动时加载Form servlet。 -flowable.form.servlet.name=Flowable Form Rest API # Form servlet的名字。 -flowable.form.servlet.path=/form-api # Form servlet的context path。 - -# IDM {sc-flowable-boot}/idm/FlowableIdmProperties.java[FlowableIdmProperties] -flowable.idm.enabled=true # 是否启用IDM引擎。 -flowable.idm.password-encoder= # 使用的密码编码类型。 -flowable.idm.servlet.load-on-startup=-1 # 启动时加载IDM servlet。 -flowable.idm.servlet.name=Flowable IDM Rest API # IDM servlet的名字。 -flowable.idm.servlet.path=/idm-api # IDM servlet的context path。 - -# IDM Ldap {sc-flowable-boot}/ldap/FlowableLdapProperties.java[FlowableLdapProperties] -flowable.idm.ldap.attribute.email= # 用户email的属性名。 -flowable.idm.ldap.attribute.first-name= # 用户名字的属性名。 -flowable.idm.ldap.attribute.group-id= # 用户组ID的属性名。 -flowable.idm.ldap.attribute.group-name= # 用户组名的属性名。 -flowable.idm.ldap.attribute.group-type= # 用户组类型的属性名。 -flowable.idm.ldap.attribute.last-name= # 用户姓的属性名。 -flowable.idm.ldap.attribute.user-id= # 用户ID的属性名。 -flowable.idm.ldap.base-dn= # 查找用户与组的DN(标志名称 distinguished name)。 -flowable.idm.ldap.cache.group-size=-1 # 设置{@link org.flowable.ldap.LDAPGroupCache}的大小。这是LRU缓存,用于缓存用户及组,以避免每次都查询LDAP系统。 -flowable.idm.ldap.custom-connection-parameters= # 用于设置所有没有专用setter的LDAP连接参数。查看 http://docs.oracle.com/javase/tutorial/jndi/ldap/jndi.html 介绍的自定义参数。参数包括配置链接池,安全设置,等等。 -flowable.idm.ldap.enabled=false # 是否启用LDAP IDM 服务。 -flowable.idm.ldap.group-base-dn= # 组查找的DN。 -flowable.idm.ldap.initial-context-factory=com.sun.jndi.ldap.LdapCtxFactory # 初始化上下文工厂的类名。 -flowable.idm.ldap.password= # 连接LDAP系统的密码。 -flowable.idm.ldap.port=-1 # LDAP系统的端口。 -flowable.idm.ldap.query.all-groups= # 查询所有组所用的语句。 -flowable.idm.ldap.query.all-users= # 查询所有用户所用的语句。 -flowable.idm.ldap.query.groups-for-user= # 按照指定用户查询所属组所用的语句 -flowable.idm.ldap.query.user-by-full-name-like= # 按照给定全名查找用户所用的语句。 -flowable.idm.ldap.query.user-by-id= # 按照userId查找用户所用的语句。 -flowable.idm.ldap.search-time-limit=0 # 查询LDAP的超时时间(以毫秒计)。默认值为'0',即“一直等待”。 -flowable.idm.ldap.security-authentication=simple # 连接LDAP系统所用的'java.naming.security.authentication'参数的值。 -flowable.idm.ldap.server= # LDAP系统的主机名。如'ldap://localhost'。 -flowable.idm.ldap.user= # 连接LDAP系统的用户ID。 -flowable.idm.ldap.user-base-dn= # 查找用户的DN。 - -# Flowable Mail {sc-flowable-boot}/FlowableMailProperties.java[FlowableMailProperties] -flowable.mail.server.default-from=flowable@localhost # 发送邮件时使用的默认发信人地址。 -flowable.mail.server.host=localhost # 邮件服务器。 -flowable.mail.server.password= # 邮件服务器的登录密码。 -flowable.mail.server.port=1025 # 邮件服务器的端口号。 -flowable.mail.server.ssl-port=1465 # SSL邮件服务器的端口号。 -flowable.mail.server.use-ssl=false # 是否使用SSL/TLS加密SMTP传输连接(即SMTPS/POPS)。 -flowable.mail.server.use-tls=false # 使用或禁用STARTTLS加密。 -flowable.mail.server.username= # 邮件服务器的登录用户名。如果为空,则不需要登录。 - -# Flowable Http {sc-flowable-boot}/FlowableHttpProperties.java[FlowableHttpProperties] -flowable.http.user-system-properties=false # 是否使用系统属性 (e.g. http.proxyPort). -flowable.http.connect-timeout=5s # 连接http客户端的超时时间 -flowable.http.socket-timeout=5s # http客户端的Socket超时时间 -flowable.http.connection-request-timeout=5s # http客户端的连接请求超时时间 -flowable.http.request-retry-limit=3 # 请求http客户端的重试限制 -flowable.http.disable-cert-verify=false # 是否禁用http客户端的证书验证 - -# Flowable REST -flowable.rest.app.cors.enabled=true # Whether to enable CORS requests at all. If false, the other properties have no effect -flowable.rest.app.cors.allow-credentials=true # Whether to include credentials in a CORS request -flowable.rest.app.cors.allowed-origins=* # Comma-separated URLs to accept CORS requests from -flowable.rest.app.cors.allowed-headers=* # Comma-separated HTTP headers to allow in a CORS request -flowable.rest.app.cors.allowed-methods=DELETE,GET,PATCH,POST,PUT # Comma-separated HTTP verbs to allow in a CORS request -flowable.rest.app.cors.exposed-headers=* # Comma-separated list of headers to expose in CORS response - -# Actuator -management.endpoint.flowable.cache.time-to-live=0ms # 缓存响应的最大时间。 -management.endpoint.flowable.enabled=true # 是否启用flowable端点。 - ----- - - -.弃用的参数 -[cols="4*",options="header"] -|=============== -|现参数 -|原参数 -|默认值 -|描述 - -|flowable.process.servlet.name -|flowable.rest-api-servlet-name -|Flowable BPMN Rest API -|Process servlet的名字。 - -|flowable.process.servlet.path -|flowable.rest-api-mapping -|/process-api -|Process servlet的context path。 - -|flowable.mail.server.host -|flowable.mail-server-host -|localhost -|邮件服务器。 - -|flowable.mail.server.password -|flowable.mail-server-password -|- -|邮件服务器的密码。 - -|flowable.mail.server.port -|flowable.mail-server-port -|1025 -|邮件服务器的端口号。 - -|flowable.mail.server.ssl-port -|flowable.mail-server-ssl-port -|1465 -|SSL邮件服务器的端口号。 - -|flowable.mail.server.use-ssl -|flowable.mail-server-use-ssl -|false -|是否使用SSL/TLS加密SMTP传输连接(即SMTPS/POPS)。 - -|flowable.mail.server.use-tls -|flowable.mail-server-use-tls -|false -|使用或禁用STARTTLS加密。 - -|flowable.mail.server.username -|flowable.mail-server-user-name -|- -|邮件服务器的登录用户名。如果为空,则不需要登录。 - -|flowable.process.definition-cache-limit -|flowable.process-definitions.cache.max -|-1 -|流程定义缓存中保存流程定义的最大数量。默认值为-1(缓存所有流程定义)。 -|=============== - -[[springBootFlowableAutoConfiguration]] -==== Flowable自动配置类 - -这是Flowable提供的所有自动配置类的列表,并包括了文档及源码的连接。记得查看你的应用的conditions报告,以确认具体启用了哪些功能。(使用--debug或-Ddebug或在Actuator应用中启动应用,并使用 `conditions` 端点)。 - -[cols=*,options="header"] -|=== -|配置类 - -|{sc-flowable-boot}/content/ContentEngineAutoConfiguration.java[ContentEngineAutoConfiguration] -|{sc-flowable-boot}/content/ContentEngineServicesAutoConfiguration.java[ContentEngineServicesAutoConfiguration] -|{sc-flowable-boot}/cmmn/CmmnEngineAutoConfiguration.java[CmmnEngineAutoConfiguration] -|{sc-flowable-boot}/cmmn/CmmnEngineServicesAutoConfiguration.java[CmmnEngineServicesAutoConfiguration] -|{sc-flowable-boot}/dmn/DmnEngineAutoConfiguration.java[DmnEngineAutoConfiguration] -|{sc-flowable-boot}/dmn/DmnEngineServicesAutoConfiguration.java[DmnEngineServicesAutoConfiguration] -|{sc-flowable-boot}/EndpointAutoConfiguration.java[EndpointAutoConfiguration] -|{sc-flowable-boot}/actuate/info/FlowableInfoAutoConfiguration.java[FlowableInfoAutoConfiguration] -|{sc-flowable-boot}/ldap/FlowableLdapAutoConfiguration.java[FlowableLdapAutoConfiguration] -|{sc-flowable-boot}/FlowableTransactionAutoConfiguration.java[FlowableTransactionAutoConfiguration] -|{sc-flowable-boot}/form/FormEngineAutoConfiguration.java[FormEngineAutoConfiguration] -|{sc-flowable-boot}/form/FormEngineServicesAutoConfiguration.java[FormEngineServicesAutoConfiguration] -|{sc-flowable-boot}/idm/IdmEngineAutoConfiguration.java[IdmEngineAutoConfiguration] -|{sc-flowable-boot}/idm/IdmEngineServicesAutoConfiguration.java[IdmEngineServicesAutoConfiguration] -|{sc-flowable-boot}/ProcessEngineAutoConfiguration.java[ProcessEngineAutoConfiguration] -|{sc-flowable-boot}/RestApiAutoConfiguration.java[RestApiAutoConfiguration] -|{sc-flowable-boot}/SecurityAutoConfiguration.java[SecurityAutoConfiguration] - -|=== - -[[springBootFlowableStarter]] -==== Flowable Starter - -这是Flowable Spring Boot stater的列表。 - -[cols=2*,options="header"] -|=== -|Starter -|描述 - -|{sc-flowable-starter}/flowable-spring-boot-starter-cmmn/pom.xml[flowable-spring-boot-starter-cmmn] -|提供以独立运行模式启动CMMN引擎的依赖 - -|{sc-flowable-starter}/flowable-spring-boot-starter-cmmn-rest/pom.xml[flowable-spring-boot-starter-cmmn-rest] -|提供以独立运行模式启动CMMN引擎,并提供其REST API的依赖。 - -|{sc-flowable-starter}/flowable-spring-boot-starter-dmn/pom.xml[flowable-spring-boot-starter-dmn] -|提供以独立运行模式启动DMN引擎的依赖。 - -|{sc-flowable-starter}/flowable-spring-boot-starter-dmn-rest/pom.xml[flowable-spring-boot-starter-dmn-rest] -|提供以独立运行模式启动DMN引擎,并提供其REST API的依赖。 - -|{sc-flowable-starter}/flowable-spring-boot-starter-process/pom.xml[flowable-spring-boot-starter-process] -|提供以独立运行模式启动流程引擎的依赖。 - -|{sc-flowable-starter}/flowable-spring-boot-starter-process-rest/pom.xml[flowable-spring-boot-starter-process-rest] -|提供以独立运行模式启动流程引擎,并提供其REST API的依赖。 - -|{sc-flowable-starter}/flowable-spring-boot-starter/pom.xml[flowable-spring-boot-starter] -|提供启动所有Flowable引擎(流程,CMMN,DMN,Form,Content及IDM)的依赖。 - -|{sc-flowable-starter}/flowable-spring-boot-starter-rest/pom.xml[flowable-spring-boot-starter-rest] -|提供启动所有Flowable引擎,并提供其REST API的依赖。 - -|{sc-flowable-starter}/flowable-spring-boot-starter-actuator/pom.xml[flowable-spring-boot-starter-actuator] -|提供Spring Boot Actuator所需的依赖。 - -|=== - - -[[_using_liquibase]] -==== 使用Liquibase - -Flowable引擎使用Liquibase管理数据库版本。 -因此Spring Boot的 `LiquibaseAutoConfiguration` 会自动启用。 -然而,如果你并未使用Liquibase,则应用将无法启动,并抛出异常。 -因此Flowable将 `spring.liquibase.enabled` 设置为 `false` ,也即如果需要使用Liquibase,则需手动启用它。 - -[[_further_reading]] -==== 扩展阅读 - -很明显还有很多Spring Boot相关的内容还没有提及,如非常简单的JTA集成、构建能在主流应用服务器上运行的WAR文件。也还有很多Spring Boot集成: - -* Actuator支持 -* Spring Integration支持 -* Rest API集成:启动Spring应用中嵌入的Flowable Rest API -* Spring Security支持 - -[[_advanced_configuration]] -==== 高级配置 - -[[_customizing_engine_configuration]] -===== 自定义引擎配置 - -实现__org.flowable.spring.boot.EngineConfigurationConfigurer__接口,可以获取引擎配置对象。其中__T__是具体引擎配置的Spring类型。 -这样可以在参数尚未公开时,进行高级配置,或简化配置。 -例如: - -[source, java, linenums] ----- -public class MyConfigurer implements EngineConfigurationConfigurer { - - public void configure(SpringProcessEngineConfiguration processEngineConfiguration) { - // advanced configuration - } - -} ----- - -在Spring Boot配置中使用__@Bean__发布该类的实例,这样配置类会在流程引擎创建前调用。 - -[TIP] -==== -可以用这种方法实现自定义的Flowable服务。参见 {sc-flowable-boot}/ldap/FlowableLdapAutoConfiguration.java[FlowableLdapAutoConfiguration] -==== - -[[_combining_starters]] -===== 整合starter - -如果需要一组引擎,则只能依次添加依赖。 -比如要使用流程、CMMN、Form与IDM引擎,并使用LDAP,则需要添加这些依赖: - -[source,xml,linenums] ----- - - org.flowable - flowable-spring-boot-starter-process - ${flowable.version} - - - org.flowable - flowable-spring-boot-starter-cmmn - ${flowable.version} - - - org.flowable - flowable-content-spring-configurator - ${flowable.version} - - - org.flowable - flowable-ldap - ${flowable.version} - ----- - -[[_configuring_async_executors]] -===== 配置异步执行器 - -流程及CMMN引擎使用专门的 `AsyncExecutor` ,并可使用 `flowable.{engine}.async.executor` 参数组进行配置。 -其中 `engine` 代表 `process` 或 `cmmn` 。 - -默认情况下, `AsyncExecutor` 共享同一个Spring `TaskExecutor` 及 `SpringRejectedJobsHandler` 。 -如果需要为引擎提供专门的执行器,则需要使用 `@Process` 及 `@Cmmn` 定义的bean。 - -可以使用如下方法配置自定义的执行器: - -[source,java,linenums] ----- -@Configuration -public class MyConfiguration { - - @Process <1> - @Bean - public TaskExecutor processTaskExecutor() { - return new SimpleAsyncTaskExecutor(); - } - - @Cmmn <2> - @Bean - public TaskExecutor cmmnTaskExecutor() { - return new SyncTaskExecutor(); - } -} ----- -<1> 流程引擎将使用 `SimpleAsyncTaskExecutor` 作为异步执行器 -<2> CMMN引擎将使用 `SyncTaskExecutor` 作为异步执行器 - -[IMPORTANT] -====== -如果使用了自定义的 `TaskExecutor` bean,则Flowable将不会再创建自己的bean。 -也就是说如果使用 `@Process` 定义了bean,也需要使用 `@Cmmn` 或 `@Primary` 再定义一个bean。否则Cmmn异步执行器将使用流程引擎所用的bean。 -====== - diff --git a/docs/userguide/src/zh_CN/bpmn/ch06-Deployment.adoc b/docs/userguide/src/zh_CN/bpmn/ch06-Deployment.adoc deleted file mode 100755 index b5471ccd01f..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch06-Deployment.adoc +++ /dev/null @@ -1,205 +0,0 @@ -[[chDeployment]] - -== 部署 - -[[_business_archives]] -=== 业务存档 - -要部署流程,需要将它们包装在业务存档(BAR, Business archive)里。业务存档是Flowable引擎的部署单元,也就是一个ZIP文件。可以包含BPMN 2.0流程、表单定义、DMN规则,与其他类型的文件。总的来说,业务存档包含一组具名资源。 - -当部署业务存档时,会扫描具有++.bpmn20.xml++或++.bpmn++扩展名的BPMN文件。每一个这种文件都会被处理,并可以包含多个流程定义。 -当启用DMN引擎时,也会解析++.dmn++。当启用表单引擎时,会处理++.form++文件。 - -[NOTE] -==== -业务存档中的Java类**不会添加至classpath**。业务存档中,所有流程定义使用的自定义类(例如Java服务任务或者事件监听器),都需要放在运行流程的flowable引擎的classpath内。 -==== - -[[_deploying_programmatically]] -==== 编程方式部署 - -从ZIP文件部署业务存档,可以这样做: - -[source,java,linenums] ----- -String barFileName = "path/to/process-one.bar"; -ZipInputStream inputStream = new ZipInputStream(new FileInputStream(barFileName)); - -repositoryService.createDeployment() - .name("process-one.bar") - .addZipInputStream(inputStream) - .deploy(); - ----- - -也可以为单个资源构建部署。查看javadoc以获取更多信息。 - -[[_external_resources]] -=== 外部资源 - -流程定义保存在Flowable数据库中。这些流程定义在使用服务任务、执行监听器,或执行Flowable配置文件中定义的Spring bean时,可以引用委托类。这些类及Spring配置文件都需要在可能运行这个流程定义的流程引擎中可用。 - -[[_java_classes]] -==== Java类 - -在流程启动时,引擎的classpath中需要有所有流程中用到的自定义类(例如服务任务、事件监听器、任务监听器等中用到的JavaDelegate)。 - -但是在部署业务存档时,classpath中可以没有这些类。这意味着,比如使用Ant部署新业务存档时,代理类不必提前放在classpath中。 - -当使用演示配置且希望添加自定义类时,需要在flowable-task或flowable-rest的webapp lib中,添加包含有你的自定义类的JAR。别忘了也要添加你的自定义类的依赖(若有)。或者,也可以将你的依赖添加到Tomcat的库文件夹++${tomcat.home}/lib++中。 - -[[_using_spring_beans_from_a_process]] -==== 在流程中使用Spring bean - -在表达式或脚本中使用Spring bean时,执行该流程定义的引擎需要可以使用这些bean。可以简单直接地自行构建web应用,并按照<>章节的介绍在上下文中配置流程引擎。但也请牢记在心,如果使用Flowable task和rest web应用,就需要更新它的上下文配置。 - -[[_creating_a_single_app]] -==== 创建单独应用 - -如果不想费心在所有流程引擎的classpath中都包含所有需要的代理类,及保证它们都使用了正确的Spring配置,也可以考虑将Flowable rest web应用嵌入你自己的web应用。也就是说只使用一个单独的++ProcessEngine++。 - - -[[versioningOfProcessDefinitions]] - -=== 流程定义的版本 - -BPMN并没有版本的概念。这其实很好,因为可执行的BPMN流程文件很可能已经作为开发项目的一部分,保存在版本管理系统仓库中了(例如Subversion,Git,或者Mercurial)。但是,作为部署过程的一部分,引擎会创建流程定义的版本。在部署时,Flowable会在保存至Flowable数据库前,为++ProcessDefinition++指定版本。 - -对于业务存档中的每个流程定义,为了初始化++key++、++version++、++name++与++id++参数,会执行下列步骤: - -* XML文件中的流程定义++id++属性用作流程定义的++key++参数。 -* XML文件中的流程定义++name++属性用作流程定义的++name++参数。如果未给定++name++属性,会使用id作为name。 -* 当每个key的流程第一次部署时,指定版本为1。对其后所有使用相同key的流程定义,部署时版本会在该key当前已部署的最高版本号基础上加1。key参数用于区分流程定义。 -* id参数设置为{processDefinitionKey}:{processDefinitionVersion}:{generated-id},其中++generated-id++是一个唯一数字,用以保证在集群环境下,流程定义缓存中,流程id的唯一性。 - -以下面的流程为例 - -[source,xml,linenums] ----- - - - ... ----- - -当部署这个流程定义时,数据库中的流程定义会是这个样子: - -[options="header"] -|=============== -|id|key|name|version -|myProcess:1:676|myProcess|My important process|1 - -|=============== - -如果我们现在部署同一个流程的更新版本(例如修改部分用户任务),且保持流程定义的++id++不变,那么流程定义表中会包含下面的记录: - - -[options="header"] -|=============== -|id|key|name|version -|myProcess:1:676|myProcess|My important process|1 -|myProcess:2:870|myProcess|My important process|2 - -|=============== - -当调用++runtimeService.startProcessInstanceByKey("myProcess")++时,会使用版本++2++的流程定义,因为这是这个流程定义的最新版本。 - -如果再创建第二个流程,如下定义并部署至Flowable,表中会增加第三行。 - -[source,xml,linenums] ----- - - - ... ----- - -表数据类似: - -[options="header"] -|=============== -|id|key|name|version -|myProcess:1:676|myProcess|My important process|1 -|myProcess:2:870|myProcess|My important process|2 -|myNewProcess:1:1033|myNewProcess|My important process|1 - -|=============== - -请注意新流程的key与第一个流程的key不同。即使name是相同的(我们也可以修改它),Flowable也只用++id++属性来区分流程。因此新的流程部署时版本为1. - - -[[providingProcessDiagram]] - - -=== 提供流程图 - -可以在部署中添加流程图片。这个图片将存储在Flowable数据库中,并可以使用API访问。图片可以用在Flowable应用中,使流程可视化。 - -如果在classpath中,有一个++org/flowable/expenseProcess.bpmn20.xml++流程,key为'expense'。则流程图片会使用下列命名约定(按顺序): - -* 如果部署中有图片资源,并且文件名包含BPMN 2.0 XML流程定义文件名以及流程key,并具有图形格式,则使用这个图片。在我们的例子中,就是++org/flowable/expenseProcess.expense.png++(或者.jpg/gif)。使用key的原因是,一个BPMN 2.0 XML文件中可以有多个流程定义。因此使用流程key区分每一个流程图的文件。 -* 如果没有这种图片,就会寻找部署中匹配BPMN 2.0 XML文件名的图片资源。在我们的例子中,就是++org/flowable/expenseProcess.png++。请注意,这意味着同一个BPMN 2.0文件中的**每一个流程定义**,都会使用同一个流程图图片。当然,如果每个BPMN 2.0 XML文件中都只有一个流程定义,就没有问题。 - - -用编程方式部署的例子: - -[source,java,linenums] ----- - -repositoryService.createDeployment() - .name("expense-process.bar") - .addClasspathResource("org/flowable/expenseProcess.bpmn20.xml") - .addClasspathResource("org/flowable/expenseProcess.png") - .deploy(); ----- - - -图片资源可用下面的API获取: - -[source,java,linenums] ----- -ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() - .processDefinitionKey("expense") - .singleResult(); - -String diagramResourceName = processDefinition.getDiagramResourceName(); -InputStream imageStream = repositoryService.getResourceAsStream( - processDefinition.getDeploymentId(), diagramResourceName); ----- - - -[[generatingProcessDiagram]] - - -=== 生成流程图 - -如果部署时没有按<>介绍的方式提供图片,且流程定义中包含必要的“图形交换(diagram interchange)”信息,Flowable引擎会生成流程图。 - -可以用与部署时<>完全相同的方法获取图片资源。 - -image::images/deployment.image.generation.png[align="center"] - -如果不需要或不希望在部署时生成流程图,可以在流程引擎配置中设置++isCreateDiagramOnDeploy++参数: - -[source,xml,linenums] ----- - ----- - -这样就不会生成流程图了。 - -[[deploymentCategory]] - - -=== 类别 - -部署与流程定义都可以自定义类别。流程定义的类别使用BPMN文件中targetNamespace的值设置:++++。 - -部署的类别也可用API如此设定: - -[source,java,linenums] ----- -repositoryService - .createDeployment() - .category("yourCategory") - ... - .deploy(); ----- diff --git a/docs/userguide/src/zh_CN/bpmn/ch07a-BPMN-Introduction.adoc b/docs/userguide/src/zh_CN/bpmn/ch07a-BPMN-Introduction.adoc deleted file mode 100755 index ce048a058e9..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch07a-BPMN-Introduction.adoc +++ /dev/null @@ -1,421 +0,0 @@ -[[bpmn20]] - -== BPMN 2.0介绍 - -[[whatIsBpmn]] - - -=== BPMN是什么? - -BPMN是一个广泛接受与支持的,展现流程的注记方法。link:$$http://www.bpmn.org/$$[OMG BPMN标准]. - -[[bpmnDefiningProcess]] - - -=== 定义流程 - - -[NOTE] -==== -本篇文档假设你使用link:$$http://eclipse.org/$$[Eclipse IDE]创建与编辑文件。但其实文档中只有少数几处使用了Eclipse的特性。你可以使用喜欢的任何其他工具创建BPMN 2.0 XML文件。 - -==== - -创建一个新的XML文件(__在任意项目上右击,选择New->Other->XML-XML File__)并命名。确保该文件名**以.bpmn20.xml或.bpmn结尾**,否则引擎不会在部署时使用这个文件。 - -image::images/new.bpmn.procdef.png[align="center"] - -BPMN 2.0概要(schema)的根元素(root element)是++definitions++元素。在这个元素中,可以定义多个流程定义(然而我们建议在每个文件中,只有一个流程定义。这样可以简化之后的部署过程)。下面给出的是一个空流程定义。请注意++definitions++元素最少需要包含++xmlns++与++targetNamespace++声明。++targetNamespace++可以为空,它用于对流程定义进行分类。 - -[source,xml,linenums] ----- - - - - .. - - - ----- - -除了使用Eclipse中的XML分类选项,也可以使用在线概要作为BPMN 2.0 XML概要。 - - -[source,xml,linenums] ----- -xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" -xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL - http://www.omg.org/spec/BPMN/2.0/20100501/BPMN20.xsd ----- - - -++process++元素有两个属性: - -* *id*: **必填**属性,将映射为Flowable ++ProcessDefinition++对象的**key**参数。可以使用++RuntimeService++中的++startProcessInstanceByKey++方法,使用++id++来启动这个流程定义的新流程实例。这个方法总会使用流程定义的**最新部署版本**。 - - -[source,java,linenums] ----- -ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myProcess"); ----- - -* 请注意这与调用++startProcessInstanceById++方法不同。++startProcessInstanceById++方法的参数为Flowable引擎在部署时生成的字符串ID(可以通过调用++processDefinition.getId()++方法获取)。生成ID的格式为**'key:version'**,长度**限制为64字符**。请注意限制流程__key__的长度,否则会抛出++FlowableException++异常,提示生成的ID过长。 -* *name*: **可选**属性,将映射为++ProcessDefinition++的__name__参数。引擎本身不会使用这个参数。可以用于在用户界面上显示更友好的名字。 - - -[[bpmn10minutetutorial]] - - -=== 开始:十分钟教程 - -这个章节包含了一个很简单的业务流程,用于介绍一些基本的Flowable概念以及Flowable API。 - - -[[bpmn10MinuteTutorialPrerequisites]] - - -==== 必要条件 - -这个教程需要你已经<>,并使用独立的H2服务器。编辑++db.properties++并设置++jdbc.url=jdbc:h2:tcp://localhost/flowable++,然后按照link:$$http://www.h2database.com/html/tutorial.html#using_server$$[H2文档]的介绍运行独立服务器。 - - -[[bpmn10MinuteTutorialGoal]] - - -==== 目标 - -这个教程的目标是学习Flowable以及BPMN 2.0的一些基础概念。最后成果是一个简单的Java SE程序,部署了一个流程定义,并可以通过Flowable引擎API与流程进行交互。当然,在这个教程里学到的东西,也可以按照你的业务流程用于构建你自己的web应用程序。 - - -[[bpmnFirstExampleUseCase]] - - -==== 用例 - -用例很简单:有一个公司,叫做BPMCorp。在BPMCorp中,由会计部门负责,每月需要为投资人撰写一份报告。在报告完成后,需要高层经理中的一人进行审核,然后才能发给所有投资人。 - - -[[bpmnFirstExampleDiagram]] - - -==== 流程图 - -上面描述的业务流程可以使用<>直接画出。但是在这个教程里我们自己写XML,这样可以学习更多。这个流程的图形化BPMN 2.0注记像是这样: - -image::images/financial.report.example.diagram.png[align="center"] - -我们看到的是一个<>(左边的圆圈),接下来是两个<>:__'Write monthly financial report(撰写月度财务报告)'__与__'Verify monthly financial report(审核月度财务报告)'__。最后是<>(右边的粗线条圆圈)。 - - -[[bpmnFirstExampleXml]] - - -==== XML格式 - -这个业务流程的XML版本(__FinancialReportProcess.bpmn20.xml__)在下面展示。很容易认出流程的主要元素(点击链接可以跳转到BPMN 2.0结构的详细章节): - -* <>是流程的__入口点(entry point)__。 -* <>表示流程中的人工任务。请注意第一个任务分配给__accountancy__组,而第二个任务分配给__management__组。查看<>章节了解更多关于用户与组如何分配用户任务的信息。 -* 流程在到达<>时结束。 -* 各元素间通过<>链接。顺序流用++source++ 与++target++定义顺序流的__流向(direction)__。 - -[source,xml,linenums] ----- - - - - - - - - - - - Write monthly financial report for publication to shareholders. - - - - accountancy - - - - - - - - - Verify monthly financial report composed by the accountancy department. - This financial report is going to be sent to all the company shareholders. - - - - management - - - - - - - - - - - ----- - - -[[bpmnFirstExamplStartProcess]] - - -==== 启动流程实例 - -现在我们已经创建了业务流程的**流程定义**。使用这样的流程定义,可以创建**流程实例**。在这个例子中,一个流程实例将对应某一月份的财经报告创建与审核工作。所有月份的流程实例共享相同的流程定义。 - -要用给定的流程定义创建流程实例,需要首先**部署(deploy)**流程定义。部署流程定义意味着两件事: - -* 流程定义将会存储在Flowable引擎配置的持久化数据库中。因此部署业务流程保证了引擎在重启后也能找到流程定义。 -* BPMN 2.0流程XML会解析为内存中的对象模型,供Flowable API使用。 - -更多关于部署的信息可以在<>章节中找到。 - -与该章节的描述一样,部署有很多种方式。其中一种是通过下面展示的API。请注意所有与Flowable引擎的交互都要通过它的__服务(services)__进行。 - -[source,java,linenums] ----- -Deployment deployment = repositoryService.createDeployment() - .addClasspathResource("FinancialReportProcess.bpmn20.xml") - .deploy(); ----- - -现在可以使用在流程定义中定义的++id++(参见XML中的process元素)启动新流程实例。请注意这个++id++在Flowable术语中被称作**key**。 - -[source,java,linenums] ----- -ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("financialReport"); ----- - -这会创建流程实例,并首先通过开始事件。在开始事件后,会沿着所有出口顺序流(在这个例子中只有一个)继续执行,并到达第一个任务('write monthly financial report 撰写月度财务报告')。这时,Flowable引擎会在持久化数据库中存储一个任务。同时也会解析并保存这个任务附加的分配用户或组。请注意,Flowable引擎会持续执行流程,直到到达__等待状态(wait state)__,例如用户任务。在等待状态,流程实例的当前状态会存储在数据库中并保持,直到用户决定完成任务。这时,引擎会继续执行,直到遇到新的等待状态,或者流程结束。如果在这期间引擎重启或崩溃,流程的状态也仍在数据库中安全的保存。 - -用户任务活动是一个__等待状态__,因此++startProcessInstanceByKey++方法会在任务创建后返回。在这个例子里,这个任务分配给一个组。这意味着这个组的每一个成员都是处理这个任务的**候选人(candidate)**。 - -现在可以将前面这些东西整合起来,构造一个简单的Java程序。创建一个新的Eclipse项目,在它的classpath中添加Flowable JAR与依赖(可以在Flowable发行版的__libs__目录下找到)。在调用Flowable服务前,需要首先构建++ProcessEngine++,用于访问服务。这里我们使用__'独立(standalone)'__配置,这个配置会构建++ProcessEngine++,并使用与演示配置中相同的数据库。 - -可以从link:$$images/FinancialReportProcess.bpmn20.xml$$[这里]下载流程定义XML。这个文件包含了上面展示的XML,同时包含了必要的BPMN<>,用于在Flowable的工具中可视化地展示流程。 - -[source,java,linenums] ----- -public static void main(String[] args) { - - // 创建Flowable流程引擎 - ProcessEngine processEngine = ProcessEngineConfiguration - .createStandaloneProcessEngineConfiguration() - .buildProcessEngine(); - - // 获取Flowable服务 - RepositoryService repositoryService = processEngine.getRepositoryService(); - RuntimeService runtimeService = processEngine.getRuntimeService(); - - // 部署流程定义 - repositoryService.createDeployment() - .addClasspathResource("FinancialReportProcess.bpmn20.xml") - .deploy(); - - // 启动流程实例 - runtimeService.startProcessInstanceByKey("financialReport"); -} ----- - - -[[bpmnFirstExampleCandidateList]] - -==== 任务列表 - -现在可以通过如下代码获取这个任务: - -[source,java,linenums] ----- -List tasks = taskService.createTaskQuery().taskCandidateUser("kermit").list(); ----- - -请注意传递给这个操作的用户需要是__accountancy__组的成员,因为在流程定义中是这么声明的: - -[source,xml,linenums] ----- - - - accountancy - - ----- - -也可以使用任务查询API,用组名查得相同结果。可以在代码中添加下列逻辑: - -[source,java,linenums] ----- -TaskService taskService = processEngine.getTaskService(); -List tasks = taskService.createTaskQuery().taskCandidateGroup("accountancy").list(); ----- - -因为我们使用与演示配置中相同的数据库配置++ProcessEngine++,因此可以直接登录link:$$http://localhost:8080/flowable-idm/$$[Flowable IDM]。使用admin/test登录,创建两个新用户__kermit__与__fozzie__,并将__Access the workflow application(访问工作流应用)__权限授予他们。然后创建两个组,命名为__accountancy__与__management__,并将fozzie添加至accountancy组,将kermit添加至management组。 -然后以fozzie登录link:$$http://localhost:8080/flowable-task/$$[Flowable task]应用。选择Task应用,再选择其__Processes__页面,选择__'Monthly financial report (月度财务报告)'__,这样就可以启动我们的业务流程。 - - -image::images/bpmn.financial.report.example.start.process.png[align="center"] - -前面已经解释过,流程会执行直到第一个用户任务。因为登录为fozzie,所以可以看到在启动流程实例后,他有一个新的候选任务(candidate task)。选择__Task__页面来查看这个新任务。请注意即使流程是由其他人启动的,accountancy组中的每一个人仍然都能看到这个候选任务。 - - -image::images/bpmn.financial.report.example.task.assigned.png[align="center"] - -[[bpmnFirstExampleClaimTask]] - - -==== 申领任务 - -会计师(accountancy组的成员)现在需要**申领任务(claim)**。申领任务后,这个用户会成为任务的**执行人(assignee)**,这个任务也会从accountancy组的其他成员的任务列表中消失。可以通过如下代码实现申领任务: - - -[source,java,linenums] ----- -taskService.claim(task.getId(), "fozzie"); ----- - -这个任务现在在**申领任务者的个人任务列表中**。 - -[source,java,linenums] ----- -List tasks = taskService.createTaskQuery().taskAssignee("fozzie").list(); ----- - -在Flowable Task应用中,点击__claim__按钮会执行相同操作。这个任务会转移到登录用户的个人任务列表中。也可以看到任务执行人变更为当前登录用户。 - -image::images/bpmn.financial.report.example.claim.task.png[align="center"] - - - -[[bpmnFirstExampleCompleteTask]] - - -==== 完成任务 - -会计师(accountancy组的成员)现在需要开始撰写财务报告了。完成报告后,他就可以**完成任务(complete)**,代表任务的所有工作都已完成。 - -[source,java,linenums] ----- -taskService.complete(task.getId()); ----- - -对于Flowable引擎来说,这是个外部信号,指示流程实例可以继续执行。Flowable会从运行时数据中移除任务,并沿着这个任务唯一的出口转移线(outgoing transition),将执行移至第二个任务(__'verification of the report 审核报告'__)。为第二个任务分配执行人的机制,与上面介绍的第一个任务使用的机制相同。唯一的区别是这个任务会分配给__management__组。 - -在演示设置中,完成任务可以通过点击任务列表中的__complete__按钮。因为Fozzie不是经理,我们需要登出Flowable Task应用,并用__kermit__(他是经理)登录。这样就可以在未分配任务列表中看到第二个任务。 - - -[[bpmnFirstExampleEndingProcess]] - - -==== 结束流程 - -可以使用与之前完全相同的方式获取并申领审核任务。完成这个第二个任务会将流程执行移至结束事件,并结束流程实例。这个流程实例,及所有相关的运行时执行数据都会从数据库中移除。 - -也可以通过编程方式,使用++historyService++验证流程已经结束 - -[source,java,linenums] ----- -HistoryService historyService = processEngine.getHistoryService(); -HistoricProcessInstance historicProcessInstance = -historyService.createHistoricProcessInstanceQuery().processInstanceId(procId).singleResult(); -System.out.println("Process instance end time: " + historicProcessInstance.getEndTime()); ----- - -[[bpmnFirstExampleCode]] - - -==== 代码总结 - -将之前章节的所有代码片段整合起来,会得到类似这样的代码。这段代码考虑到了你可能已经使用Flowable UI应用启动了一些流程实例。代码中总是获取任务列表而不是一个任务,因此可以正确执行: - -[source,java,linenums] ----- -public class TenMinuteTutorial { - - public static void main(String[] args) { - - // 创建Flowable流程引擎 - ProcessEngine processEngine = ProcessEngineConfiguration - .createStandaloneProcessEngineConfiguration() - .buildProcessEngine(); - - // 获取Flowable服务 - RepositoryService repositoryService = processEngine.getRepositoryService(); - RuntimeService runtimeService = processEngine.getRuntimeService(); - - // 部署流程定义 - repositoryService.createDeployment() - .addClasspathResource("FinancialReportProcess.bpmn20.xml") - .deploy(); - - // 启动流程实例 - String procId = runtimeService.startProcessInstanceByKey("financialReport").getId(); - - // 获取第一个任务 - TaskService taskService = processEngine.getTaskService(); - List tasks = taskService.createTaskQuery().taskCandidateGroup("accountancy").list(); - for (Task task : tasks) { - System.out.println("Following task is available for accountancy group: " + task.getName()); - - // 申领任务 - taskService.claim(task.getId(), "fozzie"); - } - - // 验证Fozzie获取了任务 - tasks = taskService.createTaskQuery().taskAssignee("fozzie").list(); - for (Task task : tasks) { - System.out.println("Task for fozzie: " + task.getName()); - - // 完成任务 - taskService.complete(task.getId()); - } - - System.out.println("Number of tasks for fozzie: " - + taskService.createTaskQuery().taskAssignee("fozzie").count()); - - // 获取并申领第二个任务 - tasks = taskService.createTaskQuery().taskCandidateGroup("management").list(); - for (Task task : tasks) { - System.out.println("Following task is available for management group: " + task.getName()); - taskService.claim(task.getId(), "kermit"); - } - - // 完成第二个任务并结束流程 - for (Task task : tasks) { - taskService.complete(task.getId()); - } - - // 验证流程已经结束 - HistoryService historyService = processEngine.getHistoryService(); - HistoricProcessInstance historicProcessInstance = - historyService.createHistoricProcessInstanceQuery().processInstanceId(procId).singleResult(); - System.out.println("Process instance end time: " + historicProcessInstance.getEndTime()); - } - -} ----- - - -[[bpmnFirstExampleFutureEnhancements]] - - -==== 后续增强 - -可以看出这个业务流程太简单了,不能实际使用。但只要继续学习Flowable中可用的BPMN 2.0结构,就可以通过以下元素增强业务流程: - -* 定义**网关(gateway)**使经理可以选择:驳回财务报告,并重新为会计师创建任务;或者接受报告。 -* 定义并使用**变量(variables)**存储或引用报告,并可以在表单中显示它。 -* 在流程结束处定义**服务任务(service task)**,将报告发送给每一个投资人。 -* 等等。 diff --git a/docs/userguide/src/zh_CN/bpmn/ch07b-BPMN-Constructs.adoc b/docs/userguide/src/zh_CN/bpmn/ch07b-BPMN-Constructs.adoc deleted file mode 100755 index bb447f23ee9..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch07b-BPMN-Constructs.adoc +++ /dev/null @@ -1,5292 +0,0 @@ -[[bpmnConstructs]] - -== BPMN 2.0结构 - -本章节介绍Flowable支持的BPMN 2.0结构,以及Flowable对BPMN标准的自定义扩展。 - - -[[bpmnCustomExtensions]] - - -=== 自定义扩展 - -BPMN 2.0标准对流程的所有的参与者都很有用。最终用户不会因为依赖专有解决方案,而被供应商“绑架”。Flowable之类的开源框架,也可以提供与大型供应商的解决方案相同(经常是更好;-)的实现。有了BPMN 2.0标准,从大型供应商解决方案向Flowable的迁移,可以十分简单平滑。 - -缺点则是标准通常是不同公司(不同观点)大量讨论与妥协的结果。作为阅读BPMN 2.0 XML流程定义的开发者,有时会觉得某些结构或方法十分笨重。Flowable将开发者的感受放在最高优先,因此引入了一些**'Flowable BPMN扩展(extensions)'**。这些“扩展”并不在BPMN 2.0规格中,有些是新结构,有些是对特定结构的简化。 - -尽管BPMN 2.0规格明确指出可以支持自定义扩展,我们仍做了如下保证: - -* 自定义扩展**保证是**在**标准方式**的基础上进行简化。因此当你决定使用自定义扩展时,不用担心无路可退(仍然可以用标准方式)。 -* 使用自定义扩展时,总是通过**flowable:**命名空间前缀,明确标识出XML元素、属性等。请注意Flowable引擎也支持**activiti:**命名空间前缀。 - -因此是否使用自定义扩展,完全取决于你自己。有些其他因素会影响选择(图形化编辑器的使用,公司策略,等等)。我们提供扩展,只是因为相信标准中的某些地方可以用更简单或效率更高的方式处理。请不要吝啬给我们反馈你对扩展的评价(正面的或负面的),也可以给我们提供关于自定义扩展的新想法。说不定某一天,你的想法会成为标准的一部分! - - -[[bpmnEvents]] - -=== 事件 - -事件(event)通常用于为流程生命周期中发生的事情建模。事件总是图形化为圆圈。在BPMN 2.0中,有两种主要的事件分类:__捕获(catching)__与__抛出(throwing)__事件。 - -* **捕获:** 当流程执行到达这个事件时,会等待直到触发器动作。触发器的类型由其中的图标,或者说XML中的类型声明而定义。捕获事件与抛出事件显示上的区别,是其内部的图标没有填充(即是白色的)。 -* **抛出:** 当流程执行到达这个事件时,会触发一个触发器。触发器的类型,由其中的图标,或者说XML中的类型声明而定义。抛出事件与捕获事件显示上的区别,是其内部的图标填充为黑色。 - -[[eventDefinitions]] - - -==== 事件定义 - -事件定义(event definition),用于定义事件的语义。没有事件定义的话,事件就“不做什么特别的事情”。例如,一个没有事件定义的开始事件,并不限定具体是什么启动了流程。如果为这个开始事件添加事件定义(例如定时器事件定义),就声明了启动流程的“类型”(例如对于定时器事件定义,就是到达了特定的时间点)。 - - -[[timerEventDefinitions]] - - -==== 定时器事件定义 - -定时器事件(timer event definition),是由定时器所触发的事件。可以用于<>,<>,或<>。定时器事件的行为取决于所使用的业务日历(business calendar)。定时器事件有默认的业务日历,但也可以为每个定时器事件定义,单独定义业务日历。 - - -[source,xml,linenums] ----- - - ... - ----- - -其中businessCalendarName指向流程引擎配置中的业务日历。如果省略业务日历定义,则使用默认业务日历。 - -定时器定义必须且只能包含下列的一种元素: - -* **timeDate**。这个元素指定了link:$$http://en.wikipedia.org/wiki/ISO_8601#Dates$$[ISO 8601]格式的固定时间。在这个时间就会触发触发器。例如: - -[source,xml,linenums] ----- - - 2011-03-11T12:13:14 - ----- - -* **timeDuration**。要定义定时器需要等待多长时间再触发,可以用__timerEventDefinition__的子元素__timeDuration__。使用link:$$http://en.wikipedia.org/wiki/ISO_8601#Durations$$[ISO 8601]格式(BPMN 2.0规范要求)。例如(等待10天): - -[source,xml,linenums] ----- - - P10D - ----- - -* **timeCycle**。指定重复周期,可用于周期性启动流程,或者为超期用户任务多次发送提醒。这个元素可以使用两种格式。第一种是按照link:$$http://en.wikipedia.org/wiki/ISO_8601#Repeating_intervals$$[ISO 8601]标准定义的循环时间周期。例如(三次重复间隔,每次间隔为10小时): - -* 也可以使用__timeCycle__的可选属性__endDate__,或者像这样直接写在时间表达式的结尾:++R3/PT10H/${EndDate}++。 -当到达endDate时,应用会停止,并为该任务创建其他作业。 -可以使用link:$$http://en.wikipedia.org/wiki/ISO_8601#Dates$$[ISO 8601]标准的常量,如__"2015-02-25T16:42:11+00:00"__。也可以使用变量,如__${EndDate}__ - - -[source,xml,linenums] ----- - - R3/PT10H - ----- - -[source,xml,linenums] ----- - - R3/PT10H/${EndDate} - ----- - -如果同时使用了两种格式,则系统会使用以属性方式定义的endDate。 - -目前只有__BoundaryTimerEvents__与__CatchTimerEvent__可以使用__EndDate__。 - -另外,也可以使用cron表达式指定定时周期。下面的例子展示了一个整点启动,每5分钟触发的触发器: - - ----- -0 0/5 * * * ? ----- - - -请参考link:$$http://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html$$[这个教程]了解如何使用cron表达式。 - -**请注意:** 与普通的Unix cron不同,第一个符号代表的是秒,而不是分钟。 - -重复时间周期更适合使用相对时间,也就是从某个特定时间点开始计算(比如用户任务开始的时间)。而cron表达式可以使用绝对时间,因此更适合用于<>。 - -可以在定时事件定义中使用表达式,也就是使用流程变量控制定时。这个流程变量必须是包含合适时间格式的字符串,ISO 8601(或者对于循环类型,cron)。 - -[source,xml,linenums] ----- - - - ${duration} - - ----- - -**请注意:**定时器只有在异步执行器启用时才能触发(需要在++flowable.cfg.xml++中,将__asyncExecutorActivate__设置为++true++。因为默认情况下异步执行器都是禁用的)。 - - - -[[bpmnErrorEventDefinition]] - - -==== 错误事件定义 - -(error event definition) - -**重要提示:** BPMN错误与Java异常**不**是一回事。事实上,这两者毫无共同点。BPMN错误事件是建模__业务异常(business exceptions)__的方式。而Java异常会按<>处理。 - -[source,xml,linenums] ----- - - - - ----- - -[[bpmnSignalEventDefinition]] - - -==== 信号事件定义 - -信号事件(signal event),是引用具名信号的事件。信号是全局范围(广播)的事件,并会被传递给所有激活的处理器(等待中的流程实例/捕获信号事件 catching signal events)。 - -使用++signalEventDefinition++元素声明信号事件定义。其++signalRef++属性引用一个++signal++元素,该++signal++元素需要声明为++definitions++根元素的子元素。下面摘录一个流程,使用中间事件(intermediate event)抛出与捕获信号事件。 - - -[source,xml,linenums] ----- - - - - - - - - - - ... - - - - - ... - - ----- - -两个++signalEventDefinition++引用同一个++signal++元素。 - - -[[bpmnSignalEventDefinitionThrow]] - -===== 抛出信号事件 - -信号可以由流程实例使用BPMN结构抛出(throw),也可以通过编程方式使用Java API抛出。下面++org.flowable.engine.RuntimeService++中的方法可以用编程方式抛出信号: - -[source,java,linenums] ----- -RuntimeService.signalEventReceived(String signalName); -RuntimeService.signalEventReceived(String signalName, String executionId); ----- - -++signalEventReceived(String signalName)++与++signalEventReceived(String signalName, String executionId)++的区别,是前者在全局范围为所有已订阅处理器抛出信号(广播),而后者只为指定的执行传递信号。 - - - -[[bpmnSignalEventDefinitionCatch]] - -===== 捕获信号事件 - -可以使用信号捕获中间事件(intermediate catch signal event)或者信号边界事件(signal boundary event)捕获信号事件。 - - -[[bpmnSignalEventDefinitionQuery]] - -===== 查询信号事件订阅 - -可以查询订阅了某一信号事件的所有执行: - -[source,java,linenums] ----- - List executions = runtimeService.createExecutionQuery() - .signalEventSubscriptionName("alert") - .list(); ----- - -可以使用++signalEventReceived(String signalName, String executionId)++方法为这些执行传递这个信号。 - - -[[bpmnSignalEventDefinitionScope]] - - -===== 信号事件的范围 - -默认情况下,信号事件在__流程引擎全局广播__。这意味着你可以在一个流程实例中抛出一个信号事件,而不同流程定义的不同流程实例都会响应这个事件。 - -但有时也会希望只在__同一个流程实例__中响应信号事件。例如,在流程实例中使用异步机制,而两个或多个活动彼此互斥的时候。 - -要限制信号事件的__范围(scope)__,在信号事件定义中添加(非BPMN 2.0标准!)__scope属性__: - - -[source,xml,linenums] ----- - ----- - -这个属性的默认值为__"global(全局)"__。 - - -[[bpmnSignalEventDefinitionExample]] - - -===== 信号事件示例 - -下面是一个不同流程通过信号通信的例子。第一个流程在保险政策更新或变更时启动。在变更由人工审核之后,会抛出信号事件,指出政策已经发生了变更: - -image::images/bpmn.signal.event.throw.png[align="center"] - -这个事件可以被所有感兴趣的流程实例捕获。下面是一个订阅这个事件的流程的例子。 - -image::images/bpmn.signal.event.catch.png[align="center"] - -**请注意:**要理解信号事件会广播给**所有**激活的处理器,这很重要。这意味着在上面的例子中,所有订阅这个信号的流程实例都会接收这个信号。在这个例子中这就是我们期望的。然而,有的情况下,不希望使用广播方式。考虑下面的流程: - - -image::images/bpmn.signal.event.warning.1.png[align="center"] - - -Flowable不支持上面流程中描述的模式。我们的想法是,在执行"do something"任务时抛出的错误,由错误边界事件捕获,并通过信号抛出事件传播至执行的并行分支,最终中断"do something in parallel"任务。到目前为止Flowable会按照预期效果执行。**然而,由于信号的广播效应,它也会被传播至所有其他订阅了这个信号事件的流程实例。**这可能并非我们希望的效果。 - -**请注意:**信号事件与特定的流程实例无关,而是会广播给所有流程实例。如果你需要只为某一特定的流程实例传递信号,则需要使用++signalEventReceived(String signalName, String executionId)++手动建立关联,并使用适当的的<>。 - -Flowable提供了解决的方法。可以在信号事件上添加__scope__属性,并将其设置为__processInstance__。 - - -[[bpmnMessageEventDefinition]] - - -==== 消息事件定义 - -消息事件(message event),是指引用具名消息的事件。消息具有名字与载荷。与信号不同,消息事件只有一个接收者。 - -消息事件定义使用++messageEventDefinition++元素声明。其++messageRef++属性引用一个++message++元素,该++message++元素需要声明为++definitions++根元素的子元素。下面摘录一个流程,声明了两个消息事件,并由开始事件与消息捕获中间事件(intermediate catching message event)引用。 - -[source,xml,linenums] ----- - - - - - - - - - - - ... - - - - ... - - - ----- - - -[[bpmnMessageEventDefinitionThrow]] - - -===== 抛出消息事件 - -作为嵌入式的流程引擎,Flowable并不关心实际如何接收消息。因为这可能与环境相关,或需要进行平台定义的操作。例如连接至JMS(Java Messaging Service,Java消息服务)队列(Queue)/主题(Topic),或者处理Webservice或者REST请求。因此接收消息需要作为应用的一部分,或者是流程引擎所嵌入的基础框架中的一部分,由你自行实现。 - -在应用中接收到消息后,需要决定如何处理它。如果这个消息需要启动新的流程实例,可以选择一种由runtime服务提供的方法: - - -[source,java,linenums] ----- -ProcessInstance startProcessInstanceByMessage(String messageName); -ProcessInstance startProcessInstanceByMessage(String messageName, Map processVariables); -ProcessInstance startProcessInstanceByMessage(String messageName, String businessKey, - Map processVariables); ----- - -这些方法使用消息启动流程实例。 - -如果需要由已有的流程实例接收消息,需要首先将消息与特定的流程实例关联(查看后续章节),然后触发等待中的执行,让流程继续进行。runtime服务提供了下列方法,可以触发订阅了消息事件的执行: - -[source,java,linenums] ----- -void messageEventReceived(String messageName, String executionId); -void messageEventReceived(String messageName, String executionId, HashMap processVariables); ----- - - -[[bpmnMessageEventDefinitionQuery]] - - -===== 查询消息事件订阅 - -* 对于消息启动事件(message start event),消息事件的订阅与的__流程定义__相关。可以使用++ProcessDefinitionQuery++查询这种类型的消息订阅: - -[source,java,linenums] ----- -ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() - .messageEventSubscription("newCallCenterBooking") - .singleResult(); ----- - -因为一个消息只能被一个流程定义订阅,因此这个查询总是返回0或1个结果。如果流程定义更新了,只有该流程定义的最新版本会订阅这个消息事件。 - -* 对于消息捕获中间事件(intermediate catch message event),消息事件的订阅与__执行__相关。可以使用++ExecutionQuery++查询这种类型的消息订阅: - - -[source,java,linenums] ----- -Execution execution = runtimeService.createExecutionQuery() - .messageEventSubscriptionName("paymentReceived") - .variableValueEquals("orderId", message.getOrderId()) - .singleResult(); ----- - -这种查询通常都会有关联查询,并且通常需要了解流程的情况(在这个例子里,对于给定的orderId,至多只有一个流程实例)。 - - -[[bpmnMessageEventDefinitionExample]] - - -===== 消息事件示例 - -下面是一个流程的例子,可以使用两种不同的消息启动: - -image::images/bpmn.start.message.event.example.1.png[align="center"] - -在流程需要通过不同的方式启动,但是后续使用统一的方式处理时,就可以使用这种方法。 - - -[[bpmnStartEvents]] - - -==== 启动事件 - -启动事件(start event)是流程的起点。启动事件的类型(流程在消息到达时启动,在指定的时间间隔后启动,等等),定义了流程__如何__启动,并显示为启动事件中的小图标。在XML中,类型由子元素声明来定义。 - -启动事件**随时捕获**:启动事件(保持)等候,直到特定的触发器被触发。 - -在启动事件中,可以使用下列Flowable自定义参数: - -* *initiator*: 指明保存认证用户(authenticated user)ID用的变量名。在流程启动时,操作用户的ID会保存在这个变量中。例如: - -[source,xml,linenums] ----- - ----- - -认证用户必须在try-finally块中调用++IdentityService.setAuthenticatedUserId(String)++方法进行设置。像这样: - -[source,java,linenums] ----- -try { - identityService.setAuthenticatedUserId("bono"); - runtimeService.startProcessInstanceByKey("someProcessKey"); -} finally { - identityService.setAuthenticatedUserId(null); -} - ----- - -这段代码已经集成在Flowable应用中,可以在<>中使用。 - -[[bpmnNoneStartEvent]] - - -==== 空启动事件 - -[[noneStartEventDescription]] - - -===== 描述 - -“空”启动事件(none Start Event),指的是未指定启动流程实例触发器的启动事件。引擎将无法预知何时启动流程实例。空启动事件用于流程实例通过调用下列__startProcessInstanceByXXX__ API方法启动的情况。 - -[source,java,linenums] ----- -ProcessInstance processInstance = runtimeService.startProcessInstanceByXXX(); ----- - -__请注意:__子流程(sub-process)必须有空启动事件。 - - -[[noneStartEventGraphicalNotation]] - - -===== 图示 - -空启动事件用空心圆圈表示,中间没有图标(也就是说,没有触发器)。 - -image::images/bpmn.none.start.event.png[align="center"] - - -[[noneStartEventXml]] - - -===== XML表示 - -空启动事件的XML表示格式,就是普通的启动事件声明,而没有任何子元素(其他种类的启动事件都有用于声明其类型的子元素)。 - -[source,xml,linenums] ----- - ----- - - -[[noneStartEventCustomExtension]] - - -===== 空启动事件的自定义扩展 - -*formKey*: 引用表单定义,用户需要在启动新流程实例时填写该表单。可以在<>找到更多信息。例如: - -[source,xml,linenums] ----- - ----- - - -[[bpmnTimerStartEvent]] - - -==== 定时器启动事件 - -[[timerStartEventDescription]] - - -===== 描述 - -定时器启动事件(timer start event)在指定时间创建流程实例。在流程只需要启动一次,或者流程需要在特定的时间间隔重复启动时,都可以使用。 - -__请注意:__子流程不能有定时器启动事件。 - -__请注意:__定时器启动事件,在流程部署的同时就开始计时。不需要调用startProcessInstanceByXXX就会在时间启动。调用startProcessInstanceByXXX时会在定时启动之外额外启动一个流程。 - -__请注意:__当部署带有定时器启动事件的流程的更新版本时,上一版本的定时器作业会被移除。这是因为通常并不希望旧版本的流程仍然自动启动新的流程实例。 - - -[[timerStartEventGraphicalNotation]] - - -===== 图示 - -定时器启动事件,用其中有一个钟表图标的圆圈来表示。 - -image::images/bpmn.clock.start.event.png[align="center"] - - -[[timerStartEventXml]] - - -===== XML表示 - -定时器启动事件的XML表示格式,是普通的启动事件声明加上定时器定义子元素。请参考<>了解详细配置方法。 - -示例:流程会启动4次,间隔5分钟,从2011年3月11日,12:13开始 - -[source,xml,linenums] ----- - - - R4/2011-03-11T12:13/PT5M - - ----- - -示例:流程会在设定的时间启动一次 - -[source,xml,linenums] ----- - - - 2011-03-11T12:13:14 - - ----- - - -[[bpmnMessageStartEvent]] - - -==== 消息启动事件 - -[[messageStartEventDescription]] - - -===== 描述 - -<>启动事件(message start event)使用具名消息启动流程实例。消息名用于__选择__正确的启动事件。 - -当**部署**具有一个或多个消息启动事件的流程定义时,会做如下判断: - -* 给定流程定义中,消息启动事件的名字必须是唯一的。一个流程定义不得包含多个同名的消息启动事件。如果流程定义中有两个或多个消息启动事件引用同一个消息,或者两个或多个消息启动事件引用了具有相同消息名字的消息,则Flowable会在部署这个流程定义时抛出异常。 -* 在所有已部署的流程定义中,消息启动事件的名字必须是唯一的。如果在流程定义中,一个或多个消息启动事件引用了已经部署的另一流程定义中消息启动事件的消息名,则Flowable会在部署这个流程定义时抛出异常。 -* 流程版本:在部署流程定义的新版本时,会取消上一版本的消息订阅,即使新版本中并没有这个消息事件)。 - -在**启动**流程实例时,可以使用下列++RuntimeService++中的方法,触发消息启动事件: - -[source,java,linenums] ----- -ProcessInstance startProcessInstanceByMessage(String messageName); -ProcessInstance startProcessInstanceByMessage(String messageName, Map processVariables); -ProcessInstance startProcessInstanceByMessage(String messageName, String businessKey, - Map - - - - - - - - - ... - - - ----- - - -[[bpmnSignalStartEvent]] - - -==== 信号启动事件 - -[[bpmnSignalStartEventDescription]] - - -===== 描述 - -<>启动事件(signal start event),使用具名信号启动流程实例。这个信号可以由流程实例中的信号抛出中间事件(intermediary signal throw event),或者API(__runtimeService.signalEventReceivedXXX__方法)触发。两种方式都会启动所有拥有相同名字信号启动事件的流程定义。 - -请注意可以选择异步还是同步启动流程实例。 - -需要为API传递的++signalName++,是由++signal++元素的++name++属性决定的名字。++signal++元素由++signalEventDefinition++的++signalRef++属性引用。 - -[[signalStartEventGraphicalNotation]] - - -===== 图示 - -信号启动事件用其中有一个信号事件标志的圆圈表示。这个标志并未填充,用以表示捕获(接收)行为。 - -image::images/bpmn.start.signal.event.png[align="center"] - - -[[signalStartEventXml]] - - -===== XML表示 - -信号启动事件的XML表示格式,为普通启动事件声明,加上signalEventDefinition子元素: - - -[source,xml,linenums] ----- - - - - - - - - - - - ----- - -[[bpmnErrorStartEvent]] - - -==== 错误启动事件 - -[[errorStartEventDescription]] - - -===== 描述 - -<>启动事件(error start event),可用于触发事件子流程(Event Sub-Process)。**错误启动事件不能用于启动流程实例**。 - -错误启动事件总是中断。 - -[[errorStartEventGraphicalNotation]] - - -===== 图示 - -错误启动事件用其中有一个错误事件标志的圆圈表示。这个标志并未填充,用以表示捕获(接收)行为。 - -image::images/bpmn.start.error.event.png[align="center"] - - -[[errorStartEventXml]] - - -===== XML表示 - -错误启动事件的XML表示格式,为普通启动事件声明加上errorEventDefinition子元素: - -[source,xml,linenums] ----- - - - ----- - - -[[bpmnEndEvent]] - - -==== 结束事件 - -结束事件(end event)标志着流程或子流程中一个分支的结束。结束事件**总是抛出(型)事件**。这意味着当流程执行到达结束事件时,会抛出一个__结果__。结果的类型由事件内部的黑色图标表示。在XML表示中,类型由子元素声明给出。 - - -[[bpmnNoneEndEvent]] - - -==== 空结束事件 - -[[noneEndEventDescription]] - - -===== 描述 - -“空”结束事件(none end event),意味着当到达这个事件时,没有特别指定抛出的__结果__。因此,引擎除了结束当前执行分支之外,不会多做任何事情。 - -[[bpmnNoneEndEventDescription]] - - -===== 图示 - -空结束事件,用其中没有图标(没有结果类型)的粗圆圈表示。 - -image::images/bpmn.none.end.event.png[align="center"] - - -[[bpmnNoneStartEventXml]] - - -===== XML表示 - -空事件的XML表示格式为普通结束事件声明,没有任何子元素(其它种类的结束事件都有子元素,用于声明其类型)。 - - -[source,xml,linenums] ----- - ----- - - -[[bpmnErrorEndEvent]] - - -==== 错误结束事件 - -[[bpmnErrorEndEventDescription]] - - -===== 描述 - -当流程执行到达**错误结束事件(error end event)**时,结束执行的当前分支,并抛出错误。这个错误可以<>。如果找不到匹配的错误边界事件,将会抛出异常。 - - -[[bpmnErrorEndEventGraphicalNotation]] - - -===== 图示 - -错误结束事件事件用内部有一个错误图标的标准结束事件(粗圆圈)表示。错误图标是全黑的,代表抛出的含义。 - -image::images/bpmn.error.end.event.png[align="center"] - - -[[bpmnErrorEndEventXml]] - - -===== XML表示 - -错误结束事件表示为结束事件,加上__errorEventDefinition__子元素: - -[source,xml,linenums] ----- - - - - ----- - -__errorRef__属性可以引用在流程外定义的__error__元素: - -[source,xml,linenums] ----- - -... - -... ----- - -__error__的**errorCode**用于查找匹配的错误捕获边界事件。如果__errorRef__不匹配任何已定义的__error__,则该__errorRef__会用做__errorCode__的快捷方式。这个快捷方式是Flowable特有的。下面的代码片段在功能上是相同的。 - -[source,xml,linenums] ----- - -... - -... - - - -... ----- - -与下面的代码功能相同 - -[source,xml,linenums] ----- - - - ----- - -请注意__errorRef__必须遵从BPMN 2.0概要(schema),且必须是合法的QName。 - -[[bpmnTerminateEndEvent]] - -==== 终止结束事件 - -===== 描述 - -当到达__终止结束事件(terminate end event)__时,当前的流程实例或子流程会被终止。也就是说,当执行到达终止结束事件时,会判断第一个__范围 scope__(流程或子流程)并终止它。请注意在BPMN 2.0中,子流程可以是嵌入式子流程,调用活动,事件子流程,或事务子流程。有一条通用规则:当存在多实例的调用过程或嵌入式子流程时,只会终止一个实例,其他的实例与流程实例不会受影响。 - -可以添加一个可选属性__terminateAll__。当其为__true__时,无论该终止结束事件在流程定义中的位置,也无论它是否在子流程(甚至是嵌套子流程)中,都会终止(根)流程实例。 - -===== 图示 - -终止结束事件用内部有一个全黑圆的标准结束事件(粗圆圈)表示。 - -image::images/bpmn.terminate.end.event.png[align="center"] - - -===== XML表示 - -终止结束事件,表示为结束事件,加上__terminateEventDefinition__子元素。 - -请注意__terminateAll__属性是可选的(默认为__false__)。 - -[source,xml,linenums] ----- - - ----- - -[[bpmnCancelEndEvent]] - -==== 取消结束事件 - -[[bpmnCancelEndEventDescription]] - - -===== 描述 - -取消结束事件(cancel end event)只能与BPMN事务子流程(BPMN transaction subprocess)一起使用。当到达取消结束事件时,会抛出取消事件,且必须由取消边界事件(cancel boundary event)捕获。取消边界事件将取消事务,并触发补偿(compensation)。 - - -[[bpmnCancelEndEventGraphicalNotation]] - - -===== 图示 - -取消结束事件用内部有一个取消图标的标准结束事件(粗圆圈)表示。取消图标是全黑的,代表抛出的含义。 - -image::images/bpmn.cancel.end.event.png[align="center"] - - -[[bpmnCancelEndEventXml]] - - -===== XML表示 - -取消结束事件,表示为结束事件,加上__cancelEventDefinition__子元素。 - -[source,xml,linenums] ----- - - - ----- - - -[[bpmnBoundaryEvent]] - - -==== 边界事件 - -边界事件(boundary event)是__捕获型__事件,依附在活动(activity)上。边界事件永远不会抛出。这意味着当活动运行时,事件将__监听__特定类型的触发器。当__捕获__到事件时,会终止活动,并沿该事件的出口顺序流继续。 - -所有的边界事件都用相同的方式定义: - -[source,xml,linenums] ----- - - - ----- - -边界事件由下列元素定义: - -* (流程范围内)唯一的标识符 -* 由**attachedToRef**属性定义的,对该事件所依附的活动的引用。请注意边界事件及其所依附的活动,应定义在相同级别(也就是说,边界事件并不包含在活动内)。 -* 定义了边界事件的类型的,形如__XXXEventDefinition__的XML子元素(例如__TimerEventDefinition__,__ErrorEventDefinition__,等等)。查阅特定的边界事件类型,以了解更多细节。 - - -[[bpmnTimerBoundaryEvent]] - - -==== 定时器边界事件 - -[[timerBoundaryEventDescription]] - - -===== 描述 - -定时器边界事件(timer boundary event)的行为像是跑表与闹钟。当执行到达边界事件所依附的活动时,将启动定时器。当定时器触发时(例如在特定时间间隔后),可以中断活动,并沿着边界事件的出口顺序流继续执行。 - - -[[bpmnTimerBoundaryEventGraphicalNotation]] - - -===== 图示 - -定时器边界事件用内部有一个定时器图标的标准边界事件(圆圈)表示。 - -image::images/bpmn.boundary.timer.event.png[align="center"] - - -[[bpmnTimerBoundaryEventXml]] - - -===== XML表示 - -定时器边界事件与<>一样定义。其中类型子元素为**timerEventDefinition**元素。 - -[source,xml,linenums] ----- - - - PT4H - - ----- - -请参考<>了解定时器配置的细节。 - -在图示中圆圈画为虚线,如下: - -image::images/bpmn.non.interrupting.boundary.timer.event.png[align="center"] - -中断与非中断定时器事件是不同的。非中断意味着最初的活动**不会**被中断,而会保持原样。默认为中断行为。在XML表示中,__cancelActivity__属性设置为false。 - -一个典型使用场景,是在一段时间之后发送提醒邮件,但不影响正常的流程流向。 - -[source,xml,linenums] ----- - ----- - -**请注意:**定时器边界事件只有在异步执行器(async executor)启用时才能触发(也就是说,需要在++flowable.cfg.xml++中,将__asyncExecutorActivate__设置为++true++。因为异步执行器默认情况下是禁用的。) - - -[[bpmnKnownIssueBoundaryEvent]] - - -===== 边界事件的已知问题 - -所有类型的边界事件,都有一个关于并发的已知问题:不能在边界事件上附加多个出口顺序流。这个问题的解决方案,是使用一条出口顺序流,指向并行网关。 - -image::images/bpmn.known.issue.boundary.event.png[align="center"] - - -[[bpmnBoundaryErrorEvent]] - - -==== 错误边界事件 - -[[bpmnBoundaryErrorEventDescription]] - - -===== 描述 - -在活动边界上的错误__捕获__中间(事件),或简称**错误边界事件(error boundary event)**,捕获其所依附的活动范围内抛出的错误。 - -在<>或者<>上定义错误边界事件最有意义,因为子流程的范围会包括其中的所有活动。错误可以由<>抛出。这样的错误会逐层向其上级父范围传播,直到在范围内找到一个匹配错误事件定义的错误边界事件。 - -当捕获错误事件时,会销毁边界事件定义所在的活动,同时销毁其中所有的当前执行(例如,并行活动,嵌套子流程,等等)。流程执行将沿着边界事件的出口顺序流继续。 - -[[bpmnBoundaryErrorEventgraphicalNotation]] - - -===== 图示 - -错误边界事件用内部有一个错误图标的标准中间事件(两层圆圈)表示。错误图标是白色的,代表__捕获__的含义。 - -image::images/bpmn.boundary.error.event.png[align="center"] - -[[bpmnBoundaryErrorEventXml]] - - -===== XML表示 - -错误边界事件与标准<>一样定义: - -[source,xml,linenums] ----- - - - ----- - -在<>中,__errorRef__引用一个流程元素外定义的错误: - -[source,xml,linenums] ----- - -... - -... - ----- - -**errorCode**用于匹配捕获的错误: - -* 如果省略了__errorRef__,错误边界事件会捕获**所有错误事件**,无论__error__的errorCode是什么。 -* 如果提供了__errorRef__,并且其引用了存在的__error__,则边界事件**只会捕获相同错误代码的错误**。 -* 如果提供了__errorRef__,但BPMN 2.0文件中没有定义__error__,则**errorRef会用作errorCode**(与错误结束事件类似)。 - - -[[bpmnBoundaryErrorEventExample]] - - -===== 示例 - -下面的示例流程展示了如何使用错误结束事件。当__'Review profitability (审核盈利能力)'__用户任务完成,并指出提供的信息不足时,会抛出错误。当这个错误被子流程边界捕获时,__'Review sales lead (审核销售线索)'__子流程中的所有运行中活动都会被销毁(即使__'Review customer rating 审核客户等级'__还没有完成),并会创建__'Provide additional details (提供更多信息)'__用户任务。 - -image::images/bpmn.boundary.error.example.png[align="center"] - -这个流程作为演示配置的示例提供。可以在__org.flowable.examples.bpmn.event.error__包中找到流程XML与单元测试。 - - -[[bpmnBoundarySignalEvent]] - - -==== 信号边界事件 - -[[bpmnBoundarySignalEventDescription]] - - -===== 描述 - -依附在活动边界上的<>捕获中间(事件),或简称**信号边界事件(signal boundary event)**,捕获与其信号定义具有相同名称的信号。 - -**请注意:**与其他事件例如错误边界事件不同的是,信号边界事件不只是捕获其所依附范围抛出的信号。信号边界事件为全局范围(广播)的,意味着信号可以从任何地方抛出,甚至可以是不同的流程实例。 - -**请注意:**与其他事件(如错误事件)不同,信号在被捕获后不会被消耗。如果有两个激活的信号边界事件,捕获相同的信号事件,则两个边界事件都会被触发,哪怕它们不在同一个流程实例里。 - - -[[bpmnBoundarySignalEventGraphicalNotation]] - - -===== 图示 - -信号边界事件,用内部有一个信号图标的标准中间事件(两层圆圈)表示。信号图标是白色的,代表__捕获__的含义。 - -image::images/bpmn.boundary.signal.event.png[align="center"] - - -[[bpmnBoundarySignalEventXml]] - - -===== XML表示 - -信号边界事件与标准<>一样定义: - -[source,xml,linenums] ----- - - - ----- - - -[[bpmnBoundarySignalEventExample]] - - -===== 示例 - -参见<>章节。 - - -[[bpmnBoundaryMessageEvent]] - - -==== 消息边界事件 - -[[bpmnBoundaryMessageEventDescription]] - - -===== 描述 - -在活动边界上的<>__捕获__中间(事件),或简称**消息边界事件(message boundary event)**,捕获与其消息定义具有相同消息名的消息。 - - -[[bpmnBoundaryMessageEventGraphicalNotation]] - - -===== 图示 - -消息边界事件,用内部有一个消息图标的标准中间事件(两层圆圈)表示。信号图标是白色的,代表__捕获__的含义。 - -image::images/bpmn.boundary.message.event.png[align="center"] - -请注意消息边界事件既可以是中断型的(右图),也可以是非中断型的(左图)。 - - -[[bpmnBoundaryMessageEventXml]] - - -===== XML表示 - -消息边界事件与标准<>一样定义: - -[source,xml,linenums] ----- - - - ----- - - -[[bpmnBoundaryMessageEventExample]] - - -===== 示例 - -参见<>章节。 - - -[[bpmnBoundaryCancelEvent]] - - -==== 取消边界事件 - -[[bpmnBoundaryCancelEventDescription]] - - -===== 描述 - -依附在事务子流程边界上的取消__捕获__中间事件,或简称**取消边界事件(cancel boundary event)**,在事务取消时触发。当取消边界事件触发时,首先会中断当前范围的所有活动执行。接下来,启动事务范围内所有有效的的补偿边界事件(compensation boundary event)。补偿会同步执行,也就是说在离开事务前,边界事件会等待补偿完成。当补偿完成时,沿取消边界事件的任何出口顺序流离开事务子流程。 - - -**请注意:**一个事务子流程只允许使用一个取消边界事件。 - -**请注意:**如果事务子流程中有嵌套的子流程,只会对成功完成的子流程触发补偿。 - -**请注意:**如果取消边界事件放置在具有多实例特性的事务子流程上,如果一个实例触发了取消,则边界事件将取消所有实例。 - - -[[bpmnBoundaryCancelEventGraphicalNotation]] - - -===== 图示 - -取消边界事件,用内部有一个取消图标的标准中间事件(两层圆圈)表示。取消图标是白色的(未填充),代表__捕获__的含义。 - -image::images/bpmn.boundary.cancel.event.png[align="center"] - - -[[bpmnBoundaryCancelEventXml]] - - -===== XML表示 - -取消边界事件与标准<>一样定义: - -[source,xml,linenums] ----- - - - ----- - -因为取消边界事件总是中断型的,因此没有++cancelActivity++属性。 - - -[[bpmnBoundaryCompensationEvent]] - - -==== 补偿边界事件 - -[[bpmnBoundaryCompensationEventDescription]] - - -===== 描述 - -依附在活动边界上的补偿__捕获__中间(事件),或简称**补偿边界事件(compensation boundary event)**,可以为活动附加补偿处理器。 - -补偿边界事件必须使用直接关联的方式引用单个的补偿处理器。 - -补偿边界事件与其它边界事件的活动策略不同。其它边界事件,例如信号边界事件,在其依附的活动启动时激活;当该活动结束时会被解除,并取消相应的事件订阅。而补偿边界事件不是这样。补偿边界事件在其依附的活动**成功完成**时激活,同时创建补偿事件的相应订阅。当补偿事件被触发,或者相应的流程实例结束时,才会移除订阅。请考虑下列因素: - -* 当补偿被触发时,会调用补偿边界事件关联的补偿处理器。调用次数与其依附的活动成功完成的次数相同。 -* 如果补偿边界事件依附在具有多实例特性的活动上,则会为每一个实例创建补偿事件订阅。 -* 如果补偿边界事件依附在位于循环内部的活动上,则每次该活动执行时,都会创建一个补偿事件订阅。 -* 如果流程实例结束,则取消补偿事件的订阅。 - -**请注意:**嵌入式子流程不支持补偿边界事件。 - - -[[bpmnBoundaryCompensationEventGraphicalNotation]] - - -===== 图示 - -补偿边界事件,用内部有一个补偿图标的标准中间事件(两层圆圈)表示。补偿图标是白色的(未填充),代表__捕获__的含义。另外,补偿边界事件使用单向连接关联补偿处理器,如下图所示: - -image::images/bpmn.boundary.compensation.event.png[align="center"] - - -[[bpmnBoundaryCompensationEventXml]] - - -===== XML表示 - -补偿边界事件与标准<>一样定义: - -[source,xml,linenums] ----- - - - - - - - ----- - -补偿边界事件在活动完成后才激活,因此不支持++cancelActivity++属性。 - - -[[bpmnIntermediateCatchingEvent]] - - -==== 捕获中间事件 - -所有的捕获中间事件(intermediate catching events)都使用相同方式定义: - -[source,xml,linenums] ----- - - - ----- - -捕获中间事件由下列元素定义: - -* (流程范围内)唯一的标识符 -* 定义了捕获中间事件类型的,形如__XXXEventDefinition__的XML子元素(例如__TimerEventDefinition__等)。查阅特定中间捕获事件类型,以了解更多细节。 - - -[[bpmnTimerIntermediateEvent]] - - -==== 定时器捕获中间事件 - -[[bpmnTimerIntermediateEventDescription]] - - -===== 描述 - -定时器捕获中间事件(timer intermediate catching event)的行为像是跑表。当执行到达捕获事件时,启动定时器;当定时器触发时(例如在一段时间间隔后),沿定时器中间事件的出口顺序流继续执行。 - - -[[bpmnTimerIntermediateEventGraphicalNotation]] - - -===== 图示 - -定时器中间事件用内部有定时器图标的中间捕获事件表示。 - -image::images/bpmn.intermediate.timer.event.png[align="center"] - - -[[bpmnTimerIntermediateEventXml]] - - -===== XML表示 - -定时器中间事件与<>一样定义。子元素为**timerEventDefinition**。 - -[source,xml,linenums] ----- - - - PT5M - - ----- - -查看<>了解详细配置。 - - -[[bpmnIntermediateSignalEvent]] - - -==== 信号捕获中间事件 - -[[bpmnIntermediateSignalEventDescription]] - - -===== 描述 - -<>__捕获__中间事件(signal intermediate catching event),捕获与其引用的信号定义具有相同信号名称的信号。 - -**请注意:**与其他事件如错误事件不同,信号在被捕获后不会被消耗。如果有两个激活的信号中间事件,捕获相同的信号事件,则两个中间事件都会被触发,哪怕它们不在同一个流程实例里。 - - -[[bpmnIntermediateSignalEventGraphicalNotation]] - - -===== 图示 - -信号捕获中间事件用内部有信号图标的标准中间事件(两层圆圈)表示。信号图标是白色的(未填充),代表__捕获__的含义。 - -image::images/bpmn.intermediate.signal.catch.event.png[align="center"] - - -[[bpmnIntermediateSignalEventXml]] - - -===== XML表示 - -信号中间事件与<>一样定义。子元素为**signalEventDefinition**。 - -[source,xml,linenums] ----- - - - ----- - - -[[bpmnIntermediateSignalEventExample]] - - -===== 示例 - -参阅<>章节。 - -[[bpmnIntermediateMessageEvent]] - - -==== 消息捕获中间事件 - -[[bpmnIntermediateMessageEventDescription]] - - -===== 描述 - -<>__捕获__中间事件(message intermediate catching event),捕获特定名字的消息。 - - -[[bpmnIntermediateMessageEventGraphicalNotation]] - - -===== 图示 - -消息捕获中间事件用内部有消息图标的标准中间事件(两层圆圈)表示。消息图标是白色的(未填充),代表__捕获__的含义。 - -image::images/bpmn.intermediate.message.catch.event.png[align="center"] - - -[[bpmnIntermediateMessageEventXml]] - - -===== XML表示 - -消息中间事件与<>一样定义。子元素为**messageEventDefinition**。 - -[source,xml,linenums] ----- - - - ----- - - -[[bpmnIntermediateMessageEventExample]] - - -===== 示例 - -参阅<>章节。 - - -[[bpmnIntermediateThrowEvent]] - - -==== 抛出中间事件 - -所有的抛出中间事件(intermediate throwing evnet)都使用相同方式定义: - -[source,xml,linenums] ----- - - - ----- - -抛出中间事件由下列元素定义: - -* (流程范围内)唯一的标识符 -* 定义了抛出中间事件类型的,形如__XXXEventDefinition__的XML子元素(例如__signalEventDefinition__等)。查阅特定中间抛出事件类型,以了解更多细节。 - -[[bpmnIntermediateThrowNoneEvent]] - - -==== 空抛出中间事件 - -下面的流程图展示了空抛出中间事件(intermediate throwing none event)的简单例子。其用于指示流程已经到达了某种状态。 - -image::images/bpmn.intermediate.none.event.png[align="center"] - -添加一个<>后,空中间事件就可以成为很好的监视某些KPI(Key Performance Indicators 关键绩效指标)的钩子。 - -[source,xml,linenums] ----- - - - - - - ----- - -你也可以添加一些自己的代码,将部分事件发送给你的BAM(Business Activity Monitoring 业务活动监控)工具,或者DWH(Data Warehouse 数据仓库)。在这种情况下,引擎本身不会做任何事情,只是从中穿过。 - - -[[bpmnIntermediateThrowSignalEvent]] - - -==== 信号抛出中间事件 - -[[bpmnIntermediateThrowSignalEventDescription]] - - -===== 描述 - -<>__抛出__中间事件(signal intermediate throwing event),抛出所定义信号的信号事件。 - -在Flowable中,信号会广播至所有的激活的处理器(也就是说,所有的信号捕获事件)。可以同步或异步地发布信号。 - -* 在默认配置中,信号**同步**地传递。这意味着抛出信号的流程实例会等待,直到信号传递至所有的捕获信号的流程实例。所有的捕获流程实例也会在与抛出流程实例相同的事务中,也就是说如果收到通知的流程实例中,有一个实例产生了技术错误(抛出异常),则所有相关的实例都会失败。 -* 信号也可以**异步**地传递。这是由到达抛出信号事件时的发送处理器来决定的。对于每个激活的处理器,JobExecutor会为其存储并传递一个异步通知消息(asynchronous notification message),即作业(Job)。 - -[[bpmnIntermediateThrowSignalEventGraphicalNotation]] - - -===== 图示 - -消息抛出中间事件用内部有信号图标的标准中间事件(两层圆圈)表示。信号图标是黑色的(已填充),代表__抛出__的含义。 - -image::images/bpmn.intermediate.signal.throw.event.png[align="center"] - - -[[bpmnIntermediateThrowSignalEventXml]] - - -===== XML表示 - -信号中间事件与<>一样定义。子元素为**signalEventDefinition**。 - -[source,xml,linenums] ----- - - - ----- - -异步信号事件这样定义: - -[source,xml,linenums] ----- - - - ----- - - -[[bpmnIntermediateThrowSignalEventExample]] - - -===== 示例 - -参阅<>章节。 - - -[[bpmnIntermediateThrowCompensationEvent]] - - -==== 补偿抛出中间事件 - -[[bpmnIntermediateThrowCompensationEventDescription]] - - -===== 描述 - -补偿__抛出__中间事件(compensation intermediate throwing event)用于触发补偿。 - -**触发补偿:**既可以为设计的活动触发补偿,也可以为补偿事件所在的范围触发补偿。补偿由活动所关联的补偿处理器执行。 - -* 活动抛出补偿时,活动关联的补偿处理器将执行的次数,为活动成功完成的次数。 -* 抛出补偿时,当前范围中所有的活动,包括并行分支上的活动都会被补偿。 -* 补偿分层触发:如果将要被补偿的活动是一个子流程,则该子流程中所有的活动都会触发补偿。如果该子流程有嵌套的活动,则会递归地抛出补偿。然而,补偿不会传播至流程的**上层**:如果子流程中触发了补偿,该补偿不会传播至子流程范围外的活动。BPMN规范指出,对“与子流程在相同级别”的活动触发补偿。 -* 在Flowable中,补偿按照执行的相反顺序运行。这意味着最后完成的活动会第一个补偿。 -* 可以使用补偿抛出中间事件补偿已经成功完成的事务子流程。 - -**请注意:**如果抛出补偿的范围中有一个子流程,而该子流程包含有关联了补偿处理器的活动,则当抛出补偿时,只有该子流程成功完成时,补偿才会传播至该子流程。如果子流程内嵌套的部分活动已经完成,并附加了补偿处理器,但包含这些活动的子流程还没有完成,则这些补偿处理器仍不会执行。参考下面的例子: - -image::images/bpmn.throw.compensation.example1.png[align="center"] - -在这个流程中,有两个并行的执行:一个执行嵌入子流程,另一个执行“charge credit card(信用卡付款)”活动。假定两个执行都已开始,且第一个执行正等待用户完成“review bookings(检查预定)”任务。第二个执行进行了“charge credit card(信用卡付款)”活动的操作,抛出了错误,导致“cancel reservations(取消预订)”事件触发补偿。这时并行子流程还未完成,意味着补偿不会传播至该子流程,因此不会执行“cancel hotel reservation(取消酒店预订)”补偿处理器。而如果“cancel reservations(取消预订)”运行前,这个用户任务(因此该嵌入式子流程也)已经完成,则补偿会传播至该嵌入式子流程。 - -**流程变量:**当补偿嵌入式子流程时,用于执行补偿处理器的执行,可以访问子流程的局部流程变量在子流程完成时的值。为此,会对范围执行(为执行子流程所创建的执行)所关联的流程变量进行快照。意味着: - -* 补偿执行器无法访问子流程范围内并行执行所添加的变量。 -* 上层执行所关联的流程变量(例如流程实例关联的流程变量)不在该快照中。因为补偿处理器可以直接访问这些流程变量在抛出补偿时的值。 -* 只会为嵌入式子流程进行变量快照。其他活动不会进行变量快照。 - -**目前的限制:** - -* 目前不支持++waitForCompletion="false"++。当补偿抛出中间事件触发补偿时,只有在补偿成功完成时,才会离开该事件。 -* 补偿由并行执行运行。并行执行会按照补偿活动完成的逆序启动。 -* 补偿不会传播至调用活动(call activity)生成的子流程。 - - -[[bpmnIntermediateThrowCompensationEventGraphicalNotation]] - - -===== 图示 - -补偿抛出中间事件用内部有补偿图标的标准中间事件(两层圆圈)表示。补偿图标是黑色的(已填充),代表__抛出__的含义。 - -image::images/bpmn.intermediate.compensation.throw.event.png[align="center"] - - -[[bpmnIntermediateThrowCompensationEventXml]] - - -===== XML表示 - -补偿中间事件与<>一样定义。子元素为**compensateEventDefinition**。 - -[source,xml,linenums] ----- - - - ----- - -另外,++activityRef++可选项用于为指定的范围或活动触发补偿: - -[source,xml,linenums] ----- - - - ----- - - -[[bpmnSequenceFlow]] - - -=== 顺序流 - -[[sequenceFlowDescription]] - - -==== 描述 - -顺序流(sequence flow)是流程中两个元素间的连接器。在流程执行过程中,一个元素被访问后,会沿着其所有出口顺序流继续执行。这意味着BPMN 2.0的默认是并行执行的:两个出口顺序流就会创建两个独立的、并行的执行路径。 - -[[sequenceFlowGraphicalNotation]] - - -==== 图示 - -顺序流,用从源元素指向目标元素的箭头表示。箭头总是指向目标元素。 - -image::images/bpmn.sequence.flow.png[align="center"] - - -[[sequenceFlowXml]] - - -==== XML表示 - -顺序流需要有流程唯一的**id**,并引用存在的**源**与**目标**元素。 - -[source,xml,linenums] ----- - ----- - - -[[bpmnConditionalSequenceFlow]] - - -==== 条件顺序流 - -[[condSeqFlowDescription]] - - -===== 描述 - -在顺序流上可以定义条件(conditional sequence flow)。当离开BPMN 2.0活动时,默认行为是计算其每个出口顺序流上的条件。当条件计算为__true__时,选择该出口顺序流。如果该方法选择了多条顺序流,则会生成多个__执行__,流程会以并行方式继续。 - -**请注意:**上面的介绍针对BPMN 2.0活动(与事件),但不适用于网关(gateway)。不同类型的网关,会用不同的方式处理带有条件的顺序流。 - - -[[conditionalSequenceFlowGraphicalNotation]] - - -===== 图示 - -条件顺序流用起点带有小菱形的顺序流表示。在顺序流旁显示条件表达式。 - -image::images/bpmn.conditional.sequence.flow.png[align="center"] - - -[[conditionalSequenceFlowXml]] - - -===== XML表示 - -条件顺序流的XML表示格式为含有**conditionExpression(条件表达式)**子元素的普通顺序流。请注意目前只支持__tFormalExpressions__。可以省略__xsi:type=""__定义,默认为唯一支持的表达式类型。 - - -[source,xml,linenums] ----- - - - 100 && order.price < 250}]]> - - ----- - -目前conditionalExpressions**只能使用UEL**。详细信息可以在<>章节找到。使用的表达式需要能解析为boolean值,否则当计算条件时会抛出异常。 - -* 下面的例子,通过典型的JavaBean的方式,使用getter引用流程变量的数据。 - -[source,xml,linenums] ----- - - 100 && order.price < 250}]]> - ----- - -* 这个例子调用了一个解析为boolean值的方法。 - -[source,xml,linenums] ----- - - - ----- - -Flowable发行版中包含了下列示例流程,用于展示值表达式与方法表达式的使用(参见__org.flowable.examples.bpmn.expression__)。 - -image::images/bpmn.uel-expression.on.seq.flow.png[align="center"] - - -[[bpmnDefaultSequenceFlow]] - - -==== 默认顺序流 - -[[bpmnDefaultSequenceFlowDescription]] - - -===== 描述 - -所有的BPMN 2.0任务与网关都可以使用**默认顺序流(default sequence flow)**。只有当没有其他顺序流可以选择时,才会选择默认顺序流作为活动的出口顺序流。流程会忽略默认顺序流上的条件。 - - -[[bpmnDefaultSequenceFlowGraphicalNotation]] - - -===== 图示 - -默认顺序流用起点带有“斜线”标记的一般顺序流表示。 - -image::images/bpmn.default.sequence.flow.png[align="center"] - - -[[bpmnDefaultSequenceFlowXmlRepresentation]] - - -===== XML表示 - -活动的默认顺序流由该活动的**default属性**定义。下面的XML片段展示了一个排他网关(exclusive gateway),带有默认顺序流__flow 2__。只有当__conditionA__与__conditionB__都计算为false时,才会选择默认顺序流作为网关的出口顺序流。 - -[source,xml,linenums] ----- - - - - ${conditionA} - - - - - - ${conditionB} - ----- - - -对应下面的图示: - -image::images/bpmn.default.sequence.flow.example.png[align="center"] - -[[bpmnGateways]] - - -=== 网关 - -网关(gateway)用于控制执行的流向(或者按BPMN 2.0的用词:执行的__“标志(token)”__)。网关可以__消费(consuming)__与__生成(generating)__标志。 - -网关用其中带有图标的菱形表示。该图标显示了网关的类型。 - -image::images/bpmn.gateway.png[align="center"] - - -[[bpmnExclusiveGateway]] - - -==== 排他网关 - -[[exclusiveGatewayDescription]] - - -===== 描述 - -排他网关(exclusive gateway)(也叫__异或网关 XOR gateway__,或者更专业的,__基于数据的排他网关 exclusive data-based gateway__),用于对流程中的**决策**建模。当执行到达这个网关时,会按照所有出口顺序流定义的顺序对它们进行计算。选择第一个条件计算为true的顺序流(当没有设置条件时,认为顺序流为__true__)继续流程。 - -**请注意这里出口顺序流的含义与BPMN 2.0中的一般情况不一样。一般情况下,会选择所有条件计算为true的顺序流,并行执行。而使用排他网关时,只会选择一条顺序流。当多条顺序流的条件都计算为true时,会且仅会选择在XML中最先定义的顺序流继续流程。如果没有可选的顺序流,会抛出异常。** - - -[[exclusiveGatewayGraphNotation]] - - -===== 图示 - -排他网关用内部带有'X'图标的标准网关(菱形)表示,'X'图标代表__异或__的含义。请注意内部没有图标的网关默认为排他网关。BPMN 2.0规范不允许在同一个流程中混合使用有及没有X的菱形标志。 - -image::images/bpmn.exclusive.gateway.notation.png[align="center"] - - -[[exclusiveGatewayXML]] - - -===== XML表示 - -排他网关的XML表示格式很简洁:一行定义网关的XML。条件表达式定义在其出口顺序流上。查看<>章节了解这种表达式的可用选项。 - -以下面的模型为例: - -image::images/bpmn.exclusive.gateway.png[align="center"] - -其XML表示如下: - -[source,xml,linenums] ----- - - - - ${input == 1} - - - - ${input == 2} - - - - ${input == 3} - ----- - - -[[bpmnParallelGateway]] - - -==== 并行网关 - -[[bpmnParallelGatewayDescription]] - - -===== 描述 - -网关也可以建模流程中的并行执行。在流程模型中引入并行的最简单的网关,就是**并行网关(parallel gateway)**。它可以将执行__分支(fork)__为多条路径,也可以__合并(join)__多条入口路径的执行。 - -并行网关的功能取决于其入口与出口顺序流: - -* **分支:**所有的出口顺序流都并行执行,为每一条顺序流创建一个并行执行。 -* **合并:**所有到达并行网关的并行执行都会在网关处等待,直到每一条入口顺序流都到达了有个执行。然后流程经过该合并网关继续。 - -请注意,如果并行网关同时具有多条入口与出口顺序流,可以**同时具有分支与合并的行为**。在这种情况下,网关首先合并所有入口顺序流,然后分裂为多条并行执行路径。 - -**与其他网关类型有一个重要区别:并行网关不计算条件。如果连接到并行网关的顺序流上定义了条件,会直接忽略该条件。** - - -[[bpmnParallelGatewayGraphicalNotation]] - - -===== 图示 - -并行网关,用内部带有'加号'图标的网关(菱形)表示,代表__与(AND)__的含义。 - -image::images/bpmn.parallel.gateway.png[align="center"] - -[[bpmnParallelGatewayXML]] - - -===== XML表示 - -定义并行网关只需要一行XML: - -[source,xml,linenums] ----- - ----- - - -实际行为(分支,合并或两者皆有),由连接到该并行网关的顺序流定义。 - -例如,上面的模型表示为下面的XML: - -[source,xml,linenums] ----- - - - - - - - - - - - - - - - - - - - - ----- - - -在上面的例子中,当流程启动后会创建两个任务: - -[source,java,linenums] ----- -ProcessInstance pi = runtimeService.startProcessInstanceByKey("forkJoin"); -TaskQuery query = taskService.createTaskQuery() - .processInstanceId(pi.getId()) - .orderByTaskName() - .asc(); - -List tasks = query.list(); -assertEquals(2, tasks.size()); - -Task task1 = tasks.get(0); -assertEquals("Receive Payment", task1.getName()); -Task task2 = tasks.get(1); -assertEquals("Ship Order", task2.getName()); ----- - -当这两个任务完成后,第二个并行网关会合并这两个执行。由于它只有一条出口顺序流,因此就不会再创建并行执行路径,而只是激活__Archive Order(存档订单)__任务。 - -请注意并行网关不需要“平衡”(也就是说,前后对应的两个并行网关,其入口/出口顺序流的数量不需要一致)。每个并行网关都会简单地等待所有入口顺序流,并为每一条出口顺序流创建并行执行,而不受流程模型中的其他结构影响。因此,下面的流程在BPMN 2.0中是合法的: - -image::images/bpmn.unbalanced.parallel.gateway.png[align="center"] - -[[bpmnInclusiveGateway]] - - -==== 包容网关 - -[[bpmnInclusiveGatewayDescription]] - - -===== 描述 - -可以把**包容网关(inclusive gateway)**看做排他网关与并行网关的组合。与排他网关一样,可以在包容网关的出口顺序流上定义条件,包容网关会计算条件。然而主要的区别是,包容网关与并行网关一样,可以同时选择多于一条出口顺序流。 - -包容网关的功能取决于其入口与出口顺序流: - -* **分支:**流程会计算所有出口顺序流的条件。对于每一条计算为true的顺序流,流程都会创建一个并行执行。 -* **合并:**所有到达包容网关的并行执行,都会在网关处等待。直到每一条具有流程标志(process token)的入口顺序流,都有一个执行到达。这是与并行网关的重要区别。换句话说,包容网关只会等待可以被执行的入口顺序流。在合并后,流程穿过合并并行网关继续。 - -请注意,如果包容网关同时具有多条入口与出口顺序流,可以**同时具有分支与合并的行为**。在这种情况下,网关首先合并所有具有流程标志的入口顺序流,然后为每一个条件计算为true的出口顺序流分裂出并行执行路径。 - -[quote, 译者附(翻译自alfresco文档 http://docs.alfresco.com/process-services1.6/topics/inclusive_gateway.html)] -____ -包容网关的汇聚行为比并行网关更复杂。所有到达包容网关的并行执行,都会在网关等待,直到所有“可以到达”包容网关的执行都“到达”包容网关。 -判断方法为:计算当前流程实例中的所有执行,检查从其位置是否有一条到达包容网关的路径(忽略顺序流上的任何条件)。如果存在这样的执行(可到达但尚未到达),则不会触发包容网关的汇聚行为。 -____ - -[[bpmnInclusiveGatewayGraphicalNotation]] - - -===== 图示 - -包容网关,用内部带有'圆圈'图标的网关(菱形)表示。 - -image::images/bpmn.inclusive.gateway.png[align="center"] - - -[[bpmnInclusiveGatewayXML]] - - -===== XML表示 - -定义包容网关需要一行XML: - -[source,xml,linenums] ----- - ----- - -实际行为(分支,合并或两者皆有),由连接到该包容网关的顺序流定义。 - -例如,上面的模型表现为下面的XML: - -[source,xml,linenums] ----- - - - - - - ${paymentReceived == false} - - - ${shipOrder == true} - - - - - - - - - - - - - - - ----- - -在上面的例子中,当流程启动后,如果流程变量paymentReceived == false且shipOrder == true,会创建两个任务。如果只有一个流程变量等于true,则只会创建一个任务。如果没有条件计算为true,会抛出异常(可通过指定默出口顺序流避免)。在下面的例子中,只会创建ship order(传递订单)一个任务: - -[source,java,linenums] ----- -HashMap variableMap = new HashMap(); -variableMap.put("receivedPayment", true); -variableMap.put("shipOrder", true); - -ProcessInstance pi = runtimeService.startProcessInstanceByKey("forkJoin"); - -TaskQuery query = taskService.createTaskQuery() - .processInstanceId(pi.getId()) - .orderByTaskName() - .asc(); - -List tasks = query.list(); -assertEquals(1, tasks.size()); - -Task task = tasks.get(0); -assertEquals("Ship Order", task.getName()); ----- - -当这个任务完成后,第二个包容网关会合并这两个执行。并且由于它只有一条出口顺序流,所有不会再创建并行执行路径,而只会激活__Archive Order(存档订单)__任务。 - -请注意包容网关不需要“平衡”(也就是说,对应的包容网关,其入口/出口顺序流的数量不需要匹配)。包容网关会简单地等待所有入口顺序流,并为每一条出口顺序流创建并行执行,不受流程模型中的其他结构影响。 - -请注意包容网关不需要“平衡”(也就是说,前后对应的两个包容网关,其入口/出口顺序流的数量不需要一致)。每个包容网关都会简单地等待所有入口顺序流,并为每一条出口顺序流创建并行执行,不受流程模型中的其他结构影响。 - -[[bpmnEventbasedGateway]] - - -==== 基于事件的网关 - -[[eventBasedGatewayDescription]] - - -===== 描述 - -基于事件的网关(event-based gateway)提供了根据事件做选择的方式。网关的每一条出口顺序流都需要连接至一个捕获中间事件。当流程执行到达基于事件的网关时,与等待状态类似,网关会暂停执行,并且为每一条出口顺序流创建一个事件订阅。 - -请注意:基于事件的网关的出口顺序流与一般的顺序流不同。这些顺序流从不实际**执行**。相反,它们用于告知流程引擎:当执行到达一个基于事件的网关时,需要订阅什么事件。有以下限制: - -* 一个基于事件的网关,必须有两条或更多的出口顺序流。 -* 基于事件的网关,只能连接至++intermediateCatchEvent(捕获中间事件)++类型的元素(Flowable不支持在基于事件的网关之后连接“接收任务 Receive Task”)。 -* 连接至基于事件的网关的++intermediateCatchEvent++,必须只有一个入口顺序流。 - - -[[eventBasedGatewayGraphNotation]] - - -===== 图示 - -基于事件的网关,用内部带有特殊图标的网关(菱形)表示。 - -image::images/bpmn.event.based.gateway.notation.png[align="center"] - - -[[eventBasedGatewayXML]] - - -===== XML表示 - -用于定义基于事件的网关的XML元素为++eventBasedGateway++。 - - -[[eventBasedGatewayExample]] - - -===== 示例 - -下面是一个带有基于事件的网关的示例流程。当执行到达基于事件的网关时,流程执行暂停。流程实例订阅alert信号事件,并创建一个10分钟后触发的定时器。流程引擎会等待10分钟,并同时等待信号事件。如果信号在10分钟内触发,则会取消定时器,流程沿着信号继续执行,激活Handle alert用户任务。如果10分钟内没有触发信号,则会继续执行,并取消信号订阅。 - -image::images/bpmn.event.based.gateway.example.png[align="center"] - - -[source,xml,linenums] ----- - - - - - - - - - - - - - - - - - - - - - - PT10M - - - - - - - - - - - - - - - - ----- - - -[[bpmnTask]] - - -=== 任务 - -[[bpmnUserTask]] - - -==== 用户任务 - -[[bpmnUserTaskDescription]] - - -===== 描述 - -“用户任务(user task)”用于对需要人工执行的任务进行建模。当流程执行到达用户任务时,会为指派至该任务的用户或组的任务列表创建一个新任务。 - - -[[bpmnUserTaskGraphicalNotation]] - - -===== 图示 - -用户任务用左上角有一个小用户图标的标准任务(圆角矩形)表示。 - -image::images/bpmn.user.task.png[align="center"] - - -[[bpmnUserTaskXml]] - - -===== XML表示 - -用户任务在XML中如下定义。其中__id__是必须属性,__name__是可选属性。 - -[source,xml,linenums] ----- - ----- - -也可以为用户任务添加描述(description)。事实上任何BPMN 2.0元素都可以有描述。描述由**documentation**元素定义。 - -[source,xml,linenums] ----- - - - - Schedule an engineering meeting for next week with the new hire. - ----- - -可以使用标准Java方式获取描述文本: - -[source,java,linenums] ----- -task.getDescription() ----- - - -[[bpmnUserTaskDueDate]] - - -===== 到期日期 - -每个任务都可以使用一个字段标志该任务的到期日期(due date)。可以使用查询API,查询在给定日期前或后到期的任务。 - -可以在任务定义中使用扩展指定表达式,以在任务创建时设定到期日期。该表达式**必须解析为++java.util.Date++,++java.util.String (ISO8601格式)++,ISO8601时间长度(例如PT50M),或者++null++**。例如,可以使用在流程里前一个表单中输入的日期,或者由前一个服务任务计算出的日期。如果使用的是时间长度,则到期日期基于当前时间加上给定长度计算。例如当dueDate使用“PT30M”时,任务在从现在起30分钟后到期。 - -[source,xml,linenums] ----- - ----- - -任务的到期日期也可以使用++TaskService++,或者在++TaskListener++中使用传递的++DelegateTask++修改。 - - -[[bpmnUserTaskAssignment]] - - -===== 用户指派 - -用户任务可以直接指派(assign)给用户。可以定义**humanPerformer**子元素来实现。__humanPerformer__需要**resourceAssignmentExpression**来实际定义用户。目前,只支持**formalExpressions**。 - -[source,xml,linenums] ----- - - - ... - - - - - kermit - - - ----- - -**只能指定一个**用户作为任务的__humanPerformer__。在Flowable术语中,这个用户被称作**办理人(assignee)**。拥有办理人的任务,在其他人的任务列表中不可见,而只能在该办理人的**个人任务列表**中看到。 - -可以通过TaskService获取特定用户办理的任务: - -[source,java,linenums] ----- -List tasks = taskService.createTaskQuery().taskAssignee("kermit").list(); ----- - -任务也可以放在用户的**候选任务列表**中。在这个情况下,需要使用**potentialOwner(潜在用户)**结构。用法与__humanPerformer__结构类似。请注意需要指定表达式中的每一个元素为用户还是组(引擎无法自行判断)。 - -[source,xml,linenums] ----- - - - ... - - - - - user(kermit), group(management) - - - ----- - -可用如下方法获取定义了__potentialOwner__结构的任务: - -[source,java,linenums] ----- - List tasks = taskService.createTaskQuery().taskCandidateUser("kermit"); ----- - -将获取所有kermit作为**候选用户**的任务,也就是说,表达式含有__user(kermit)__的任务。同时也将获取所有**指派给kermit为其成员的组**的任务(例如,kermit时__management__组的成员,且任务指派给__management__组)。组在运行时解析,并可通过<>管理。 - -如果并未指定给定字符串是用户还是组,引擎默认其为组。下列代码与__声明group(accountancy)__效果一样。 - -[source,xml,linenums] ----- -accountancy ----- - - -[[bpmnUserTaskUserAssignmentExtension]] - - -===== 用于任务指派的Flowable扩展 - -很明显,当指派关系不复杂时,这种用户与组的指派方式十分笨重。为避免这种复杂性,可以在用户任务上使用<>。 - -* **assignee(办理人)属性**:这个自定义扩展用于直接将用户指派至用户任务。 - -[source,xml,linenums] ----- - ----- - -与<>定义的**humanPerformer**结构效果完全相同。 - -* **candidateUsers(候选用户)属性**:这个自定义扩展用于为任务指定候选用户。 - -[source,xml,linenums] ----- - ----- - - -与使用<>定义的**potentialOwner**结构效果完全相同。请注意不需要像在__potentialOwner__中一样,使用__user(kermit)__的声明,因为这个属性只能用于用户。 - - -* **candidateGroups(候选组)attribute**:这个自定义扩展用于为任务指定候选组。 - -[source,xml,linenums] ----- - ----- - -与使用<>定义的**potentialOwner**结构效果完全相同。请注意不需要像在__potentialOwner__中一样,使用__group(management)__的声明,因为这个属性只能用于组。 - -* 可以定义在一个用户任务上同时定义__candidateUsers__与__candidateGroups__。 - -请注意:尽管Flowable提供了<>身份管理组件,但并不会检查给定的用户是否实际存在。这是为了便于将Flowable嵌入应用时,与已有的身份管理解决方案进行集成。 - -[[bpmnUserTaskUserCustomIdentityLinkAssignmentExtension]] - - -===== 自定义身份关联类型 - -在<>中已经介绍过,BPMN标准支持单个指派用户即**humanPerformer**,或者由一组用户构成**potentialOwners**潜在用户池。另外,Flowable为用户任务定义了<>,用于代表任务的**办理人**或者**候选用户**。 - -Flowable支持的身份关联(identity link)类型有: - -[source,java,linenums] ----- -public class IdentityLinkType { - /* Flowable内置角色 */ - public static final String ASSIGNEE = "assignee"; - public static final String CANDIDATE = "candidate"; - public static final String OWNER = "owner"; - public static final String STARTER = "starter"; - public static final String PARTICIPANT = "participant"; -} ----- - - -BPMN标准及Flowable示例中,身份认证是**用户**与**组**。在前一章节提到过,Flowable的身份管理实现并不适用于生产环境,而需要在支持的认证概要下自行扩展。 - -如果需要添加额外的关联类型,可按照下列语法,使用自定义资源作为扩展元素: - -[source,xml,linenums] ----- - - - - - user(kermit), group(management) - - - - ----- - -自定义关联表达式添加至__TaskDefinition__类: - -[source,java,linenums] ----- - -protected Map> customUserIdentityLinkExpressions = - new HashMap>(); -protected Map> customGroupIdentityLinkExpressions = - new HashMap>(); - -public Map> getCustomUserIdentityLinkExpressions() { - return customUserIdentityLinkExpressions; -} - -public void addCustomUserIdentityLinkExpression( - String identityLinkType, Set idList) { - - customUserIdentityLinkExpressions.put(identityLinkType, idList); -} - -public Map> getCustomGroupIdentityLinkExpressions() { - return customGroupIdentityLinkExpressions; -} - -public void addCustomGroupIdentityLinkExpression( - String identityLinkType, Set idList) { - - customGroupIdentityLinkExpressions.put(identityLinkType, idList); -} ----- - -这些方法将在运行时,由__UserTaskActivityBehavior__的__handleAssignments__方法调用。 - -最后,需要扩展__IdentityLinkType__类,以支持自定义身份关联类型: - -[source,java,linenums] ----- -package com.yourco.engine.task; - -public class IdentityLinkType extends org.flowable.engine.task.IdentityLinkType { - - public static final String ADMINISTRATOR = "administrator"; - - public static final String EXCLUDED_OWNER = "excludedOwner"; -} ----- - - -[[bpmnUserTaskUserCustomAssignmentTaskListeners]] - - -===== 通过任务监听器自定义指派 - -如果上面的方式仍不能满足要求,可以在创建事件(create event)上使用<>,调用自定义指派逻辑: - -[source,xml,linenums] ----- - - - - - ----- - -传递至++TaskListener++的++DelegateTask++,可用于设置办理人与候选用户/组: - -[source,java,linenums] ----- -public class MyAssignmentHandler implements TaskListener { - - public void notify(DelegateTask delegateTask) { - // 在这里执行自定义身份查询 - - // 然后调用如下命令: - delegateTask.setAssignee("kermit"); - delegateTask.addCandidateUser("fozzie"); - delegateTask.addCandidateGroup("management"); - ... - } - -} ----- - -当使用Spring时,可以按上面章节的介绍使用自定义指派属性,并交由使用<>、带有<>的Spring bean,监听任务__创建__事件。在下面的例子中,通过调用++ldapService++ Spring bean的++findManagerOfEmployee++方法设置办理人。传递的__emp__参数是一个流程变量。 - -[source,xml,linenums] ----- - ----- - -也可以用于候选用户与组: - -[source,xml,linenums] ----- - ----- - -请注意调用方法的返回类型必须是++String++或++Collection++(候选用户或组): - -[source,java,linenums] ----- -public class FakeLdapService { - - public String findManagerForEmployee(String employee) { - return "Kermit The Frog"; - } - - public List findAllSales() { - return Arrays.asList("kermit", "gonzo", "fozzie"); - } - -} ----- - - -[[bpmnScriptTask]] - - -==== 脚本任务 - -[[bpmnScriptTaskDescription]] - - -===== 描述 - -脚本任务(script task)是自动执行的活动。当流程执行到达脚本任务时,会执行相应的脚本。 - - -[[bpmnScriptTaskGraphicalNotation]] - - -===== 图示 - -脚本任务用左上角有一个小“脚本”图标的标准BPMN 2.0任务(圆角矩形)表示。 - -image::images/bpmn.scripttask.png[align="center"] - - -[[bpmnScriptTaskXml]] - - -===== XML表示 - -脚本任务使用**script**与**scriptFormat**元素定义。 - -[source,xml,linenums] ----- - - - ----- - -**scriptFormat**属性的值,必须是兼容link:$$http://jcp.org/en/jsr/detail?id=223$$[JSR-223](Java平台脚本)的名字。默认情况下,JavaScript包含在每一个JDK中,因此不需要添加任何JAR文件。如果想使用其它(兼容JSR-223的)脚本引擎,则需要在classpath中添加相应的jar,并使用适当的名字。例如,Flowable单元测试经常使用Groovy,因为其语法与Java十分相似。 - -请注意Groovy脚本引擎与groovy-jsr223 JAR捆绑在一起。在Groovy 4.0版本以前,脚本引擎是Groovy JAR的一部分。因此,必须添加如下依赖: - -[source,xml,linenums] ----- - - org.apache.groovy - groovy-jsr223 - 4.x.x - ----- - - -[[bpmnScriptTaskVariables]] - - -===== 脚本中的变量 - -到达脚本引擎的执行中,所有的流程变量都可以在脚本中使用。在这个例子里,脚本变量__'inputArray'__实际上就是一个流程变量(一个integer的数组)。 - -[source,xml,linenums] ----- - ----- - -也可以简单地调用__execution.setVariable("variableName", variableValue)__,在脚本中设置流程变量。默认情况下,变量不会自动储存(**请注意,在一些早期版本中是会储存的!**)。可以将++scriptTask++的++autoStoreVariables++参数设置为++true++,以自动保存任何在脚本中定义的变量(例如上例中的__sum__)。然而这并不是最佳实践。**最佳实践是显式调用execution.setVariable()**,因为在JDK近期的一些版本中,某些脚本语言不能自动保存变量。查看link:$$http://www.jorambarrez.be/blog/2013/03/25/bug-on-jdk-1-7-0_17-when-using-scripttask-in-activiti/$$[这个链接]了解更多信息。 - - -[source,xml,linenums] ----- - ----- - -这个参数的默认值为++false++。也就是说如果在脚本任务定义中忽略这个参数,则脚本声明的所有变量将只在脚本执行期间有效。 - -在脚本中设置变量的例子: - -[source,xml,linenums] ----- - ----- - -请注意:下列名字是保留字,**不能用于**变量名:**out,out:print,lang:import,context,elcontext**。 - - -[[bpmnScriptTaskResultValue]] - - -===== 脚本任务的结果 - -脚本任务的返回值,可以通过为脚本任务定义的__'flowable:resultVariable'__属性设置为流程变量。可以是已经存在的,或者新的流程变量。如果指定为已存在的流程变量,则流程变量的值会被脚本执行的结果值覆盖。如果不指定结果变量名,则脚本结果值将被忽略。 - -[source,xml,linenums] ----- - - - ----- - -在上面的例子中,脚本执行的结果(解析表达式__'#{echo}'__的值),将在脚本完成后,设置为名为__'myVar'__的流程变量。 - -[[_security]] -===== 安全性 - -当使用__javascript__作为脚本语言时,可以使用__“安全脚本(secure scripting)”__。参见<>章节。 - - -[[bpmnJavaServiceTask]] - - -==== Java服务任务 - -[[bpmnJavaServiceTaskDescription]] - - -===== 描述 - -Java服务任务(Java service task)用于调用Java类。 - - -[[bpmnJavaServiceTaskGraphicalNotation]] - - -===== 图示 - -服务任务用左上角有一个小齿轮图标的圆角矩形表示。 - -image::images/bpmn.java.service.task.png[align="center"] - - -[[bpmnJavaServiceTaskXML]] - - -===== XML表示 - -有四种方法声明如何调用Java逻辑: - -* 指定实现了JavaDelegate或ActivityBehavior的类 -* 调用解析为委托对象(delegation object)的表达式 -* 调用方法表达式(method expression) -* 对值表达式(value expression)求值 - -使用**'flowable:class'**属性提供全限定类名(fully qualified classname),指定流程执行时调用的类。 - -[source,xml,linenums] ----- - ----- - - -查看<>章节,了解使用这种类的更多信息。 - -也可以使用解析为对象的表达式。该对象必须遵循的规则,与使用++flowable:class++创建的对象规则相同(查看<>)。 - -[source,xml,linenums] ----- - ----- - -++delegateExpressionBean++是一个实现了++JavaDelegate++接口的bean,定义在Spring容器中。 - -使用**flowable:expression**属性指定需要计算的UEL方法表达式。 - -[source,xml,linenums] ----- - ----- - -将在名为++printer++的对象上调用++printMessage++方法(不带参数)。 - -也可以为表达式中使用的方法传递变量。 - -[source,xml,linenums] ----- - ----- - -将在名为++printer++的对象上调用++printMessage++方法。传递的第一个参数为++DelegateExecution++,名为++execution++,在表达式上下文中默认可用。传递的第二个参数,是当前执行中,名为++myVar++变量的值。 - -可以使用**flowable:expression**属性指定需要计算的UEL值表达式。 - -[source,xml,linenums] ----- - ----- - -会调用名为++split++的bean的++ready++参数的getter方法,++getReady++(不带参数)。该对象会被解析为执行的流程变量或(如果可用的话)Spring上下文中的bean。 - - -[[bpmnJavaServiceTaskImplementation]] - - -===== 实现 - -要实现可以在流程执行中调用的类,需要实现__org.flowable.engine.delegate.JavaDelegate__接口,并在__execute__方法中提供所需逻辑。当流程执行到达该活动时,会执行方法中定义的逻辑,并按照BPMN 2.0的默认方法离开活动。 - -下面是一个Java类的示例,用于将流程变量String改为大写。这个类需要实现__org.flowable.engine.delegate.JavaDelegate__接口,因此需要实现__execute(DelegateExecution)__方法。这个方法就是引擎将调用的方法,需要实现业务逻辑。可以通过link:$$http://flowable.org/javadocs/org/flowable/engine/delegate/DelegateExecution.html$$[DelegateExecution]接口(点击链接获取该接口操作的详细Javadoc)访问流程实例信息,如流程变量等。 - -[source,java,linenums] ----- -public class ToUppercase implements JavaDelegate { - - public void execute(DelegateExecution execution) { - String var = (String) execution.getVariable("input"); - var = var.toUpperCase(); - execution.setVariable("input", var); - } - -} ----- - - -请注意:**只会为serviceTask上定义的Java类创建一个实例**。所有流程实例共享同一个类实例,用于调用__execute(DelegateExecution)__。这意味着该类不能有任何成员变量,并需要是线程安全的,因为它可能会在不同线程中同时执行。这也影响了<>的使用方法。(译者注:原文可能较老,不正确。5.21中,flowable:class指定的类,会在流程实例启动时,为每个活动分别进行实例化。不过,当该活动在流程中重复执行,或者为多实例时,使用的都会是同一个类实例。) - -在流程定义中引用(如++flowable:class++)的类,**不会在部署时实例化**。只有当流程执行第一次到达该类使用的地方时,才会创建该类的实例。如果找不到这个类,会抛出++FlowableException++。这是因为部署时的环境(更准确的说__classpath__),与实际运行的环境经常不一样。例如当使用__ant__或者Flowable应用中业务存档上传的方式部署的流程,其classpath中不会自动包含流程引用的类。 - -<>也可以使用实现了__org.flowable.engine.impl.delegate.ActivityBehavior__接口的类。该实现可以访问更强大的引擎功能,例如,可以影响流程的控制流程。请注意这并不是很好的实践,需要避免这么使用。建议只有在高级使用场景下,并且你确知在做什么的时候,才使用__ActivityBehavior__接口。 - - -[[serviceTaskFieldInjection]] - - -===== 字段注入 - -可以为委托类的字段注入值。支持下列注入方式: - -* 字符串常量 -* 表达式 - -如果可以的话,会按照Java Bean命名约定(例如,++firstName++成员使用setter ++setFirstName(...)++),通过委托类的公有setter方法,注入变量。如果该字段没有可用的setter,会直接设置该委托类的私有成员的值。有的环境中,SecurityManagers不允许修改私有字段,因此为想要注入的字段暴露一个公有setter方法,是更安全的做法。 - -**不论在流程定义中声明的是什么类型的值,注入对象的setter/私有字段的类型,总是++org.flowable.engine.delegate.Expression++。解析表达式后,可以被转型为合适的类型。** - -__'flowable:class'__属性支持字段注入。也可以在使用__flowable:delegateExpression__属性时,进行字段注入。然而考虑到线程安全,需要遵循特殊的规则(参见下一章节)。 - -下面的代码片段展示了如何为类中声明的字段注入常量值。请注意按照BPMN 2.0 XML概要的要求,**在实际字段注入声明前,需要先声明'extensionElements'XML元素**。 - -[source,xml,linenums] ----- - - - - - ----- - -++ToUpperCaseFieldInjected++类有一个字段++text++,为++org.flowable.engine.delegate.Expression++类型。当调用++text.getValue(execution)++时,会返回配置的字符串++Hello World++: - -[source,java,linenums] ----- -public class ToUpperCaseFieldInjected implements JavaDelegate { - - private Expression text; - - public void execute(DelegateExecution execution) { - execution.setVariable("var", ((String)text.getValue(execution)).toUpperCase()); - } - -} ----- - -另外,对于较长文本(例如邮件正文),可以使用__'flowable:string'__子元素: - -[source,xml,linenums] ----- - - - - - This is a long string with a lot of words and potentially way longer even! - - - - ----- - -可以使用表达式在运行时动态解析注入的值。这种表达式可以使用流程变量,或者(若使用Spring)Spring定义的Bean。在<>中提到过,当服务任务中使用__flowable:class__属性时,该Java类的实例在所有流程实例中共享。要动态地为字段注入值,可以在++org.flowable.engine.delegate.Expression++中注入值或方法表达式,它们会通过++execute++方法传递的++DelegateExecution++计算/调用。 - -下面的示例类使用了注入的表达式,并使用当前的++DelegateExecution++解析它们。调用__genderBean__方法时传递的是__gender__变量。完整的代码与测试可以在++org.flowable.examples.bpmn.servicetask.JavaServiceTaskTest.testExpressionFieldInjection++中找到 - -[source,xml,linenums] ----- - - - - - ${genderBean.getGenderString(gender)} - - - Hello ${gender == 'male' ? 'Mr.' : 'Mrs.'} ${name} - - - ----- - -[source,java,linenums] ----- -public class ReverseStringsFieldInjected implements JavaDelegate { - - private Expression text1; - private Expression text2; - - public void execute(DelegateExecution execution) { - String value1 = (String) text1.getValue(execution); - execution.setVariable("var1", new StringBuffer(value1).reverse().toString()); - - String value2 = (String) text2.getValue(execution); - execution.setVariable("var2", new StringBuffer(value2).reverse().toString()); - } -} ----- - - -另外,为避免XML太过冗长,可以将表达式设置为属性,而不是子元素。 - -[source,xml,linenums] ----- - - ----- - -[[serviceTaskFieldInjectionThreadSafety]] - -===== 字段注入与线程安全 - -通常情况下,在服务任务中使用Java委托与字段注入是线程安全的。然而,有些情况下不能保证线程安全。这取决于设置,或Flowable运行的环境。 - -当使用__flowable:class__属性时,使用字段注入总是线程安全的(译者注:仍不完全安全,如对于多实例服务任务,使用的是同一个实例)。对于引用了某个类的每一个服务任务,都会实例化新的实例,并且在创建实例时注入一次字段。在不同的任务或流程定义中多次使用同一个类没有问题。 - -当使用__flowable:expression__属性时,不能使用字段注入。只能通过方法调用传递变量。总是线程安全的。 - -当使用__flowable:delegateExpression__属性时,委托实例的线程安全性,取决于表达式解析的方式。如果该委托表达式在多个任务或流程定义中重复使用,并且表达式总是返回相同的示例,则字段注入**不是线程安全的**。让我们看几个例子。 - -假设表达式为__${factory.createDelegate(someVariable)}__,其中factory为引擎可用的Java bean(例如使用Spring集成时的Spring bean),并在每次表达式解析时创建新的实例。这种情况下,使用字段注入时,没有线程安全性问题:每次表达式解析时,都会注入新实例的字段。 - -然而,如果表达式为__${someJavaDelegateBean}__,解析为JavaDelegate的实现,并且在创建单例的环境(如Spring)中运行。当在不同的任务或流程定义中使用这个表达式时,表达式总会解析为相同的实例。这种情况下,使用字段注入不是线程安全的。例如: - -[source,xml,linenums] ----- - - - - - - - - - - - - - ----- - -这段示例代码有两个服务任务,使用同一个委托表达式,但是__expression__字段填写不同的值。**如果该表达式解析为相同的实例,就会在并发场景下,注入__someField__字段时出现竞争条件**。 - -最简单的解决方法是: - -* 使用表达式代替直接使用Java委托,并将所需数据通过方法参数传递给委托。 -* 或者,在每次委托表达式解析时,返回委托类的新实例。这意味着这个bean的scope必须是**prototype(原型)**(例如在委托类上加上@Scope(SCOPE_PROTOTYPE)注解)。 - -在Flowable 5.22版本中,可以通过配置流程引擎配置,禁用在委托表达式上使用字段注入。需要设置__delegateExpressionFieldInjectionMode__参数(取__org.flowable.engine.imp.cfg.DelegateExpressionFieldInjectionMode__枚举中的值)。 - -可使用下列选项: - -* **DISABLED(禁用)**:当使用委托表达式时,完全禁用字段注入。不会再尝试进行字段注入。这是最安全的方式,保证线程安全。 -* **COMPATIBILITY(兼容)**:在这个模式下,行为与V5.21之前完全一样:可以在委托表达式中使用字段注入,如果委托类中没有定义该字段,会抛出异常。这是最不线程安全的模式,但可以保证历史版本兼容性,也可以在委托表达式只在一个任务中使用的时候(因此不会产生并发竞争条件),安全使用。 -* **MIXED(混合)**:可以在使用委托表达式时注入,但当委托中没有定义字段时,不会抛出异常。这样可以在部分委托(比如不是单例的实例)中使用注入,而在部分委托中不使用注入。 - -* **Flowable 5.x版本的默认模式为COMPATIBILITY**。 -* **Flowable 6.x版本的默认模式为MIXED**。 - -例如,假设使用__MIXED__模式,并使用Spring集成,在Spring配置中定义了如下bean: - -[source,xml,linenums] ----- - - - ----- - -第一个bean是一般的Spring bean,因此是单例的。第二个bean的scope为__prototype__,因此每次请求这个bean时,Spring容器都会返回一个新实例。 - -在以下流程定义中: - -[source,xml,linenums] ----- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ----- - -有四个服务任务,第一、二个使用__${prototypeDelegateExpressionBean}__委托表达式,第三、四个使用__${singletonDelegateExpressionBean}__委托表达式。 - -先看原型bean: - -[source,java,linenums] ----- -public class PrototypeDelegateExpressionBean implements JavaDelegate { - - public static AtomicInteger INSTANCE_COUNT = new AtomicInteger(0); - - private Expression fieldA; - private Expression fieldB; - private Expression resultVariableName; - - public PrototypeDelegateExpressionBean() { - INSTANCE_COUNT.incrementAndGet(); - } - - @Override - public void execute(DelegateExecution execution) { - - Number fieldAValue = (Number) fieldA.getValue(execution); - Number fieldValueB = (Number) fieldB.getValue(execution); - - int result = fieldAValue.intValue() + fieldValueB.intValue(); - execution.setVariable(resultVariableName.getValue(execution).toString(), result); - } - -} ----- - -在运行上面流程定义的流程实例后,__INSTANCE_COUNT__的值为__2__。这是因为每次解析__${prototypeDelegateExpressionBean}__时,都会创建新实例。可以看到三个__Expression__成员字段的注入没有任何问题。 - -单例bean则有一点区别: - -[source,java,linenums] ----- -public class SingletonDelegateExpressionBean implements JavaDelegate { - - public static AtomicInteger INSTANCE_COUNT = new AtomicInteger(0); - - public SingletonDelegateExpressionBean() { - INSTANCE_COUNT.incrementAndGet(); - } - - @Override - public void execute(DelegateExecution execution) { - - Expression fieldAExpression = DelegateHelper.getFieldExpression(execution, "fieldA"); - Number fieldA = (Number) fieldAExpression.getValue(execution); - - Expression fieldBExpression = DelegateHelper.getFieldExpression(execution, "fieldB"); - Number fieldB = (Number) fieldBExpression.getValue(execution); - - int result = fieldA.intValue() + fieldB.intValue(); - - String resultVariableName = DelegateHelper.getFieldExpression(execution, - "resultVariableName").getValue(execution).toString(); - execution.setVariable(resultVariableName, result); - } - -} ----- - -在对于单例bean,__INSTANCE_COUNT__总是__1__。在这个委托中,没有__Expression__成员字段(使用__MIXED__模式)。而在__COMPATIBILITY__模式下,就会抛出异常,因为需要有成员字段。这个bean也可以使用__DISABLED__模式,但会禁用上面进行了字段注入的原型bean。 - -在委托的代码里,使用了**org.flowable.engine.delegate.DelegateHelper**。它提供了一些有用的工具方法,用于执行相同的逻辑,并且在单例中是线程安全的。与注入__Expression__不同,它通过__getFieldExpression__读取。这意味着在服务任务的XML里,字段定义与单例bean完全相同。查看上面的XML代码,可以看到定义是相同的,只是实现逻辑不同。 - -技术提示:__getFieldExpression__直接读取BpmnModel,并在方法执行时创建表达式,因此是线程安全的。 - -* 在Flowable V5.x版本中,(由于架构缺陷)不能在__ExecutionListener__或__TaskListener__中使用DelegateHelper。要保证监听器的线程安全,仍需使用表达式,或确保每次解析委托表达式时,都创建新实例。 -* 在Flowable V6.x版本中,在__ExecutionListener__或__TaskListener__中可以使用DelegateHelper。例如在V6.x版本中,下列代码可以使用**DelegateHelper**: - - -[source,xml,linenums] ----- - - - - - - ----- - -其中__testExecutionListener__解析为ExecutionListener接口的一个实现的实例: - -[source,java,linenums] ----- -@Component("testExecutionListener") -public class TestExecutionListener implements ExecutionListener { - - @Override - public void notify(DelegateExecution execution) { - Expression inputExpression = DelegateHelper.getFieldExpression(execution, "input"); - Number input = (Number) inputExpression.getValue(execution); - - int result = input.intValue() * 100; - - Expression resultVarExpression = DelegateHelper.getFieldExpression(execution, "resultVar"); - execution.setVariable(resultVarExpression.getValue(execution).toString(), result); - } - -} ----- - - -[[serviceTaskResultValue]] - - -===== 服务任务的结果 - -服务执行的返回值(仅对使用表达式的服务任务),可以通过为服务任务定义的__'flowable:resultVariable'__属性设置为流程变量。可以是已经存在的,或者新的流程变量。 -如果指定为已存在的流程变量,则流程变量的值会被服务执行的结果值覆盖。 -如果使用__'flowable:useLocalScopeForResultVariable'__,则会将结果值设置为局部变量。 -如果不指定结果变量名,则服务任务的结果值将被忽略。 - -[source,xml,linenums] ----- - ----- - -在上例中,服务执行的结果(流程变量或Spring bean中,使用__'myService'__名字所获取的对象,调用__'doSomething()'__方法的返回值),在服务执行完成后,会设置为名为__'myVar'__的流程变量。 - -[[serviceTaskTriggerable]] - - -===== 可触发 - -一种常见的模式是发送JMS消息或HTTP调用触发外部服务,然后流程实例进入等待状态。之后外部系统会回复响应,流程实例继续执行下一个活动。在默认的BPMN中,需要使用服务任务和接收任务(receive task)。但是这样会引入竞争条件:外部服务的响应可能会早于流程实例持久化及接收任务激活。为了解决这个问题,Flowable为服务任务增加了triggerable(可触发)属性,可以将服务任务转变为执行服务逻辑,并在继续执行之前等待外部触发的任务。如果在可触发服务任务上同时设置异步(async 为 true),则流程实例会先持久化,然后在异步作业中执行服务任务逻辑。在BPMN XML中,可以这样实现可触发服务任务: - -[source,xml,linenums] ----- - ----- - -外部服务可以同步或异步地触发等待中的流程实例。为了避免乐观锁异常,最好使用异步触发。默认情况下,异步作业是排他的,也就是说流程实例会被锁定,以保证流程实例中的其他活动不会影响到触发器的逻辑。可以使用RuntimeService的triggerAsync方法,异步触发等待中的流程实例。当然还是可以使用RuntimeService的trigger方法,同步触发。 - -[[serviceTaskExceptionHandling]] - - -===== 处理异常 - -当执行自定义逻辑时,通常需要捕获并在流程中处理特定的业务异常。Flowable提供了多种选择。 - -[[serviceTaskBpmnErrors]] - - -====== 抛出BPMN错误 - -可以在服务任务或脚本任务的用户代码中抛出BPMN错误。可以在Java委托、脚本、表达式与委托表达式中,抛出特殊的FlowableException:__BpmnError__。引擎会捕获这个异常,并将其转发至合适的错误处理器,如错误边界事件或错误事件子流程。 - -[source,java,linenums] ----- -public class ThrowBpmnErrorDelegate implements JavaDelegate { - - public void execute(DelegateExecution execution) throws Exception { - try { - executeBusinessLogic(); - } catch (BusinessException e) { - throw new BpmnError("BusinessExceptionOccurred"); - } - } - -} ----- - -构造函数的参数是错误代码。错误代码决定了处理这个错误的错误处理器。参见<>了解如何捕获BPMN错误。 - -这个机制**只应该用于业务错误**,需要通过流程中定义的错误边界事件或错误事件子流程处理。技术错误应该通过其他异常类型表现,并且通常不在流程内部处理。 - -[[exceptionMapping]] - -====== 异常映射 - -也可以使用++mapException++扩展,直接将Java异常映射至业务异常(错误)。单映射是最简单的形式: - -[source,xml,linenums] ----- - - - org.flowable.SomeException - - - ----- - -在上面的代码中,如果服务任务抛出++org.flowable.SomeException++的实例,引擎会捕获该异常,并将其转换为带有给定errorCode的BPMN错误。然后就可以像普通BPMN错误完全一样地处理。其他的异常没有映射,仍将抛出至API调用处。 - -也可以在单行中使用++includeChildExceptions++属性,映射特定异常的所有子异常。 - -[source,xml,linenums] ----- - - - org.flowable.SomeException - - - ----- - -上面的代码中,Flowable会将++SomeException++的任何直接或间接的子类,转换为带有指定错误代码的BPMN错误。 -当未指定++includeChildExceptions++时,视为“false”。 - -默认映射最泛用。默认映射是一个不指定类的映射,可以匹配任何Java异常: - -[source,xml,linenums] ----- - - - - - ----- - -除了默认映射,会按照从上至下的顺序检查映射,使用第一个匹配的映射。只在所有映射都不能成功匹配时使用默认映射。 -只有第一个不指定类的映射会作为默认映射。默认映射忽略++includeChildExceptions++。 - - -[[serviceTaskExceptionSequenceFlow]] - - -====== 异常顺序流 - -<> - - -也可以选择在发生异常时,将流程执行路由至另一条路径。下面是一个例子。 - -[source,xml,linenums] ----- - - - - - ----- - -服务任务有两条出口顺序流,命名为++exception++与++no-exception++。在发生异常时,使用顺序流ID控制流程流向: - -[source,java,linenums] ----- -public class ThrowsExceptionBehavior implements ActivityBehavior { - - public void execute(DelegateExecution execution) { - String var = (String) execution.getVariable("var"); - - String sequenceFlowToTake = null; - try { - executeLogic(var); - sequenceFlowToTake = "no-exception"; - } catch (Exception e) { - sequenceFlowToTake = "exception"; - } - DelegateHelper.leaveDelegate(execution, sequenceFlowToTake); - } - -} ----- - - -[[serviceTaskCallActivitiService]] - - -===== 在JavaDelegate中使用Flowable服务 - -有的时候,需要在Java服务任务中使用Flowable服务(例如调用活动(call activity)不满足需要的场景下,使用RuntimeService启动流程实例)。 - -[source,java,linenums] ----- -public class StartProcessInstanceTestDelegate implements JavaDelegate { - - public void execute(DelegateExecution execution) throws Exception { - RuntimeService runtimeService = Context.getProcessEngineConfiguration().getRuntimeService(); - runtimeService.startProcessInstanceByKey("myProcess"); - } - -} ----- - -可以使用这个接口访问所有Flowable服务API。 - -使用这些API调用造成的所有数据变更都在当前事务中。在依赖注入的环境(如Spring或CDI,无论是否使用启用JTA的数据源)下也可以使用这个接口。例如,下面的代码片段与上面的代码具有相同功能,但通过注入而不是__org.flowable.engine.EngineServices__接口获得RuntimeService。 - -[source,java,linenums] ----- -@Component("startProcessInstanceDelegate") -public class StartProcessInstanceTestDelegateWithInjection { - - @Autowired - private RuntimeService runtimeService; - - public void startProcess() { - runtimeService.startProcessInstanceByKey("oneTaskProcess"); - } - -} ----- - -**重要技术提示:**由于服务调用是在当前事务中完成的,因此在服务任务执行前产生或修改的数据尚未存入数据库。所有API调用都基于数据库数据处理,这意味着这些未提交的修改在服务任务的API调用中“不可见”。 - -[[bpmnWebserviceTask]] - - -==== Web服务任务 - -[[bpmnWebserviceTaskDescription]] - - -===== 描述 - -Web服务任务(Web service task)用于同步地调用外部的Web服务。 - -[[bpmnWebserviceTaskGraphicalNotation]] - - -===== 图示 - -Web服务任务与Java服务任务图标一样。 - -image::images/bpmn.web.service.task.png[align="center"] - - -[[bpmnWebserviceTaskXML]] - - -===== XML表示 - -使用Web服务之前,需要导入其操作及复杂的类型。可以使用导入标签(import tag)指向Web服务的WSDL,自动处理: - -[source,xml,linenums] ----- - ----- - -按照上面的声明,Flowable会导入定义,但不会创建条目定义(item definition)与消息。如果需要调用一个名为'prettyPrint'的方法,则需要先为请求及回复消息创建对应的消息与条目定义: - -[source,xml,linenums] ----- - - - - - ----- - -在声明服务任务前,需要定义实际引用Web服务的BPMN接口与操作。基本上,是定义“接口”与所需的“操作”。对每一个操作都可以重复使用之前定义的“传入”与“传出”消息。例如,下面的声明定义了“counter”接口及“prettyPrintCountOperation”操作: - -[source,xml,linenums] ----- - - - tns:prettyPrintCountRequestMessage - tns:prettyPrintCountResponseMessage - - ----- - -这样就可以使用##WebService实现,声明Web服务任务,并引用Web服务操作。 - -[source,xml,linenums] ----- - ----- - -[[bpmnWebserviceTaskIOSpecification]] - - -===== Web服务任务IO规范 - -除非使用简化方法处理输入与输出数据关联(见下),否则需要为每个Web服务任务声明IO规范,指出任务的输入与输出是什么。这个方法很简单,也兼容BPMN 2.0。在prettyPrint例子中,根据之前声明的条目定义,定义输入与输出: - -[source,xml,linenums] ----- - - - - - dataInputOfServiceTask - - - dataOutputOfServiceTask - - ----- - -[[bpmnWebserviceTaskDataInputAssociation]] - - -===== Web服务任务数据输入关联 - -有两种指定数据输入关联的方式: - -* 使用表达式 -* 使用简化方法 - -使用表达式指定数据输入关联,需要定义源及目标条目,并指定每个条目与字段的关联。下面的例子中,我们针对每个条目,指定prefix与suffix字段: - -[source,xml,linenums] ----- - - dataInputOfProcess - dataInputOfServiceTask - - ${dataInputOfProcess.prefix} - ${dataInputOfServiceTask.prefix} - - - ${dataInputOfProcess.suffix} - ${dataInputOfServiceTask.suffix} - - ----- - -也可以使用更简单明了的简化方法。'sourceRef'元素是一个Flowable变量名,'targetRef'是条目定义的参数。在下面的例子里,将'PrefixVariable'变量的值关联至'prefix'字段,并将'SuffixVariable'变量的值关联至'suffix'字段。 - -[source,xml,linenums] ----- - - PrefixVariable - prefix - - - SuffixVariable - suffix - ----- - -[[bpmnWebserviceTaskDataOutputAssociation]] - - -===== Web服务任务数据输出关联 - -有两种指定数据输出关联的方式: - - -* 使用表达式 -* 使用简化方法 - - -使用表达式指定数据输出关联,需要定义目标变量及源表达式。这种方法很简单,与数据输入关联类似: - -[source,xml,linenums] ----- - - dataOutputOfProcess - ${dataOutputOfServiceTask.prettyPrint} - ----- - -也可以使用更简单明了的简化方法。'sourceRef'是条目定义的参数,'targetRef'元素是Flowable变量名。这种方法很简单,与数据输入关联类似: - -[source,xml,linenums] ----- - - prettyPrint - OutputVariable - ----- - -[[bpmnBusinessRuleTask]] - - -==== 业务规则任务 - -[[bpmnBusinessRuleTaskDescription]] - - -===== 描述 - -业务规则任务(business rule task)用于同步地执行一条或多条规则。Flowable使用名为Drools Expert的Drools规则引擎执行业务规则。目前,业务规则中包含的.drl文件,必须与定义了业务规则服务并执行规则的流程定义一起部署。这意味着流程中使用的所有.drl文件都需要打包在流程BAR文件中,与任务表单等类似。要了解如何为Drools Expert创建业务规则,请访问位于link:$$http://www.jboss.org/drools/documentation$$[JBoss Drools]的Drools文档。 - - -如果想要使用自己的规则任务实现,比如希望通过不同方法使用Drools,或者想使用完全不同的规则引擎,则可以使用BusinessRuleTask的class或expression属性。这样它会与link:$$#bpmnJavaServiceTask$$[服务任务]的行为完全相同。 - - -[[bpmnBusinessRuleTaskGraphicalNotation]] - - -===== 图示 - -业务规则任务显示为带有表格图标的圆角矩形。 - -image::images/bpmn.business.rule.task.png[align="center"] - - -[[bpmnBusinessRuleTaskXML]] - - -===== XML表示 - -要执行与流程定义在同一个BAR文件中部署的一条或多条业务规则,需要定义输入与结果变量。输入变量可以用流程变量的列表定义,使用逗号分隔。输出变量只能有一个变量名,将执行业务规则后的输出对象存储至流程变量。请注意结果变量会包含对象的List。如果没有指定结果变量名,默认为org.flowable.engine.rules.OUTPUT。 - -下面的业务规则任务,执行与流程定义一起部署的所有业务规则: - -[source,xml,linenums] ----- - - - - - - - - - - - - ----- - -也可以将业务规则任务配置为只执行部署的.drl文件中的一组规则。要做到这一点,需要指定规则名字的列表,用逗号分隔。 - -[source,xml,linenums] ----- - ----- - -这样只会执行rule1与rule2。 - -也可以定义需要从执行中排除的规则列表。 - -[source,xml,linenums] ----- - ----- - -这个例子中,除了rule1与rule2之外,其它所有与流程定义一起部署在同一个BAR文件中的规则都会被执行。 - -前面提到过,还可以自行指定BusinessRuleTask的实现: - -[source,xml,linenums] ----- - ----- - -这样配置的业务规则任务与服务任务的行为完全一样,但仍保持业务规则任务的图标,代表在这里处理业务规则。 - - -[[bpmnEmailTask]] - - -==== 邮件任务 - -Flowable让你可以通过自动的邮件服务任务(email task),增强业务流程。可以向一个或多个收信人发送邮件,支持cc,bcc,HTML文本,等等。请注意邮件任务**不是**BPMN 2.0规范的“官方”任务(所以也没有专用图标)。因此,在Flowable中,邮件任务实现为一种特殊的服务任务。 - -[[bpmnEmailTaskServerConfiguration]] - - -===== 配置邮件服务器 - -Flowable引擎使用支持SMTP的外部邮件服务器发送邮件。为了发送邮件,引擎需要了解如何连接邮件服务器。可以在__flowable.cfg.xml__配置文件中设置下面的参数: - -[options="header"] -|=============== -|参数|必填?|描述 -|mailServerHost|否|邮件服务器的主机名(如mail.mycorp.com)。默认为++localhost++ -|mailServerPort|是,如果不使用默认端口|邮件服务器的SMTP端口。默认值为__25__ -|mailServerDefaultFrom|否|若用户没有提供地址,默认使用的邮件发件人地址。默认为__flowable@localhost___ -|mailServerUsername|若服务器需要|部分邮件服务器发信时需要进行认证。默认为空。 -|mailServerPassword|若服务器需要|部分邮件服务器发信时需要进行认证。默认为空。 -|mailServerUseSSL|若服务器需要|部分邮件服务器要求ssl通信。默认设置为false。 -|mailServerUseTLS|若服务器需要|部分邮件服务器要求TLS通信(例如gmail)。默认设置为false。 - -|=============== - - -[[bpmnEmailTaskUsage]] - - -===== 定义邮件任务 - -邮件任务实现为特殊的<>,将服务任务的__type__定义为__'mail'__进行设置。 - -[source,xml,linenums] ----- - ----- - -邮件任务通过<>配置。这些参数的值可以使用EL表达式,并将在流程执行运行时解析。可以设置下列参数: - - -[options="header"] -|=============== -|参数|必填?|描述 -|to|是|邮件的收信人。可以使用逗号分隔的列表定义多个接收人 -|from|否|邮件的发信人地址。如果不设置,会使用<>的地址 -|subject|否|邮件的主题 -|cc|否|邮件的抄送人。可以使用逗号分隔的列表定义多个接收人 -|bcc|否|邮件的密送人。可以使用逗号分隔的列表定义多个接收人 -|charset|否|可以指定邮件的字符集,对许多非英语语言很必要。 -|html|否|邮件的HTML文本 -|text|否|邮件的内容,用于纯文本邮件。对于不支持富文本内容的客户端,可以与__html__一起使用。邮件客户端可以回退为显式纯文本格式。 -|htmlVar|否|存储邮件HTML内容的流程变量名。与__html__参数的最大区别,是这个参数会在邮件任务发送前,使用其内容进行表达式替换。 -|textVar|否|存储邮件纯文本内容的流程变量名。与__text__参数的最大区别,是这个参数会在邮件任务发送前,使用其内容进行表达式替换。 -|ignoreException|否|处理邮件失败时,是忽略还是抛出FlowableException。默认设置为false。 -|exceptionVariableName|否|如果设置__ignoreException = true__,而处理邮件失败时,则使用给定名字的变量保存失败信息 - -|=============== - - -[[bpmnEmailTaskExampleUsage]] - - -===== 示例 usage - -下面的XML代码片段是使用邮件任务的示例。 - -[source,xml,linenums] ----- - - - - - - - - - - Hello ${male ? 'Mr.' : 'Mrs.' } ${recipientName},

- - As of ${now}, your order has been processed and shipped.

- - Kind regards,
- - TheCompany. - - - ]]> -
-
-
-
- ----- - - -[[bpmnHttpTask]] - - -==== Http任务 - -Http任务(Http task)用于发出HTTP请求,增强了Flowable的集成能力。请注意Http任务不是BPMN 2.0规范的“官方”任务(所以也没有专用图标)。因此,在Flowable中,Http任务实现为一种特殊的服务任务。 - -[[bpmnHttpTaskClientConfiguration]] - - -===== 配置Http客户端 - -Flowable使用可配置的Http客户端发出Http请求。如果不进行设置,会使用默认配置。 - -示例配置: - -[source,xml,linenums] ----- - - - - - - - - - - - ----- - -[options="header"] -|=============== -|参数|必填?|描述 -|connectTimeout|否|连接超时时间,以毫秒计。 + -默认值 5000。 -|socketTimeout|否|Socket超时时间,以毫秒计。 + -默认值 5000。 -|connectionRequestTimeout|否|请求连接超时时间。以毫秒计 + -默认值 5000。 -|requestRetryLimit|否|请求重试次数(“0”代表不重试) + -默认值 3。 -|disableCertVerify|否|禁用SSL证书验证。 + -默认值 false。 - -|=============== - -[[bpmnHttpTaskUsage]] - - -===== 定义Http任务 - -Http任务实现为特殊的<>,将服务任务的__type__定义为__'http'__进行设置。 - -[source,xml,linenums] ----- - ----- - -可以使用自定义的实现,覆盖Http任务的默认行为。 -需要扩展org.flowable.http.HttpActivityBehavior,并覆盖perform()方法。 - -需要在任务定义中设置__httpActivityBehaviorClass__字段(默认值为 __org.flowable.http.impl.HttpActivityBehaviorImpl__)。 - -当前使用的默认实现__HttpActivityBehaviorImpl__基于Apache Http Client。尽管Apache Http Client可以使用很多方法自定义,但我们并没有在Http客户端配置中使用全部选项。 - -参考 link:$$http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/client/HttpClientBuilder.html$$[Http Client builder] 创建自定义客户端。 - - ----- - - - - - - - - - ----- - -[[bpmnHttpTaskConfiguration]] - -===== 配置Http任务 - -Http任务通过<>配置。所有参数都可以配置为EL表达式,在运行时进行解析。可以设置下列参数: - -[options="header"] -|=============== -|参数|必填?|描述 -|requestMethod|是|请求方法 + -(GET,POST,PUT,DELETE)。 -|requestUrl|yes|请求URL + -(例如 - http://flowable.org)。 -|requestHeaders|否|行分隔的Http请求头。 + -例如 - + -Content-Type: application/json + -Authorization: Basic aGFRlc3Q= -|requestBody|否|请求体 + -例如 - ${sampleBody} -|requestTimeout|否|请求超时时间。单位为毫秒 + -(例如 - 5000)。 + -默认值为“0”,即没有超时。 + -链接相关的超时设置为<>。 -|disallowRedirects|否|是否禁用Http重定向。 + -默认为false。 + -(例如 - true)。 -|failStatusCodes|否|逗号分隔的Http状态码,将令请求失败并抛出FlowableException。 + -例如:400, 404, 500, 503 + -例如:400, 5XX -|handleStatusCodes|否|逗号分隔的Http状态码,将令任务抛出BpmnError,并可用错误边界事件捕获。 + -BpmnError的错误码为__HTTP__。 + -例如,404状态码会将错误码设置为__HTTP404__。 + -仅当__disallowRedirects__字段设置为true时,3XX状态码才会被抛出。若同一个状态码在__handleStatusCodes__及__failStatusCodes__中都有配置,则__handleStatusCodes__生效。 + -例如:400, 404, 500, 503 + -例如:3XX, 4XX, 5XX + -|ignoreException|否|是否忽略异常。异常将被捕获,并存储在名为__.errorMessage__的变量中。 -|saveRequestVariables|否|是否保存请求变量。 + -默认情况下,只会保存将响应相关的变量。 -|saveResponseParameters|否|是否保存全部的响应变量,包括HTTP状态码,响应头等。 + -默认情况下,只会将响应体保存为变量。 -|resultVariablePrefix|否|执行变量名的前缀。 + -如果不设置前缀,变量名为__.fieldName__。 + -例如,对于id为__task7__的任务,其请求URL将保存为__task7.requestUrl__。 -|saveResponseParametersTransient|否|若为true,则会将响应体变量(如果设置了保存响应头,状态码,也包括在内)设置为瞬时变量。 -|saveResponseVariableAsJson|否|若为true,则响应体会保存为JSON变量,而非String。如果HTTP服务返回JSON,并且想使用点注记方式使用字段(如__myResponse.user.name__),这个配置就很有用。 -|httpActivityBehaviorClass|否|org.flowable.http.HttpActivityBehavior类的自定义扩展的全限定类名。 -|=============== - -除了上面提到的字段,使用__saveResponseParameters__还会在执行成功后设置下列变量。 - -[options="header"] -|=============== -|变量|可选?|描述 -|responseProtocol|是|Http版本。 -|responseReason|是|Http响应原因短语。 -|responseStatusCode|是|Http响应状态码(例如 - 200)。 -|responseHeaders|是|行分隔的Http响应头。 + -例如 - + -Content-Type: application/json + -Content-Length: 777 -|responseBody|是|字符串形式的响应体,若有。 -|errorMessage|是|被忽略的异常信息,若有。 -|=============== - -[[_result_variables]] -===== 结果变量 - -请注意上述执行变量名都会使用__resultVariablePrefix__前缀。 -例如,可以在其他活动中,使用__task7.responseStatusCode__获取响应状态码。 -其中__task7__是服务任务的__id__。可以设置__resultVariablePrefix__覆盖这个行为。 - -[[bpmnHttpTaskExampleUsage]] - - -===== 示例 - -下面的XML片段是使用Http任务的例子。 - -[source,xml,linenums] ----- - - - - - - - - - - - - - - - - task7 - - - ----- - -[[bpmnHttpTaskErrorHandling]] - -===== 错误处理 - -默认情况下,当发生链接、IO或其他未处理的异常时,Http任务抛出FlowableException。 -默认情况下,不会处理任何重定向/客户端/服务端错误状态码。 - -可以设置__failStatusCodes__及/或__handleStatusCodes__字段,配置Http任务处理异常及Http状态的方式。参见<>。 - -由__handleStatusCodes__抛出的BpmnError与其他BPMN异常一样,需要由对应的错误边界事件处理。 -下面是一些Http任务错误处理及重试的例子。 - -====== __400__及5XX失败,异步执行,并按照failedJobRetryTimeCycle重试的Http任务 - -[source,xml,linenums] ----- - - - - - - - - - - - - R3/PT5S - - ----- - -====== 将__400__处理为BmpnError -[source,xml,linenums] ----- - - - - - - - - - - - - - - - - ----- - -====== 忽略异常 -[source,xml,linenums] ----- - - - - - - - - - - - - - ----- - -====== 异常映射 -参见<> - -[[bpmnCamelTask]] - - -==== Camel任务 - -Camel任务(Camel task)可以向Camel发送消息,增强Flowable的集成特性。请注意Camel任务**不是**BPMN 2.0规范的“官方”任务(所以也没有专用图标)。因此,在Flowable中,Camel任务实现为一种特殊的服务任务。还请注意,需要在项目中包含Flowable Camel模块才能使用Camel任务。 - - -[[bpmnCamelTaskUsage]] - - -===== 定义Camel任务 - -Camel任务实现为特殊的<>,将服务任务的__type__定义为__'camel'__进行设置。 - - -[source,xml,linenums] ----- - ----- - -只需要在流程定义的服务任务上定义Camel类型即可。集成逻辑都通过Camel容器委托。默认情况下Flowable引擎在Spring容器中查找camelContext Bean。camelContext Bean定义由Camel容器装载的Camel路由。在下面的例子中,按照指定的Java包装载路由。但也可以自行在Spring配置中直接定义路由。 - -[source,xml,linenums] ----- - - - org.flowable.camel.route - - ----- - -可以在link:$$http://camel.apache.org/$$[Camel网站]找到关于Camel路由的更多文档。下面只通过几个小例子展示基本概念。在第一个例子中,在Flowable工作流中进行最简单的Camel调用。叫做SimpleCamelCall。 - -如果想要定义多个Camel上下文Bean,或想使用不同的Bean名字,可以在Camel任务定义中像这样覆盖: - -[source,xml,linenums] ----- - - - - - ----- - - -[[bpmnCamelTaskSimpleCamelCall]] - - -===== 简单Camel调用示例 - -这个例子相关的所有文件,都可以在flowable-camel模块的org.flowable.camel.examples.simpleCamelCall包中找到。目标是简单地启动一个Camel路由。首先需要一个配置了上面提到的路由的Spring上下文。下面的代码实现这个目的: - -[source,xml,linenums] ----- - - - org.flowable.camel.examples.simpleCamelCall - - ----- - -[source,java,linenums] ----- -public class SimpleCamelCallRoute extends RouteBuilder { - - @Override - public void configure() throws Exception { - from("flowable:SimpleCamelCallProcess:simpleCall").to("log:org.flowable.camel.examples.SimpleCamelCall"); - } -} ----- - -路由只是记录消息体,不做更多事情。请注意from端点(endpoint)的格式,包含冒号分隔的三个部分: - - -[options="header"] -|=============== -|端点URL部分|描述 -|flowable|指向引擎端点 -|SimpleCamelCallProcess|流程名 -|simpleCall|流程中Camel服务的名字 - -|=============== - -现在已经配置好路由,可以访问Camel。下面需要像这样定义工作流: - -[source,xml,linenums] ----- - - - - - - - - - ----- - - -[[bpmnCamelTaskPingPong]] - - -===== 连通性测试示例 - -示例已经可以工作,但实际上Camel与Flowable之间并没有通信,因此没有太多价值。在这个例子里,将试着从Camel接收与发送消息。我们将发送一个字符串,Camel在其上附加一些文字并返回作为结果。发送部分比较普通,即以变量的格式将信息发送给Camel服务。这是我们的调用代码: - -[source,java,linenums] ----- -@Deployment -public void testPingPong() { - Map variables = new HashMap(); - - variables.put("input", "Hello"); - Map outputMap = new HashMap(); - variables.put("outputMap", outputMap); - - runtimeService.startProcessInstanceByKey("PingPongProcess", variables); - assertEquals(1, outputMap.size()); - assertNotNull(outputMap.get("outputValue")); - assertEquals("Hello World", outputMap.get("outputValue")); -} ----- - - -“input”变量是实际上是Camel路由的输入,而outputMap用于捕获Camel传回的结果。流程像是这样: - -[source,xml,linenums] ----- - - - - - - - - - - ----- - -请注意SaveOutput服务任务会从上下文中取出“Output”变量,并存储至上面提到的OutputMap。现在需要了解变量如何发送至Camel,以及如何返回。这就需要了解Camel行为(Behavior)的概念。变量与Camel通信的方式可以通过CamelBehavior配置。在这个例子里使用默认配置,其它配置在后面会进行简短介绍。可以使用类似的代码配置期望的Camel行为: - - -[source,xml,linenums] ----- - - - - - ----- - -如果不指定行为,则会设置为org.flowable.camel.impl.CamelBehaviorDefaultImpl。这个行为会将变量复制到相同名字的Camel参数。无论选择什么行为,对于返回值:如果Camel消息体是一个map,则其中的每个元素都将复制为变量;否则整个对象将复制为名为"camelBody"的特定变量。以第二个例子作为Camel路由的总结: - -[source,java,linenums] ----- -@Override -public void configure() throws Exception { - from("flowable:PingPongProcess:ping").transform().simple("${property.input} World"); -} ----- - -在这个路由中,字符串"world"会在结尾连接上名为“input”的参数,并将结果作为消息体返回。可以通过Java服务任务访问"camelBody"变量。也可以访问“outputMap”获取。除了这个例子中使用的默认行为之外,我们还可以看看其他的方式。在每个Camel路由开始时,流程实例ID会复制为名为"PROCESS_ID_PROPERTY"的Camel参数。之后会用于将流程实例与Camel路由相关联。也可以在Camel路由中直接使用。 - -Flowable提供了三种不同的行为。可以通过修改路由URL中特定的部分覆写行为。这里有个在URL中覆写已有行为的例子: - -[source,java,linenums] ----- -from("flowable:asyncCamelProcess:serviceTaskAsync2?copyVariablesToProperties=true"). - ----- - -下表展示了三种可用的Camel行为: - -[options="header"] -|=============== -|行为|URL中|描述 -|CamelBehaviorDefaultImpl|copyVariablesToProperties|将Flowable变量复制为Camel参数。 -|CamelBehaviorCamelBodyImpl|copyCamelBodyToBody|只将名为"camelBody"的Flowable变量复制为Camel消息体。 -|CamelBehaviorBodyAsMapImpl|copyVariablesToBodyAsMap|将一个map中的所有Flowable变量复制为Camel消息体。 - -|=============== - -上表展示了Flowable变量如何传递给Camel。下表展示Camel变量如何返回至Flowable。需要在路由URL中进行配置。 - - -[options="header"] -|=============== -|URL|描述 -|Default|如果Camel消息体是一个map,则将其中每一对象复制为Flowable变量;否则将整个Camel消息体复制为"camelBody" Flowable变量。 -|copyVariablesFromProperties|将Camel参数以同名复制为Flowable变量。 -|copyCamelBodyToBodyAsString|与default相同,但如果Camel消息体不是map,则首先将其转换为字符串,然后再复制为"camelBody"。 -|copyVariablesFromHeader|额外地,将Camel头复制为Flowable的同名变量。 - -|=============== - -[[_returning_back_the_variables]] -===== 返回变量 - -上面提到的变量传递,不论是从Camel到Flowable还是反向,都只用于变量传递的起始侧。 -要特别注意,由于Flowable的行为是非阻塞的,Flowable不会自动向Camel返回变量。 -为此提供了特殊的语法。可以在Camel路由URL中,以++var.return.someVariableName++的格式,指定一个或多个参数。与这些参数同名(但没有++var.return++部分)的变量会作为输出变量。因此将会以相同的名字复制回Camel参数。 + -例如在如下路由中: - - ----- -from("direct:start").to("flowable:process?var.return.exampleVar").to("mock:result"); ----- - -名为++exampleVar++的Flowable变量会作为输出变量。因此会以同名复制回Camel参数。 - - -[[bpmnCamelTaskAsyncPingPong]] - - -===== 异步连通性测试示例 - -上面的例子全都是同步的。流程实例等待,直到Camel路由结束并返回。有时,需要Flowable流程实例继续运行。这时可以使用Camel服务任务的异步功能。可以将Camel服务任务的__async__参数设置为true,启用这个功能。 - - -[source,xml,linenums] ----- - ----- - - -设置这个参数后,Camel路由会由Flowable作业执行器异步启动。如果在Camel路由中定义了队列,Flowable流程实例会继续执行流程定义中Camel服务任务之后的活动。Camel路由会与流程执行完全异步地执行。如果需要在流程定义的某处等待Camel服务任务的响应,可以使用接收任务(receive task)。 - -[source,xml,linenums] ----- - ----- - -流程实例会等待,直到接收到来自Camel的信号。可以在Camel中向特定的Flowable端点发送消息,来为流程实例发送信号。 - - -[source,java,linenums] ----- - from("flowable:asyncPingProcess:serviceAsyncPing").to("flowable:asyncPingProcess:receiveAsyncPing"); ----- - - -* “flowable”字符串常量 -* 流程名 -* 接收任务名 - - -[[bpmnCamelInstantiateWorkflowFromCamelRoute]] - - -===== 使用Camel路由实例化工作流 - -上面的例子都是先启动Flowable流程实例,然后在流程实例中启动Camel路由。也可以反过来,在已经启动的Camel路由中启动或调用流程实例。类似于为接收任务发送消息。例如,一个简单的路由: - -[source,java,linenums] ----- -from("direct:start").to("flowable:camelProcess"); ----- - -可以看到,URL包含两部分:第一部分是“flowable”字符串常量,第二部分是流程定义的名字。当然,需要提前在Flowable引擎中部署这个流程定义。 - -也可以在Camel头中,将流程实例起动人设置为某个已认证用户ID。为此,首先需要在流程定义中指定启动人变量: - -[source,xml,linenums] ----- - ----- - -然后使用Camel头__CamelProcessInitiatorHeader__指定用户ID。Camel路由定义如下: - -[source,java,linenums] ----- -from("direct:startWithInitiatorHeader") - .setHeader("CamelProcessInitiatorHeader", constant("kermit")) - .to("flowable:InitiatorCamelCallProcess?processInitiatorHeaderName=CamelProcessInitiatorHeader"); ----- - - -[[bpmnManualTask]] - - -==== 手动任务 - -[[bpmnManualTaskDescription]] - - -===== 描述 - -__手动任务(manual task)__定义在BPM引擎之外的任务。它用于建模引擎不需要了解,也不需要提供系统或用户界面的工作。对于引擎来说,手动任务将按**直接穿过活动**处理,在流程执行到达手动任务时,自动继续执行流程。 - - -[[bpmnManualTaskGraphicalNotation]] - - -===== 图示 - -手动任务用左上角有一个小“手”图标的标准BPMN 2.0任务(圆角矩形)表示。 - -image::images/bpmn.manual.task.png[align="center"] - - -[[bpmnManualTaskXml]] - - -===== XML表示 - -[source,xml,linenums] ----- - ----- - - -[[bpmnReceiveTask]] - - -==== Java接收任务 - -[[bpmnReceiveTaskDescription]] - - -===== 描述 - -接收任务(receive task),是等待特定消息到达的简单任务。目前,我们只为这个任务实现了Java语义。当流程执行到达接收任务时,流程状态将提交至持久化存储。这意味着流程将保持等待状态,直到引擎接收到特定的消息,触发流程穿过接收任务继续执行。 - -[[_graphical_notation_2]] -===== 图示 - -接收任务用左上角有一个消息图标的标准BPMN 2.0任务(圆角矩形)表示。消息图标是白色的(对应的黑色消息图标代表发送的含义)。 - -image::images/bpmn.receive.task.png[align="center"] - -[[_xml_representation_2]] -===== XML表示 - -[source,xml,linenums] ----- - ----- - -要使流程实例从接收任务的等待状态中继续执行,需要使用到达接收任务的执行id,调用__runtimeService.signal(executionId)__。下面的代码片段展示了如何操作: - -[source,java,linenums] ----- -ProcessInstance pi = runtimeService.startProcessInstanceByKey("receiveTask"); -Execution execution = runtimeService.createExecutionQuery() - .processInstanceId(pi.getId()) - .activityId("waitState") - .singleResult(); -assertNotNull(execution); - -runtimeService.trigger(execution.getId()); ----- - - -[[bpmnShellTask]] - - -==== Shell任务 - -[[bpmnShellTaskDescription]] - - -===== 描述 - -Shell任务(Shell task)可以运行Shell脚本与命令。请注意Shell任务**不是**BPMN 2.0规范的“官方”任务(因此也没有专用图标)。 - - -[[bpmnShellTaskUsage]] - - -===== 定义Shell任务 - -Shell任务实现为特殊的<>,将服务任务的__type__定义为__'shell'__进行设置。 - -[source,xml,linenums] ----- - ----- - -Shell任务通过<>配置。这些参数的值可以使用EL表达式,将在流程执行运行时解析。可以设置下列参数: - - -[options="header"] -|=============== -|参数|必填?|类型|描述|默认值 -|command|是|String|要执行的Shell命令。| -|arg1-5|否|String|参数1至参数5| -|wait|否|true/false|是否等待Shell进程终止。|true -|redirectError|否|true/false|是否将标准错误(standard error)并入标准输出(standard output)。|false -|cleanEnv|否|true/false|是否避免Shell进程继承当前环境。|false -|outputVariable|否|String|保存输出的变量名|不会记录输出。 -|errorCodeVariable|否|String|保存结果错误码的变量名|不会记录错误码。 -|directory|否|String|Shell进程的默认目录|当前目录 - -|=============== - - -[[bpmnShellTaskExampleUsage]] - - -===== 示例 - -下面的XML代码片段是使用Shell任务的例子。将会运行"cmd /c echo EchoTest" Shell脚本,等待其结束,并将其结果存入__resultVar__。 - -[source,xml,linenums] ----- - - - - - - - - - - - ----- - - -[[executionListeners]] - - -==== 执行监听器 - -执行监听器(execution listener)可以在流程执行中发生特定的事件时,执行外部Java代码或计算表达式。可以被捕获的事件有: - -* 流程实例的启动和结束。 -* 流程执行转移。 -* 活动的启动和结束。 -* 网关的启动和结束。 -* 中间事件的启动和结束。 -* 启动事件的结束,和结束事件的启动。 - -下面的流程定义包含了三个执行监听器: - -[source,xml,linenums] ----- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ----- - -第一个执行监听器将在流程启动时收到通知。这个监听器是一个外部Java类(++ExampleExecutionListenerOne++),并且需要实现++org.flowable.engine.delegate.ExecutionListener++接口。当该事件发生时(这里是++start++事件),会调用++notify(ExecutionListenerExecution execution)++方法。 - -[source,java,linenums] ----- -public class ExampleExecutionListenerOne implements ExecutionListener { - - public void notify(ExecutionListenerExecution execution) throws Exception { - execution.setVariable("variableSetInExecutionListener", "firstValue"); - execution.setVariable("eventReceived", execution.getEventName()); - } -} ----- - -也可以使用实现了++org.flowable.engine.delegate.JavaDelegate++接口的委托类。这些委托类也可以用于其他的结构,如服务任务的委托。 - -第二个执行监听器在流程执行转移时被调用。请注意++listener++元素并未定义++event++,因为在转移上只会触发++take++事件。**当监听器定义在转移上时,++event++属性的值将被忽略。** - -最后一个执行监听器在++secondTask++活动结束时被调用。监听器声明中没有使用++class++,而是定义了++expression++。这个表达式将在事件触发时计算/调用。 - -[source,xml,linenums] ----- - ----- - -与其他表达式一样,可以使用与解析__execution__变量。execution对象提供了露事件名参数,可以使用++execution.eventName++向你的方法传递事件名。 - -<>,执行监听器也支持使用++delegateExpression++。 - -[source,xml,linenums] ----- - ----- - -较早之前,我们也引入了新的执行监听器类型,org.flowable.engine.impl.bpmn.listener.ScriptExecutionListener。这个脚本执行监听器可以为执行监听器事件执行一段脚本代码。 - -[source,xml,linenums] ----- - - - - - def bar = "BAR"; // 局部变量 - foo = "FOO"; // 将变量放入执行上下文 - execution.setVariable("var1", "test"); // 测试访问执行实例 - bar // 隐式返回值 - - - - - - ----- - - -[[executionListenerFieldInjection]] - - -===== 执行监听器上的字段注入 - -使用通过++class++属性配置的执行监听器时,可以使用字段注入。与<>使用完全相同的机制,可以在那里看到字段注入的各种用法。 - -下面的代码片段展示了一个简单的示例流程,带有一个使用了字段注入的执行监听器。 - -[source,xml,linenums] ----- - - - - - - - - - - - - - - - - - - ----- - -[source,java,linenums] ----- -public class ExampleFieldInjectedExecutionListener implements ExecutionListener { - - private Expression fixedValue; - - private Expression dynamicValue; - - public void notify(ExecutionListenerExecution execution) throws Exception { - execution.setVariable("var", fixedValue.getValue(execution).toString() + - dynamicValue.getValue(execution).toString()); - } -} ----- - -++ExampleFieldInjectedExecutionListener++类将连接两个字段(一个是固定值-fixedValue,另一个是动态值-dynamicValue),并将其存储在'++var++'流程变量中。 - -[source,java,linenums] ----- -@Deployment(resources = { - "org/flowable/examples/bpmn/executionListener/ExecutionListenersFieldInjectionProcess.bpmn20.xml"}) -public void testExecutionListenerFieldInjection() { - Map variables = new HashMap(); - variables.put("myVar", "listening!"); - - ProcessInstance processInstance = runtimeService.startProcessInstanceByKey( - "executionListenersProcess", variables); - - Object varSetByListener = runtimeService.getVariable(processInstance.getId(), "var"); - assertNotNull(varSetByListener); - assertTrue(varSetByListener instanceof String); - - // 结果为固定注入字段及注入表达式的连接 - assertEquals("Yes, I am listening!", varSetByListener); -} ----- - -请注意,与服务任务使用相同的线程安全规则。请阅读<>了解更多信息。 - -[[taskListeners]] - - -==== 任务监听器 - -__任务监听器(task listener)__用于在特定的任务相关事件发生时,执行自定义的Java逻辑或表达式。 - -任务监听器只能在流程定义中作为<>的子元素。请注意,任务监听器是一个Flowable自定义结构,因此也需要作为__BPMN 2.0 extensionElements__,放在__flowable__命名空间下。 - - -[source,xml,linenums] ----- - - - - - ----- - -__任务监听器__包含下列属性: - -* **event(事件)**(必填):触发任务监听器的任务事件类型。可用的事件有: -** **create(创建)**:当任务已经创建,并且**所有任务参数都已经设置**时触发。 -** **assignment(指派)**:当任务已经指派给某人时触发。请注意:当流程执行到达用户任务时,在触发__create__事件**之前**,会首先触发__assignment__事件。这顺序看起来不太自然,但是有实际原因的:当收到__create__事件时,我们通常希望能看到任务的所有参数,包括办理人。 -** **complete(完成)**:当任务已经完成,从运行时数据中删除前触发。 -** **delete(删除)**:在任务即将被删除前触发。请注意任务由completeTask正常完成时也会触发。 -* **class**:需要调用的委托类。这个类必须实现++org.flowable.task.service.delegate.TaskListener++接口。 - -[source,java,linenums] ----- -public class MyTaskCreateListener implements TaskListener { - - public void notify(DelegateTask delegateTask) { - // 这里是要实现的业务逻辑 - } -} ----- - -也可以使用<>,为委托类传递流程变量或执行。请注意委托类的实例在流程部署时创建(与Flowable中其它的委托类一样),这意味着该实例会在所有流程实例执行中共享。 - -* **expression**:(不能与__class__属性一起使用):指定在事件发生时要执行的表达式。可以为被调用的对象传递++DelegateTask++对象与事件名(使用++task.eventName++)作为参数。 - -[source,java,linenums] ----- - ----- - -* **delegateExpression**:指定一个能够解析为++TaskListener++接口实现类的对象的表达式。<>。 - - -[source,xml,linenums] ----- - ----- - -* 较早之前,我们也引入了新的执行监听器类型,org.flowable.engine.impl.bpmn.listener.ScriptTaskListener。这个脚本任务监听器可以为一个任务监听器事件执行一段脚本代码。 - -[source,xml,linenums] ----- - - - - def bar = "BAR"; // 局部变量 - foo = "FOO"; // 将变量放入执行上下文 - task.setOwner("kermit"); // 测试访问任务实例 - bar // 隐式返回值 - - - - - ----- - - -[[bpmnMultiInstance]] - - -==== 多实例(for each) - -[[bpmnMultiInstanceDescription]] - - -===== 描述 - -__多实例活动(multi-instance activity)__是在业务流程中,为特定步骤定义重复的方式。在编程概念中,多实例类似**for each**结构:可以为给定集合中的每一条目,**顺序或并行地**,执行特定步骤,甚至是整个子流程。 - -__多实例__是一个普通活动,加上定义(被称作“__多实例__特性的”)额外参数,会使得活动在运行时被多次执行。下列活动可以成为__多实例活动:__ - -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> -* <> - -<>与<>**不能**设置为多实例。 - -按照BPMN2.0规范的要求,用于为每个实例创建执行的父执行,会提供下列变量: - -* **nrOfInstances**:实例总数。 -* **nrOfActiveInstances**:当前活动的(即未完成的),实例数量。对于顺序多实例,这个值总为1。 -* **nrOfCompletedInstances**:已完成的实例数量。 - -可以调用++execution.getVariable(x)++方法获取这些值。 - -另外,每个被创建的执行,都有局部变量(对其他执行不可见,也不存储在流程实例级别): - -* **loopCounter**:给定实例在__for-each循环中的index__。可以通过Flowable的**elementIndexVariable**属性为loopCounter变量重命名。 - - -[[bpmnMultiInstanceGraphicalNotation]] - - -===== 图示 - -如果一个活动是多实例,将通过在该活动底部的三条短线表示。三条__竖__线代表实例会并行执行,而三条__横__线代表顺序执行。 - -image::images/bpmn.multi.instance.png[align="center"] - - -[[bpmnMultiInstanceXml]] - - -===== XML表示 - -要将活动变成多实例,该活动的XML元素必须有++multiInstanceLoopCharacteristics++子元素 - -[source,xml,linenums] ----- - - ... - ----- - -**isSequential**属性代表了活动的实例为顺序还是并行执行。 - -实例的数量**在进入活动时,计算一次**。有几种不同方法可以配置数量。一个方法是通过**loopCardinality**子元素,直接指定数字。 - -[source,xml,linenums] ----- - - 5 - ----- - -也可以使用解析为正整数的表达式: - -[source,xml,linenums] ----- - - ${nrOfOrders-nrOfCancellations} - ----- - -另一个定义实例数量的方法,是使用++loopDataInputRef++子元素,指定一个集合型流程变量的名字。对集合中的每一项,都会创建一个实例。可以使用++inputDataItem++子元素,将该项设置给该实例的局部变量。在下面的XML示例中展示: - - -[source,xml,linenums] ----- - - - assigneeList - - - ----- - -假设变量++assigneeList++包含++[kermit, gonzo, fozzie]++。上面的代码会创建三个并行的用户任务。每一个执行都有一个名为++assignee++的(局部)流程变量,含有集合中的一项,并在这个例子中被用于指派用户任务。 - -++loopDataInputRef++与++inputDataItem++的缺点是名字很难记,并且由于BPMN 2.0概要的限制,不能使用表达式。Flowable通过在++multiInstanceCharacteristics++上提供**collection**与**elementVariable**属性解决了这些问题: - -[source,xml,linenums] ----- - - - - ----- - -请注意++collection++属性会作为表达式进行解析。如果表达式解析为字符串而不是一个集合,不论是因为本身配置的就是静态字符串值,还是表达式计算结果为字符串,这个字符串都会被当做变量名,在流程变量中用于获取实际的集合。 - -例如,下面的代码片段会要求集合存储在++assigneeList++流程变量中: - -[source,xml,linenums] ----- - - - - ----- - -假如++myService.getCollectionVariableName()++返回字符串值,引擎就会用这个值作为变量名,获取流程变量保存的集合。 - -[source,xml,linenums] ----- - - - - ----- - -多实例活动在所有实例都完成时结束。然而,也可以指定一个表达式,在每个实例结束时进行计算。当表达式计算为true时,将销毁所有剩余的实例,并结束多实例活动,继续执行流程。这个表达式必须通过**completionCondition**子元素定义。 - -[source,xml,linenums] ----- - - - ${nrOfCompletedInstances/nrOfInstances >= 0.6 } - - ----- - -在这个例子里,会为++assigneeList++集合中的每个元素创建并行实例。当60%的任务完成时,其他的任务将被删除,流程继续运行。 - - -[[bpmnMultiInstanceBoundaryEvent]] - - -===== 边界事件与多实例 - -多实例是普通活动,因此可以在其边界定义<>。如果是中断边界事件,当其捕获事件时,会销毁活动中的**所有实例**。以下面的多实例子流程为例: - -image::images/bpmn.multi.instance.boundary.event.png[align="center"] - -当定时器触发时,子流程的所有实例都会被销毁,无论有多少实例,或者实例的内部活动是否完成。 - - -[[bpmnCompensationHandlers]] - -===== 多实例与执行监听器 - -执行监听器与多实例一起使用时需要特别注意。以下面的BPMN 2.0 XML代码片段为例。这段XML定义在与__multiInstanceLoopCharacteristics__ XML元素相同的级别: - -[source,xml,linenums] ----- - - - - ----- - -对于普通的BPMN活动,会在活动开始与结束时调用一次监听器。 - -但是当该活动为多实例时,行为有区别: - -* 当进入多实例活动时,在任何__内部__活动执行前,抛出一个启动事件。__loopCounter__变量还未设置(为null)。 -* 进入每个实际执行的活动时,抛出一个启动事件。__loopCounter__变量已经设置。 - -结束事件类似: - -* 离开每个实际执行的活动后,抛出一个结束事件。__loopCounter__变量已经设置。 -* 多实例活动整体完成后,抛出一个结束事件。__loopCounter__变量未设置。 - -例如: - -[source,xml,linenums] ----- - - - - - - - assignees - - - - - - ----- - -在这个例子中,假设__assignees__有三项。在运行时会发生如下事情: - -* 多实例整体抛出一个启动事件。调用一次__start__执行监听器,__loopCounter__与__assignee__变量均未设置(即为null)。 -* 每一个活动实例抛出一个启动事件。调用三次__start__执行监听器,__loopCounter__与__assignee__变量均已设置(也就是说不为null)。 -* 因此启动执行监听器总共被调用四次。 - -请注意,即使__multiInstanceLoopCharacteristics__不是定义在子流程上,也是一样。例如,如果上面的例子中只是一个简单的用户任务,抛出事件的行为也是一样。 - -[[_compensation_handlers]] -==== 补偿处理器 - -[[bpmnCompensationHandlerDescription]] - - -===== 描述 - -如果要使用一个活动补偿另一个活动的影响,可以将其声明为__补偿处理器(compensation handler)__。补偿处理器不在正常流程中执行,而只在流程抛出补偿事件时才会执行。 - -补偿处理器不得有入口或出口顺序流。 - -补偿处理器必须通过单向的连接,关联一个补偿边界事件。 - -[[bpmnCompensationHandlerGraphicalNotation]] - - -===== 图示 - -如果一个活动是补偿处理器,则会在其下部中间显示补偿事件图标。下面摘录的流程图展示了一个带有补偿边界事件的服务任务,并关联至一个补偿处理器。请注意补偿处理器图标显示在"cancel hotel reservation(取消酒店预订)"服务任务的下部中间。 - - -image::images/bpmn.boundary.compensation.event.png[align="center"] - - -[[bpmnCompensationHandlerXml]] - - -===== XML表示 - -要将一个活动声明为补偿处理器,需要将++isForCompensation++属性设置为true: - -[source,xml,linenums] ----- - - ----- - -[[bpmnSubprocessAndCallActivity]] - - -=== 子流程与调用活动 - -[[bpmnSubProcess]] - - -==== 子流程 - -[[bpmnSubProcessDescription]] - - -===== 描述 - -__子流程(sub-process)__是包含其他的活动、网关、事件等的活动。其本身构成一个流程,并作为更大流程的一部分。__子流程__完全在父流程中定义(这就是为什么经常被称作__嵌入式__子流程)。 - -子流程有两个主要的使用场景: - -* 子流程可以**分层建模**。很多建模工具都可以__折叠__子流程,隐藏子流程的所有细节,而只显示业务流程的高层端到端总览。 -* 子流程会创建新的**事件范围**。在子流程执行中抛出的事件可以通过子流程边界上的<>捕获,为该事件创建了限制在子流程内的范围。 - -使用子流程也要注意以下几点: - -* 子流程只能有**一个空启动事件**,而不允许有其他类型的启动事件。请注意BPMN 2.0规范允许省略子流程的启动与结束事件,但目前Flowable的实现尚不支持省略。 -* **顺序流不能跨越子流程边界。** - - - -[[bpmnSubProcessGraphicalNotation]] - - -===== 图示 - -子流程表示为标准活动(圆角矩形)。若__折叠__了子流程,则只显示其名字与一个加号,以展示流程的高层概览: - -image::images/bpmn.collapsed.subprocess.png[align="center"] - -若__展开__了子流程,则在子流程内显示子流程的所有步骤: - -image::images/bpmn.expanded.subprocess.png[align="center"] - -使用子流程的一个主要原因是为事件定义范围。下面的流程模型展示了这种用法:__investigate software(调查硬件)/investigate hardware(调查软件)__两个任务需要并行执行,且需要在给定时限内,在__Level 2 support(二级支持)__响应前完成。在这里,定时器的范围(即需要按时完成的活动)通过子流程进行限制。 - -image::images/bpmn.subprocess.with.boundary.timer.png[align="center"] - - -[[bpmnSubProcessXML]] - - -===== XML表示 - -子流程通过__subprocess__元素定义。子流程中的所有活动、网关、事件等,都需要定义在这个元素内。 - -[source,xml,linenums] ----- - - - - - ... 其他子流程元素 ... - - - - ----- - - -[[bpmnEventSubprocess]] - - -==== 事件子流程 - -[[bpmnEventSubprocessDescription]] - - -===== 描述 - -事件子流程(event sub-process)是BPMN 2.0新定义的。事件子流程是通过事件触发的子流程。可以在流程级别,或者任何子流程级别,添加事件子流程。用于触发事件子流程的事件,使用启动事件进行配置。因此可知,不能在事件子流程中使用空启动事件。事件子流程可以通过消息事件、错误事件、信号时间、定时器事件或补偿事件等触发。在事件子流程的宿主范围(流程实例或子流程)创建时,创建对启动事件的订阅。当该范围销毁时,删除订阅。 - -事件子流程可以是中断或不中断的。中断的子流程将取消当前范围内的任何执行。非中断的事件子流程将创建新的并行执行。宿主范围内的每个活动,只能触发一个中断事件子流程,而非中断事件子流程可以多次触发。子流程是否是中断的,通过触发事件子流程的启动事件配置。 - -事件子流程不能有任何入口或出口顺序流。事件子流程是由事件触发的,因此入口顺序流不合逻辑。当事件子流程结束时,要么同时结束当前范围(中断事件子流程的情况),要么是非中断子流程创建的并行执行结束。 - -**目前的限制:** - -* Flowable支持错误、定时器、信号与消息启动事件触发事件子流程。 - - -[[bpmnEventSubprocessGraphicalNotation]] - - -===== 图示 - -事件子流程表示为点线边框的<>。 - -image::images/bpmn.subprocess.eventSubprocess.png[align="center"] - - -[[bpmnEventSubprocessXMLRepresentation]] - - -===== XML表示 - -事件子流程的XML表示形式与嵌入式子流程相同。但需要将++triggeredByEvent++属性设置为++true++: - -[source,xml,linenums] ----- - - ... - ----- - - -[[bpmnEventSubprocessExample]] - - -===== 示例 - -下面是使用错误启动事件触发事件子流程的例子。该事件子流程处于“流程级别”,即流程实例的范围: - -image::images/bpmn.subprocess.eventSubprocess.example.1.png[align="center"] - -事件子流程在XML中是这样的: - -[source,xml,linenums] ----- - - - - - - - ----- - -前面已经指出,事件子流程也可以添加到嵌入式子流程内。若添加到嵌入式子流程内,可以代替边界事件的功能。例如在下面两个流程图中,嵌入式子流程都抛出错误事件。错误事件都被捕获,并由用户任务处理。 - -image::images/bpmn.subprocess.eventSubprocess.example.2a.png[align="center"] - -对比: - -image::images/bpmn.subprocess.eventSubprocess.example.2b.png[align="center"] - -两种情况下都执行相同的任务。然而,两种模型有如下不同: - -* 嵌入式(事件)子流程使用其宿主范围的执行来执行。这意味着嵌入式(事件)子流程可以访问其范围的局部变量。当使用边界事件时,执行嵌入式子流程的执行,会被边界事件的出口顺序流删除。意味着嵌入式子流程创建的变量将不再可用。 -* 使用事件子流程时,事件完全由其所在的子流程处理。当使用边界事件时,事件由其父流程处理。 - -这两点可以帮助你判断哪种方式更适合解决特定的流程建模或实现问题,以选择使用边界事件还是嵌入式(事件)子流程。 - -[[bpmnTransactionSubprocess]] - - -==== 事务子流程 - -[[_description_2]] - -===== 描述 - -事务子流程(transaction sub-process)是一种嵌入式子流程,用于将多个活动组织在一个事务里。事务是工作的逻辑单元,可以组织一组独立活动,使得它们可以一起成功或失败。 - -**事务的可能结果:**事务有三种不同的结果: - -* 若未被取消,或被意外终止,则事务__成功(successful)__。若事务子流程成功,将使用出口顺序流离开。若流程后面抛出了补偿事件,成功的事务可以被补偿。__请注意:__与“普通”嵌入式子流程一样,可以使用补偿抛出中间事件,在事务成功完成后补偿。 -* 若执行到达取消结束事件时,事务被__取消(canceled)__。在这种情况下,所有执行都将被终止并移除。只会保留一个执行,设置为取消边界事件,并将触发补偿。在补偿完成后,事务子流程通过取消边界事件的出口顺序流离开。 -* 若由于抛出了错误结束事件,且未被事务子流程所在的范围捕获,则事务会被__意外(hazard)__终止。错误被事件子流程的边界捕获也一样。在这种情况下,不会进行补偿。 - -下面的流程图展示这三种不同的结果: - -image::images/bpmn.transaction.subprocess.example.1.png[align="center"] - - -**与ACID事务的关系:**要注意不要将BPMN事务子流程与技术(ACID)事务混淆。BPMN事务子流程不是划分技术事务范围的方法。要理解Acitivit中的事务管理,请阅读<>章节。BPMN事务与ACID事务有如下区别: - -* ACID事务生存期一般比较短,而BPMN事务可以持续几小时,几天甚至几个月才完成。考虑一个场景:事务包括的活动中有一个用户任务。通常人的响应时间要比程序长。或者,在另一个场景下,BPMN事务可能等待某些业务事件发生,像是特定订单的填写完成。这些操作通常要比更新数据库字段、使用事务队列存储消息等,花长得多的时间完成。 -* 不可能将业务活动的持续时间限定为ACID事务的范围,因此一个BPMN事务通常会生成多个ACID事务。 -* 一个BPMN事务可以生成多个ACID事务,也就不能使用ACID特性。例如,考虑上面的流程例子。假设"book hotel(预订酒店)"与"charge credit card(信用卡付款)"操作在分开的ACID事务中处理。再假设"book hotel(预订酒店)"活动已经成功。这时,因为已经进行了预订酒店操作,而还没有进行信用卡扣款,就处在中间不一致状态(intermediary inconsistent state)。在ACID事务中,会顺序进行不同的操作,因此也处在中间不一致状态。在这里不一样的是,不一致状态在事务范围外可见。例如,如果通过外部预订服务进行预定,则使用该预订服务的其他部分将能看到酒店已被预订。这意味着,当使用业务事务时,完全不会使用隔离参数(的确,当使用ACID事务时,我们通常也会降低隔离级别,以保证高并发级别。但ACID事务可以细粒度地进行控制,而中间不一致状态也只会存在于一小段时间内)。 -* BPMN业务事务不使用传统方式回滚。这是因为它生成多个ACID事务,在BPMN事务取消时,部分ACID事务可能已经提交。这样它们没法回滚。 - -因为BPMN事务天生需要长时间运行,因此就需要使用不同的方式缺乏隔离与回滚机制造成的问题。在实际使用中,通常只能通过领域特定(domain specific)的方式解决这些问题: - -* 通过补偿实现回滚。如果在事务范围内抛出了取消事件,就补偿所有成功执行并带有补偿处理器的活动所造成的影响。 -* 缺乏隔离通常使用特定领域的解决方案来处理。例如,在上面的例子里,在我们确定第一个客户可以付款前,一个酒店房间可能被第二个客户预定。这可能不满足业务预期,因此预订服务可能会选择允许一定量的超量预定。 -* 另外,由于事务可以由于意外而终止,预订服务需要处理这种情况,比如酒店房间已经预定,但从未付款(因为事务可能已经终止)。在这种情况下,预定服务可能选择这种策略:一个酒店房间有最大预留时间,若到时还未付款,则取消预订。 - -总结一下:尽管ACID事务提供了对回滚、隔离级别,与启发式结果(heuristic outcomes)等问题的通用解决方案,但仍然需要在实现业务事务时,为这些问题寻找特定领域的解决方案。 - -**目前的限制:** - -* BPMN规范要求,流程引擎响应底层事务协议提交的事务。如果在底层协议中发生了取消事件,则取消事务。作为嵌入式的引擎,Flowable当前不支持这点。查看下面介绍一致性的段落,了解其后果。 - -**基于ACID事务与乐观锁(optimistic concurrency)的一致性:**BPMN事务在如下情况保证一致性:所有活动都成功完成;或若部分活动不能执行,则所有已完成活动都被补偿。两种方法都可以达到最终一致性状态。然而需要了解的是:Flowable中BPMN事务的一致性模型,以流程执行的一致性模型为基础。Flowable以事务的方式执行流程,并通过乐观锁标记处理并发。在Flowable中,BPMN的错误、取消与补偿事件,都建立在相同的ACID事务与乐观锁之上。例如,只有在实际到达时,取消结束事件才能触发补偿。如果服务任务抛出了非受检异常,导致并未实际到达取消结束事件;或者,由于底层ACID事务中的其他操作,将事务设置为rollback-only(回滚)状态,导致补偿处理器的操作不能提交;或者,当两个并行执行到达一个取消结束事件时,补偿会被两次触发,并由于乐观锁异常而失败。这些情况下都不能真正完成补偿。想说明的是,当在Flowable中实现BPMN事务时,与实施“普通”流程与子流程,需要遵守相同的规则。因此实现流程时需要有效地保证一致性,需要将乐观锁、事务执行模型纳入考虑范围。 - -[[bpmnTransactionSubprocessGraphicalNotation]] - - -===== 图示 - -事务子流程表示为带有两层边框的<>。 - -image::images/bpmn.transaction.subprocess.png[align="center"] - - -[[bpmnTransactionSubprocessXMLRepresentation]] - - -===== XML表示 - -事务子流程在XML中通过++transaction++标签表示: - -[source,xml,linenums] ----- - - ... - ----- - - -[[bpmnTransactionSubprocessExample]] - - -===== 示例 - -下面是一个事务子流程的例子: - -image::images/bpmn.transaction.subprocess.example.2.png[align="center"] - - -[[bpmnCallActivity]] - - -==== 调用活动(子流程) - -[[bpmnCallActivityDescription]] - - -===== 描述 - -尽管看起来很相像,但在BPMN 2.0中,调用活动(call activity)有别于一般的__<>__——通常也称作__嵌入式子流程__。从概念上说,两者都在流程执行到达该活动时,调用一个子流程。 - -两者的区别为,调用活动引用一个流程定义外部的流程,而__<>__嵌入在原有流程定义内。调用活动的主要使用场景是,在多个不同流程定义中调用一个可复用的流程定义。 - -当流程执行到达__调用活动__时,会创建一个新的执行,作为到达调用活动的执行的子执行。这个子执行用于执行子流程,也可用于创建并行子执行(与普通流程中行为类似)。父执行将等待子流程完成,之后沿原流程继续执行。 - -[[bpmnCallActivityGraphicalNotation]] - - -===== 图示 - -调用过程表现为带有粗边框(折叠与展开都是)的<>。取决于建模工具,调用过程可以展开,但默认表现为折叠形式。 - -image::images/bpmn.collapsed.call.activity.png[align="center"] - - -[[bpmnCallActivityXMLRepresentation]] - - -===== XML表示 - -调用活动是一个普通活动,在__calledElement__中通过**key**引用流程定义。在实际使用中,通常在__calledElement__中配置**流程的ID**。 - -[source,xml,linenums] ----- - ----- - -请注意子流程的流程定义**在运行时解析**。这意味着如果需要的话,子流程可以与调用流程分别部署。 - -[[bpmnCallActivityPassVariables]] - - -===== 传递变量 - -可以向子流程传递与接收流程变量。数据将在子流程启动时复制到子流程,并在其结束时复制回主流程。 - -[source,xml,linenums] ----- - - - - - - ----- - -可以将++inheritVariables++设置为true,将所有流程变量传递给子流程。 - -[source,xml,linenums] ----- - ----- - -除了需要按照BPMN 2.0标准的方式声明流程变量的BPMN标准元素__dataInputAssociation__与__dataOutputAssociation__之外, -Flowable还提供了扩展作为快捷方式。 - -也可以在这里使用表达式: - -[source,xml,linenums] ----- - - - - - - ----- - -因此最终 z = y+5 = x+5+5 。 - -调用活动元素还提供了一个自定义Flowable属性扩展,__businessKey__,用于设置子流程实例的businessKey。 - ----- - -... - ----- - -将__inheritBusinessKey__属性设置为++true++,会将子流程的businessKey值设置为调用流程的businessKey的值。 - ----- - -... - ----- - - -[[bpmnCallActivityExample]] - -===== 引用同一部署中的流程 - -默认会使用引用流程最后部署的流程定义版本。但有的时候也会想引用与主流程一起部署的引用流程定义。这需要将主流程与引用流程放在同一个部署单元中,以便引用相同的部署。 - -在++callActivity++元素中,将++sameDeployment++属性设置为++true++,即可引用相同部署的流程。 - -如下例所示: - ----- - -... - ----- - -++sameDeployment++默认值为false。 - -[[_example]] -===== 示例 - -下面的流程图展示了简单的订单处理流程。因为检查客户的信用额度的操作在许多其他流程中都通用,因此将__check credit step(检查信用额度步骤)__建模为调用活动。 - -image::images/bpmn.call.activity.super.process.png[align="center"] - -流程像是下面这样: - -[source,xml,linenums] ----- - - - - - - - - - - - - - ----- - -子流程像是下面这样: - -image::images/bpmn.call.activity.sub.process.png[align="center"] - -与子流程的流程定义相比没什么特别。但调用活动的流程也可以不通过其他流程调用而直接使用。 - -[[bpmnConcurrencyAndTransactions]] - - -=== 事务与并发 - -[[asyncContinuations]] - - -==== 异步延续 -(Asynchronous Continuations) - -Flowable以事务方式执行流程,并可按照你的需求配置。让我们从Flowable一般如何为事务划分范围开始介绍。如果Flowable被触发(启动流程,完成任务,为执行发送信号),Flowable将沿流程执行,直到到达每个执行路径的等待状态。更具体地说,它以深度优先方式搜索流程图,并在每个执行分支都到达等待状态时返回。等待状态是“之后”再执行的任务,也就是说着Flowable将当前执行持久化,并等待再次触发。触发可以来自外部来源如用户任务或消息接受任务,也可以来自Flowable自身如定时器事件。以下面的图片说明: - -image::images/async.example.no.async.PNG[align="center"] - -这是一个BPMN流程的片段,有一个用户任务、一个服务任务,与一个定时器事件。用户任务的完成操作与验证地址(validate address)在同一个工作单元内,因此需要原子性地(atomically)成功或失败。这意味着如果服务任务抛出了异常,我们会想要回滚当前事务,以便执行返回到用户任务,并希望用户任务仍然保存在数据库中。这也是Flowable的默认行为。在(1)中,应用或客户端线程完成任务。在相同的线程中,Flowable执行服务并继续,直到到达等待状态,在这个例子中,是定时器事件(2)。然后将控制权返回至调用者(3),同时提交事务(如果事务由Flowable开启)。 - -在有的情况下,我们不想要这样。有时我们需要在流程中自定义地控制事务边界,以便为工作的逻辑单元划分范围。这就需要使用异步延续。考虑下面的流程(片段): - -image::images/async.example.async.PNG[align="center"] - -完成用户任务,生成发票,并将发票发送给客户。这次发票的生成不再是同一个工作单元的一部分,因此我们不希望当发票生成失败时,回滚用户任务。所以我们希望Flowable做的,是完成用户任务(1),提交事务,并将控制权返回给调用程序。然后我们希望在后台线程中,异步地生成发票。这个后台线程就是Flowable作业执行器(事实上是一个线程池),它周期性地将作业保存至数据库。因此在幕后,当到达"generate invoice(生成发票)"任务时,Flowable会创建“消息”作业并将其持久化到数据库中,用于继续执行流程。这个作业之后会被作业执行器选中并执行。Flowable也会向本地的作业执行器进行提示,告知其有新作业到来,以提升性能。 - -要使用这个特性,可以使用__flowable:async="true"__扩展。因此,一个示例的服务任务会像是这样: - -[source,xml,linenums] ----- - ----- - -可以为下列BPMN任务类型指定__flowable:async__:任务,服务任务,脚本任务,业务规则任务,发送任务,接收任务,用户任务,子流程,调用活动。 - -对于用户任务、接收任务与其他等待状态来说,异步操作允许我们在一个独立的线程/事务中启动执行监听器。 - -[[failRetry]] - - -==== 失败重试 - -默认配置下,如果作业执行中有任何异常,Flowable将三次重试执行作业。对异步作业也是这样。需要更灵活的配置时可以使用这两个参数: - -* 重试的次数 -* 重试的间隔 - -这两个参数可以通过++flowable:failedJobRetryTimeCycle++元素配置。这有一个简单的例子: - -[source,xml,linenums] ----- - - - - R5/PT7M - - ----- - -时间周期表达式与定时器事件表达式一样遵循ISO 8601标准。上面的例子会让作业执行器重试5次,并在每次重试前等待7分钟。 - - -[[exclusiveJobs]] - - -==== 排他作业 - -从近期版本开始,JobExecutor确保同一个流程实例的作业永远不会并发执行。为什么这样? - -[[_why_exclusive_jobs]] -===== 为什么使用排他作业? - -考虑下面的流程定义: - -image::images/bpmn.why.exclusive.jobs.png[align="center"] - -一个并行网关,之后是三个服务任务,都使用异步操作执行。其结果是在数据库中添加了三个作业。当作业储存在数据库后,就由JobExecutor处理。JobExecutor获取作业,并将其委托至工作线程的线程池,由它们实际执行作业。这意味着通过使用异步操作,可以将工作分发至线程池(在集群场景下,甚至会在集群中跨越多个线程池)。通常这都是好事。但也有其固有问题:一致性。考虑服务任务后的并行合并:当服务任务的执行完成时到达并行合并,并需要决定等待其他执行,还是需要继续向前。这意味着,对于每一个到达并行合并的分支,都需要选择继续执行,还是需要等待其他分支上的一个或多个其他执行。 - -为什么这是问题呢?这是因为服务任务配置为使用异步延续,有可能所有相应的作业都同时被作业执行器处理,并委托至不同的工作线程。结果是服务执行的事务,与到达并行合并的3个独立执行所在的事务会发生重叠。如果这样,每一个独立事务都“看不到”其他事物已经并发地到达了同样的并行合并,并因此判断自己需要等待其他事务。然而,如果每个事务都判断需要等待其他事务,在并行合并后不会有继续流程的事务,而流程实例也就会永远保持这个状态。 - -Flowable如何解决这个问题呢?Flowable使用乐观锁。每当需要基于数据进行判断,而数据可能不是最新值(因为其他事务可能在我们提交前修改了这个数据)时,我们确保会在每个事务中都增加同一个数据库记录行的版本号。这样,无论哪个事务第一个提交,都将成功,而其他的会抛出乐观锁异常并失败。这样就解决了上面流程中讨论的问题:如果多个执行并发到达并行合并,它们都判断需要等待,增加其父执行(流程实例)的版本号并尝试提交。无论哪个执行第一个提交,都可以成功提交,而其他的将会抛出乐观锁异常并失败。因为这些执行由作业触发,Flowable会在等待给定时间后,重试执行相同的作业,期望这一次通过这个同步的网关。 - -这是好的解决方案么?我们可以看到乐观锁使Flowable避免不一致状态。它确保了我们不会“在合并网关卡住”,也就是说:要么所有的执行都通过网关,要么数据库中的作业能确保可以重试通过它。然而,尽管这是一个持久化与一致性角度的完美解决方案,但从更高层次看,仍然不一定总是理想行为: - -* Flowable只会为同一个作业重试一个固定的最大次数(默认配置为__3__次)。在这之后,作业仍然保存在数据库中,但不会再重试。这就需要手动操作来触发作业。 -* 如果一个作业有非事务性的副作用,则副作用将不会由于事务失败而回滚。例如,如果"book concert tickets(预定音乐会门票)"服务与Flowable不在同一个事务中,则重试执行作业将预定多张票。 - -[[_what_are_exclusive_jobs]] -===== 什么是排他作业? - -排他作业不能与同一个流程实例中的其他排他作业同时执行。考虑上面展示的流程:如果我们将服务任务都声明为排他的,则JobExecutor将确保相关的作业都不会并发执行。相反,它将确保不论何时从特定流程实例中获取了排他作业,都会从同一个流程实例中获取所有其他的排他作业,并将它们委托至同一个工作线程。这保证了作业的顺序执行。 - -如何启用这个特性?从近期版本开始,排他作业成为默认配置。所有异步操作与定时器事件都默认为排他的。另外,如果希望作业成为非排他的,可以使用++flowable:exclusive="false"++配置。例如,下面的服务任务是异步,但非排他的。 - -[source,xml,linenums] ----- - ----- - -这是好的解决方案么?有很多人都在问这个问题。他们的顾虑是,这将阻止并行操作,因此会有性能问题。但也需要考虑以下两点: - -* 如果你是专家,并且知道你在做什么(并理解“为什么排他作业?”章节的内容),可以关掉排他。否则,对大多数用户来说,异步操作与定时器能够正常工作才更重要。 -* 事实上不会有性能问题。只有在重负载下才会有性能问题。重负载意味着作业执行器的所有的工作线程都一直忙碌。对于排他作业,Flowable会简单的根据负载不同进行分配。排他作业意味着同一个流程实例的作业都将在同一个线程中顺序执行。但是请想一下:我们有不止一个流程实例。其他流程实例的作业将被委托至其他线程,并与本实例的作业并发执行。也就是说Flowable不会并发执行同一个流程实例的排他作业,但会并发执行多个实例。从总吞吐量角度来看,可以期望大多数场景下都可以保证实例很快地完成。此外,执行同一个流程实例中下一个作业所需的数据,已经缓存在同一个执行集群节点中。如果作业与节点没有关联关系,则可能需要重新从数据库中获取数据。 - - -[[security]] - - -=== 流程启动认证 - -默认情况下,任何人都可以启动已部署流程定义的新流程实例。可以使用流程启动认证功能定义用户与组,让Web客户端可以选择性的限制能够启动新流程实例的用户。请注意Flowable引擎**不会**用任何方式验证认证定义。这个功能只是为了开发人员可以简化Web客户端认证规则的实现。语法与为用户任务指派用户的语法类似:可以使用标签,将用户或组指派为流程的潜在启动者。这里有一个例子: - -[source,xml,linenums] ----- - - - - - group2, group(group3), user(user3) - - - - - - ... ----- - -在上面的XML中,__user(user3)__直接引用用户__user3__,而__group(group3)__引用组__group3__。不显式标明的话,默认为组。也可以使用标签提供的的属性。这里有一个例子: - -[source,xml,linenums] ----- - - ... ----- - -这些属性可以同时使用。 - -在流程启动认证定义后,开发者可以使用下列方法获取该认证定义。 -这段代码获取可以由给定用户启动的流程定义列表: - -[source,java,linenums] ----- -processDefinitions = repositoryService.createProcessDefinitionQuery().startableByUser("userxxx").list(); ----- - -也可以获取给定流程定义中,所有定义为潜在启动者的身份关联 - -[source,java,linenums] ----- -identityLinks = repositoryService.getIdentityLinksForProcessDefinition("processDefinitionId"); ----- - -下面的例子展示了如何获取能够启动给定流程的用户列表: - -[source,java,linenums] ----- -List authorizedUsers = identityService().createUserQuery() - .potentialStarter("processDefinitionId") - .list(); ----- - -用完全相同的方法,可以获取配置为给定流程定义的潜在启动者的组列表: - -[source,java,linenums] ----- -List authorizedGroups = identityService().createGroupQuery() - .potentialStarter("processDefinitionId") - .list(); ----- - - -[[dataobjects]] - - -=== 数据对象 - -BPMN提供了将数据对象定义为流程或子流程元素的一部分的可能性。根据BPMN规范,数据对象可以包含复杂的XML结构,并可以从XSD定义中引入。下列XSD类型为Flowable支持的第一批数据对象: - -[source,xml,linenums] ----- - - - - - - ----- - -数据对象定义使用__name__属性值作为新变量的名字,将其自动转换为流程变量。另外,Flowable也提供了为变量设置默认值的扩展元素。下面的BPMN代码片段示例: - -[source,xml,linenums] ----- - - - - Testing123 - - - ... ----- diff --git a/docs/userguide/src/zh_CN/bpmn/ch08-Forms.adoc b/docs/userguide/src/zh_CN/bpmn/ch08-Forms.adoc deleted file mode 100755 index 463118deffb..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch08-Forms.adoc +++ /dev/null @@ -1,246 +0,0 @@ -[[forms]] - -== 表单 - -Flowable提供了一种简便灵活的方式,用来为业务流程中的人工步骤添加表单。 -有两种使用表单的方法:使用(由表单设计器创建的)表单定义的内置表单渲染,以及外部表单渲染。 -使用外部表单渲染时,可以使用(自Explorer web应用V5版本支持的)表单参数;也可以使用表单key定义,引用外部的、使用自定义代码解析的表单。 - -[[formDefinition]] - -=== 表单定义 - -link:$$http://flowable.org/docs/userguide-form/$$[表单引擎用户手册]中提供了关于表单定义与Flowable表单引擎的完整信息。 -可以使用Flowable表单设计器创建表单定义。表单设计器是Flowable Modeler web应用的一部分。也可以直接使用JSON编辑器创建表单定义。 -表单引擎用户手册中介绍了表单定义JSON的完整结构。表单支持下列表单字段类型: - -* Text: 渲染为文本框 -* Multiline text: 渲染为多行文本框 -* Number: 渲染为只允许数字值的文本框 -* CheckBox: 渲染为复选框 -* Date: 渲染为日期框 -* Dropdown: 渲染为下拉选择框,候选值由字段定义配置 -* Radio buttons: 渲染为单选按钮,候选值由字段定义配置 -* People: 渲染为选人框,可以选择用户身份表中的用户 -* Group of people: 渲染为选组框,可以选择组身份表中的组 -* Upload: 渲染为上传框 -* Expression: 渲染为一个标签,可以在标签文字中使用JUEL表达式,以使用变量及/或其他动态值 - -Flowable Task应用可以用表单定义JSON渲染出html表单。 -也可以使用Flowable API,自行获取表单定义JSON。 - -[source,java,linenums] ----- -FormModel RuntimeService.getStartFormModel(String processDefinitionId, String processInstanceId) ----- - -或 - -[source,java,linenums] ----- -FormModel TaskService.getTaskFormModel(String taskId) ----- - -FormModel对象是一个代表了表单定义JSON的Java对象。 - -可以调用下列API,使用启动表单定义以启动流程实例: - -[source,java,linenums] ----- -ProcessInstance RuntimeService.startProcessInstanceWithForm(String processDefinitionId, String outcome, - Map variables, String processInstanceName) ----- - -如果在流程定义的(某一个或多个)启动事件上定义了表单定义,则可以使用这个方法,使用启动表单中填写的值启动流程实例。 -Flowable Task应用使用同样的方法,用表单启动流程实例。 -通过变量map传入所有需要的表单值,也可以指定表单输出字符串及流程实例名。 - -类似的,可以调用下列API,使用表单完成用户任务: - -[source,java,linenums] ----- -void TaskService.completeTaskWithForm(String taskId, String formDefinitionId, - String outcome, Map variables) ----- - -再次强调,要获取关于表单定义的更多信息,请查看link:$$http://flowable.org/docs/userguide-form/$$[表单引擎用户手册]。 - - -[[formProperties]] - - -=== 表单参数 - -所有与业务流程相关的信息,要么包含在流程变量里,要么可以通过流程变量引用。Flowable也支持将复杂的Java对象,以++Serializable++对象、JPA实体,或整个XML文档存储为++String++等方式,存储为流程变量。 - -启动流程与完成用户任务是用户参与流程的地方,所以需要使用UI界面渲染表单。为了简化UI设计,可以在流程定义中,将流程变量中的复杂的Java对象转换为++Map++格式的**__参数__**。 - -这样UI就可以使用Flowable API方法,在这些参数的基础上构建表单。这些参数可看做是专用(也更受限)的流程变量视图。可以使用**FormData**返回值,获取用于显示表单的参数。如 - -[source,java,linenums] ----- -StartFormData FormService.getStartFormData(String processDefinitionId) ----- - -或 - -[source,java,linenums] ----- -TaskFormData FormService.getTaskFormData(String taskId) ----- - -默认情况下,内建表单引擎能够“看到”参数与流程变量。因此如果任务表单参数一对一对应流程变量,则不需要专门进行声明。例如,对于如下声明: - -[source,xml,linenums] ----- - ----- - -当执行到达startEvent时,所有流程变量都可用。但 - -[source,java,linenums] ----- -formService.getStartFormData(String processDefinitionId).getFormProperties() ----- - -将为空,因为并未指定映射。 - -在上面的例子中,所有提交的参数都存储为流程变量。也就是说,只要简单地在表单中添加输入框,就可以存储新变量。 - -参数从流程变量衍生而来,但并不是必须存储为流程变量。例如,流程变量可以是Address类的JPA实体。而UI使用的++StreetName++表单参数,则通过++#{address.street}++表达式获取。 - -类似的,表单中用户需要提交的参数,可以存储为流程变量,也可以使用UEL值表达式,保存至某个流程变量的参数。如++#{address.street}++。 - -除非使用++formProperty++声明,否则提交参数时,默认将其存储为流程变量。 - -在表单参数与流程变量的处理过程中,也可以进行类型转换。 - -例如: - -[source,xml,linenums] ----- - - - - - - - - ----- - -* ++room++表单参数将作为String,映射为++room++流程变量 -* ++duration++表单参数将作为java.lang.Long,映射为++duration++流程变量 -* ++speaker++表单参数将被映射为++SpeakerName++流程变量。将只在TaskFormData对象中可用。若提交了speaker参数,将抛出FlowableException。对应地,使用++readable="false"++属性,参数可以提交,但不会在FormData中提供。 -* ++street++表单参数将作为String,映射为++address++流程变量的Java bean参数++street++。如果在提交时没有提供这个字段,required="true"将抛出异常。 - -++StartFormData FormService.getStartFormData(String processDefinitionId)++与++TaskFormdata FormService.getTaskFormData(String taskId)++方法返回的FormData同样提供类型元数据。 - -支持下列表单参数类型: - -* +string+ (org.flowable.engine.impl.form.StringFormType -* +long+ (org.flowable.engine.impl.form.LongFormType) -* +double+ (org.flowable.engine.impl.form.DoubleFormType) -* +enum+ (org.flowable.engine.impl.form.EnumFormType) -* +date+ (org.flowable.engine.impl.form.DateFormType) -* +boolean+ (org.flowable.engine.impl.form.BooleanFormType) - -可以通过++List formService.getStartFormData(String processDefinitionId).getFormProperties()++与++List formService.getTaskFormData(String taskId).getFormProperties()++方法,获取每个表单参数的下列++FormProperty++信息: - -[source,java,linenums] ----- -public interface FormProperty { - /** - * 在{@link FormService#submitStartFormData(String, java.util.Map)} - * 或{@link FormService#submitTaskFormData(String, java.util.Map)} - * 中提交参数时使用的key - */ - String getId(); - - /** 显示标签 */ - String getName(); - - /** 在本接口中定义的类型,例如{@link #TYPE_STRING} */ - FormType getType(); - - /** 可选。这个参数需要显示的值 */ - String getValue(); - - /** 这个参数是否可以读取:在表单中显示,并可通过 - * {@link FormService#getStartFormData(String)} - * 与{@link FormService#getTaskFormData(String)} - * 方法访问。 - */ - boolean isReadable(); - - /** 用户提交表单时是否可以包含这个参数? */ - boolean isWritable(); - - /** 输入框中是否必填这个参数 */ - boolean isRequired(); -} ----- - -例如: - -[source,xml,linenums] ----- - - - - - - - - - - - - - - - ----- - -所有这些信息都可以通过API获取:用++formProperty.getType().getName()++获取类型名、++formProperty.getType().getInformation("datePattern")++获取日期格式、++formProperty.getType().getInformation("values")++获取枚举值。 - -下面的XML代码片段 - -[source,xml,linenums] ----- - - - - - - - - ----- - -可以在自定义应用中用于渲染流程启动表单。 - - -[[externalFormRendering]] - - -=== 外部表单渲染 - -也可以使用API,在Flowable引擎之外,自行渲染任务表单。下面的步骤介绍在自行渲染任务表单时,可以使用的钩子。 - -实际上,渲染表单所需的所有数据都组装在:++StartFormData FormService.getStartFormData(String processDefinitionId)++与++TaskFormdata FormService.getTaskFormData(String taskId)++这两个方法中。 - -可以通过++ProcessInstance FormService.submitStartFormData(String processDefinitionId, Map properties)++与++void FormService.submitTaskFormData(String taskId, Map properties)++提交表单参数。 - -查看<>了解如何将表单参数映射至流程变量。 - -如果希望按版本将表单与流程存储在一起,可以将表单模板资源放在部署的业务存档中,并可以使用++String ProcessDefinition.getDeploymentId()++与++InputStream RepositoryService.getResourceAsStream(String deploymentId, String resourceName);++,作为部署中的资源获取,在你的应用中渲染/显示表单。 - -除了任务表单之外,也可以获取其他部署资源。 - -++String FormService.getStartFormData(String processDefinitionId).getFormKey()++与++String FormService.getTaskFormData(String taskId).getFormKey()++API提供++ - - - - - - - - - - - - - - -
----- - -下面的示例配置使用自定义的++EntityManagerFactory++(open-jpa实体管理器)。请注意这段代码只包含了与本例相关的bean,而省略了其他的bean。使用open-jpa实体管理器的完整可用示例,可以在flowable-spring-examples (++/flowable-spring/src/test/java/org/flowable/spring/test/jpa/JPASpringTest.java++)中找到。 - -[source,xml,linenums] ----- - - - - - - - - - - - - - - - - - - ----- - -也可以使用相同的配置,以编程方式构建引擎。例如: - -[source,java,linenums] ----- -ProcessEngine processEngine = ProcessEngineConfiguration - .createProcessEngineConfigurationFromResourceDefault() - .setJpaPersistenceUnitName("flowable-pu") - .buildProcessEngine(); ----- - -配置参数: - -* ++jpaPersistenceUnitName++:要使用的持久化单元的名字。(需要确保该持久化单元在classpath中可用。根据规范,默认位置为++/META-INF/persistence.xml++)。++jpaEntityManagerFactory++与++jpaPersistenceUnitName++二选一。 - -* ++jpaEntityManagerFactory++:用于载入实体及刷入更新的,实现++jakarta.persistence.EntityManagerFactory++的bean。__jpaEntityManagerFactory__与__jpaPersistenceUnitName__二选一。 - -* ++jpaHandleTransaction++:标示是否需要由引擎负责开启及提交/回滚__EntityManager__上的事务。当使用__Java Transaction API (JTA)__时,需设置为false。 - -* ++jpaCloseEntityManager++:标示是否需要由引擎负责关闭从++EntityManagerFactory++获取的++EntityManager++实例。当__EntityManager__由容器管理时(例如,使用扩展持久化上下文 Extended Persistence Context,而不将实体范围限制为单一事务时)需设置为false。 - -[[_usage]] -=== 使用 - -[[_simple_example]] -==== 简单示例 - -可以在Flowable源代码的JPAVariableTest中找到使用JPA变量的例子。下面逐步解释++JPAVariableTest.testUpdateJPAEntityValues++。 - -首先,基于++META-INF/persistence.xml++为持久化单元创建__EntityManagerFactory__。包括需要包含在持久化单元内的类及一些(数据库)厂商特定配置。 - -在这个测试里使用的是简单实体,包括id以及一个++String++值参数。在运行测试前,先创建一个实体并保存。 - -[source,java,linenums] ----- -@Entity(name = "JPA_ENTITY_FIELD") -public class FieldAccessJPAEntity { - - @Id - @Column(name = "ID_") - private Long id; - - private String value; - - public FieldAccessJPAEntity() { - // JPA需要的空构造方法 - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } -} ----- - -启动一个新的流程实例,将这个实体加入变量。与其他变量一样,它们都会在引擎中持久化存储。当下一次请求这个变量时,将会根据类及Id,从++EntityManager++载入。 - -[source,java,linenums] ----- -Map variables = new HashMap(); -variables.put("entityToUpdate", entityToUpdate); - -ProcessInstance processInstance = runtimeService.startProcessInstanceByKey( - "UpdateJPAValuesProcess", variables); ----- - -流程定义的第一个节点是++服务任务++,将调用++entityToUpdate++上的++setValue++方法。++entityToUpdate++将解析为之前启动流程实例时设置的JPA变量,并使用当前引擎的上下文中关联的++EntityManager++载入。 - -[source,xml,linenums] ----- - ----- - -当服务任务完成时,流程实例在流程定义中的用户任务处等待,以便我们可以查看流程实例。在这时,++EntityManager++已经刷入,对实体的修改也已经存入数据库。当获取++entityToUpdate++变量的值时,将重新载入实体。所以可以得到++value++参数设置为++updatedValue++的实体。 - - -[source,java,linenums] ----- -// 流程'UpdateJPAValuesProcess'中的服务任务已经设置了entityToUpdate的值。 -Object updatedEntity = runtimeService.getVariable(processInstance.getId(), "entityToUpdate"); -assertTrue(updatedEntity instanceof FieldAccessJPAEntity); -assertEquals("updatedValue", ((FieldAccessJPAEntity)updatedEntity).getValue()); ----- - -[[_query_jpa_process_variables]] -==== 查询JPA流程变量 - -可以查询以特定JPA实体作为变量值的++流程实例++与++执行++。**请注意++ProcessInstanceQuery++与++ExecutionQuery++中,只有++variableValueEquals(name, entity)++方法支持JPA实体查询**。而++variableValueNotEquals++、++variableValueGreaterThan++、++variableValueGreaterThanOrEqual++、++variableValueLessThan++与++variableValueLessThanOrEqual++等方法都不支持JPA,并会在值传递为JPA实体时,抛出++FlowableException++。 - -[source,java,linenums] ----- - ProcessInstance result = runtimeService.createProcessInstanceQuery() - .variableValueEquals("entityToQuery", entityToQuery).singleResult(); ----- - -[[_advanced_example_using_spring_beans_and_jpa]] -==== 使用Spring bean与JPA的高级示例 - -可以在++flowable-spring-examples++中找到高级用法的示例——++JPASpringTest++。它描述了一个简单的用例: - -* 使用一个已有的Spring bean及已定义的JPA实体,用于存储贷款申请。 -* Flowable通过该bean获取该实体,并将其用作流程中的变量。流程定义如下步骤: -** 使用++LoanRequestBean++,并使用启动流程时(从启动表单)接收的变量创建LoanRequest(贷款申请)实体的服务任务。使用++flowable:resultVariable++将表达式结果,即所创建的实体存储为流程变量。 -** 经理用于审核并批准/驳回申请的用户任务,并将审核结论存储为boolean变量++approvedByManager++。 -** 更新贷款申请实体的服务任务,使实体与流程同步。 -** 使用一个排他网关,依据++approved++实体参数的值选择下一步采用哪条路径:若申请被批准,结束流程;否则,生成一个额外任务(Send rejection letter 发送拒信),以便客户可以收到拒信得到通知。 - -请注意这个流程只用于单元测试,而不包含任何表单。 - -image::images/jpa.spring.example.process.png[align="center"] - -[source,xml,linenums] ----- - - - - - - - - - - - - - - - - - - - ${loanRequest.approved} - - - ${!loanRequest.approved} - - - - - - - - - - ----- - -尽管上面的例子很简单,但也展示了JPA与Spring结合,以及带参数方法表达式的威力。这个流程本身完全不需要写Java代码(当然还是需要写Spring bean),大幅加速了开发。 diff --git a/docs/userguide/src/zh_CN/bpmn/ch09-ProcessInstanceMigration.adoc b/docs/userguide/src/zh_CN/bpmn/ch09-ProcessInstanceMigration.adoc deleted file mode 100644 index 98884841ee4..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch09-ProcessInstanceMigration.adoc +++ /dev/null @@ -1,85 +0,0 @@ - -== Process Instance Migration (Experimental) - -When process definitions are updated with new versions, the question arises what should be done with already running process instances that are using older versions of the process definition. -In case running process instances should be migrated to another process definition version, you can use the process instance migration features on the Flowable Engine. - - -=== Simple example - -Let's start with a simple example to explain the basics of process instance migration in the Flowable Engine. -In this simple example we use the following use case: - -* There's one process instance running with a process definition that has a key named simpleTasks and it consists of a start event - user task 1 - end event. -* The running process instance has an active state of user task 1. -* A new process definition is deployed with the same key (simpleTasks) and the process definition now consists of a start event - user task 1 - user task 2 - end event. -* The running process instance should be migrated to the new process definition. - -To test if the process instance can be migrated without issues the following code can be used: - -[source,java,linenums] ----- -ProcessInstanceMigrationValidationResult validationResult = runtimeService.createProcessInstanceMigrationBuilder() - .migrateToProcessDefinition(version2ProcessDef.getId()) - .validateMigration(processInstanceToMigrate.getId()); - -boolean isMigrationValid = validationResult.isMigrationValid(); ----- - -The process instance migration builder can be used to validate and, as we will see later on, migrate one or more process instances. -In this case we test if the running process instance can be migrated to the new process definition version with 2 user tasks. -Because the user task id didn't change between the two process definition versions, the process instance can be migrated without any additional mapping configuration. -Therefore the migration will have a migration valid boolean value of true. This means we can run the actual migration without to be expected issues. - -[source,java,linenums] ----- -ProcessInstanceMigrationValidationResult validationResult = runtimeService.createProcessInstanceMigrationBuilder() - .migrateToProcessDefinition(version2ProcessDef.getId()) - .migrate(processInstanceToMigrate.getId()); ----- - -After executing the migrate method, the running process instance is migrated to the new process definition (including the historic information). -This means that when user task 1 is completed, user task 2 will be the next active state for the running process instance. - -=== Migration with activity migration mappings - -In the simple example user task 1 was automatically mapped to the same user task in the new process definition version. -But in some cases the current activity of a running process instance doesn't exist anymore in the new process definition, or the activity should be migrated to another activity for another reason. -For this use case, the process instance migration builder allows you to specify a list of specific activity migration mappings. - -[source,java,linenums] ----- -ProcessInstanceMigrationValidationResult validationResult = runtimeService.createProcessInstanceMigrationBuilder() - .migrateToProcessDefinition(version2ProcessDef.getId()) - .addActivityMigrationMapping("userTask1Id", "userTask2Id") - .migrate(processInstanceToMigrate.getId()); ----- - -In this example running process instance with an active state of user task 1 will be migrated to a new process definition version with 2 user tasks, and the active state will be migrated to user task 2. -This means that when user task 2 is completed the process instance will be ended. - -=== Supported process instance migration cases - -This section provides an overview of the supported cases for process instance migration. -If the case you are looking for is not yet supported have a look at next section with upcoming support. - -* automatic migration of wait states (user task, receive task, intermediate catch events) to activities with the same id in the new process definition version. -* manual migration of wait states by specifying the target activity for a specific active state in the running process instance. -* migrating a wait state to an activity with a boundary timer, signal or message event. -* migrating a wait state with a boundary timer, signal or message event to an activity without a boundary event. -* migrating a wait state to an activity in an embedded sub process or a nested embedded subprocess. -* migrating a wait state in an embedded sub process or a nested embedded sub process to the root level of the process definition or another nested scope. -* migrating a wait state to an activity in an (nested) event sub process, both interrupting and non-interrupting. - -=== Upcoming process instance migration support - -With this version of the Flowable Engine the first step with process instance migration support is added. In the next version the focus is on adding support for the following migration cases: - -* Support moving multiple executions when using a parallel or inclusive gateway, to one execution outside of the gateway scope. -* Support moving from a single execution to multiple executions within a parallel or inclusive gateway. -* Support to move a collection of multi instance executions to another activity. -* Support to move a wait state to a multi instance activity. -* Support to move a wait state to an activity in a sub process, when one or more call activities are present in the process definition. -* Support to move a wait state to an activity in the parent process. -* Support to add and remove variables in the process instance or local execution scope. -* Support to define the assignment rules and other configuration options of a target user task. \ No newline at end of file diff --git a/docs/userguide/src/zh_CN/bpmn/ch10-History.adoc b/docs/userguide/src/zh_CN/bpmn/ch10-History.adoc deleted file mode 100755 index 271cad586ec..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch10-History.adoc +++ /dev/null @@ -1,243 +0,0 @@ -[[history]] - -== 历史 - -历史是记录流程执行过程中发生的事情,并将其永久存储的组件。与运行时数据不同,历史数据在流程实例完成以后仍保存在数据库中。 - -有6个历史实体: - -* ++HistoricProcessInstance++保存当前及已结束流程实例的信息。 -* ++HistoricVariableInstance++保存流程变量或任务变量的最新值。 -* ++HistoricActivityInstance++保存活动(流程中的节点)的一次执行的信息。 -* ++HistoricTaskInstance++保存当前与历史(完成及删除的)任务实例的信息。 -* ++HistoricIdentityLink++保存任务及流程实例、当前及历史的身份关联的信息。 -* ++HistoricDetail++保存与历史流程实例、活动实例或任务实例等有关的多种信息。 - -历史与当前进行中的流程实例都在数据库中保存历史实体,因此可以选择直接查询历史表,以减少对运行时流程实例数据的访问,并提高运行时执行的性能。 - -[[historyQuery]] - - -=== 查询历史 - -可以使用HistoryServiceAPI提供的++createHistoricProcessInstanceQuery()++、++createHistoricVariableInstanceQuery()++、++createHistoricActivityInstanceQuery()++、 ++getHistoricIdentityLinksForTask()++、++getHistoricIdentityLinksForProcessInstance()++、++createHistoricDetailQuery()++与++createHistoricTaskInstanceQuery()++方法,查询全部6种历史实体。 - -下面用一些例子展示历史查询API的部分用法。可以在link:$$http://flowable.org/javadocs/index.html$$[javadoc]的++org.flowable.engine.history++包中找到全部用法。 - -[[historyQueryProcessInstance]] - - -==== 历史流程实例查询 - -获取所有流程中,完成所花费时间(持续时间)排名前10的、流程定义为__XXX__的、已完成的++HistoricProcessInstances(历史流程实例)++。 - -[source,java,linenums] ----- -historyService.createHistoricProcessInstanceQuery() - .finished() - .processDefinitionId("XXX") - .orderByProcessInstanceDuration().desc() - .listPage(0, 10); ----- - - -[[historyQueryVariableInstance]] - - -==== 历史变量实例查询 - -获取已完成的、id为'XXX'的流程实例中,所有的++HistoricVariableInstances(历史变量实例)++,并以变量名排序。 - -[source,java,linenums] ----- -historyService.createHistoricVariableInstanceQuery() - .processInstanceId("XXX") - .orderByVariableName.desc() - .list(); ----- - -[[historyQueryActivityInstance]] - - -==== 历史活动实例查询 - -获取最新的、已完成的、流程定义的id为XXX的、服务任务类型的++HistoricActivityInstance(历史活动实例)++。 - -[source,java,linenums] ----- -historyService.createHistoricActivityInstanceQuery() - .activityType("serviceTask") - .processDefinitionId("XXX") - .finished() - .orderByHistoricActivityInstanceEndTime().desc() - .listPage(0, 1); ----- - -[[historyQueryDetail]] - - -==== 历史详情查询 - -下面的的例子获取id为123的流程中所有的变量更新记录。这个查询只会返回++HistoricVariableUpdate(历史变量更新)++。请注意一个变量名可能会有多个++HistoricVariableUpdate++实体,这代表了流程中的每一次变量更新。可以使用++orderByTime(按变量更新的时间)++或++orderByVariableRevision(按变量更新的版本号)++对这些更新记录进行排序。 - - -[source,java,linenums] ----- -historyService.createHistoricDetailQuery() - .variableUpdates() - .processInstanceId("123") - .orderByVariableName().asc() - .list() ----- - -下面的例子获取流程id为"123"的、启动时提交或任何任务中提交的所有<>。这个查询只会返回++HistoricFormProperties(历史表单参数)++。 - -[source,java,linenums] ----- -historyService.createHistoricDetailQuery() - .formProperties() - .processInstanceId("123") - .orderByVariableName().asc() - .list() ----- - -最后一个例子获取id为"123"的任务进行的所有变量更新操作。将返回该任务设置的所有变量(任务局部变量)的++HistoricVariableUpdates++,而**不会**返回流程实例中设置的变量。 - -[source,java,linenums] ----- -historyService.createHistoricDetailQuery() - .variableUpdates() - .taskId("123") - .orderByVariableName().asc() - .list() ----- - -可以在++TaskListener++中使用++TaskService++或++DelegateTask++设置任务局部变量: - -[source,java,linenums] ----- -taskService.setVariableLocal("123", "myVariable", "Variable value"); ----- - -[source,java,linenums] ----- -public void notify(DelegateTask delegateTask) { - delegateTask.setVariableLocal("myVariable", "Variable value"); -} ----- - -[[historyQueryTaskInstance]] - - -==== 历史任务实例查询 - -获取所有任务中,完成所花费时间(持续时间)排名前10的、已完成的++HistoricTaskInstance(历史任务实例)++。 - -[source,java,linenums] ----- -historyService.createHistoricTaskInstanceQuery() - .finished() - .orderByHistoricTaskInstanceDuration().desc() - .listPage(0, 10); ----- - -获取删除原因包含"invalid"的、最终指派给__kermit__用户的++HistoricTaskInstance++。 - -[source,java,linenums] ----- -historyService.createHistoricTaskInstanceQuery() - .finished() - .taskDeleteReasonLike("%invalid%") - .taskAssignee("kermit") - .listPage(0, 10); ----- - - -[[historyConfig]] - -=== 配置历史 - -可以使用org.flowable.engine.impl.history.HistoryLevel枚举(或在5.11之前的版本中,++ProcessEngineConfiguration++中定义的__HISTORY__常量),以编程方式配置历史级别: - - -[source,java,linenums] ----- -ProcessEngine processEngine = ProcessEngineConfiguration - .createProcessEngineConfigurationFromResourceDefault() - .setHistory(HistoryLevel.AUDIT.getKey()) - .buildProcessEngine(); ----- - -也可以在flowable.cfg.xml或Spring上下文中配置级别: - -[source,xml,linenums] ----- - - - ... - ----- - -可以配置下列历史级别: - -* ++none(无)++:跳过所有历史的存档。这是流程执行性能最高的配置,但是不会保存任何历史信息。 - -* ++activity(活动)++:存档所有流程实例与活动实例。在流程实例结束时,将顶级流程实例变量的最新值复制为历史变量实例。但不会存档细节。 - -* ++audit(审计)++:默认级别。将存档所有流程实例及活动实例,并保持变量值与提交的表单参数的同步,以保证所有通过表单进行的用户操作都可追踪、可审计。 - -* ++full(完全)++:历史存档的最高级别,因此也最慢。这个级别存储所有++audit++级别存储的信息,加上所有其他细节(主要是流程变量的更新)。 - -**在Flowable 5.11版本以前,历史级别保存在数据库中(+$$ACT_GE_PROPERTY$$+ 表,参数名为++historyLevel++)。从5.11开始,这个值不再使用,并从数据库中忽略/删除。现在可以在引擎每次启动时切换历史级别。不会由于前一次启动时修改了级别,而导致本次启动抛出异常。** - -[[asyncHistoryConfig]] - -=== 配置异步历史 - -[实验性] Flowable 6.1.0引入了异步历史,使用历史作业执行器异步地进行历史数据的持久化。 - -[source,xml,linenums] ----- - - - - - ... - ----- - -配置++asyncHistoryExecutorActivate++参数后,流程引擎启动时会自动启动历史作业执行器。只有在测试(或不使用异步历史时)才应该设置为false。 -++asyncHistoryExecutorNumberOfRetries++参数用于配置异步历史作业的重试次数。这个参数与普通的异步作业有些不同,因为历史作业可能需要更多周期才能成功完成。比如,首先需要在ACT_HI_TASK_表中创建一个历史的任务,然后才能在另一个历史作业中记录其办理人的更新。流程引擎配置中,这个参数的默认值为10。到达重试次数后,会忽略这个历史作业(且不会写入死信作业表中)。 - -另外,可以使用++asyncHistoryExecutor++参数配置异步执行器,与普通的异步作业执行器类似。 - -如果不在默认的历史表中保存历史数据,而是在NoSQL数据库(Elasticsearch、MongoDb、Cassandra等)或其他什么地方保存,可以覆盖处理作业的处理器: - -* 使用++historyJobHandlers++参数,配置全部自定义历史作业处理器的map -* 或者,配置++customHistoryJobHandlers++列表。启动时会将列表中的所有处理器加入++historyJobHandlers++ map中。 - -另外,也可以使用消息队列,让引擎在产生新的历史作业时发送消息。这样,历史数据就可以在另外的服务器中进行处理。也可以配置引擎及消息队列使用JTA(以及JMS),这样就可以不用在作业中记录历史数据,而可以将所有数据发送至全局事务的消息队列中。 - -link:$$https://github.com/flowable/flowable-examples/tree/master/async-history$$[Flowable异步历史示例]提供了配置异步历史的不同示例,包括默认方式、JMS队列、JTA,还有使用消息队列,并使用Spring Boot应用作为消息监听器。 - -[[historyFormAuditPurposes]] - - -=== 用于审计的历史 - -如果历史至少<>为++audit++级别,则会记录由++FormService.submitStartFormData(String processDefinitionId, Map properties)++与++FormService.submitTaskFormData(String taskId, Map properties)++方法提交的所有参数。 - -表单参数可以像这样通过查询API读取: - -[source,java,linenums] ----- -historyService - .createHistoricDetailQuery() - .formProperties() - ... - .list(); ----- - -这段代码只会返回++HistoricFormProperty++类型的历史详情。 - -如果在调用提交方法前,使用++IdentityService.setAuthenticatedUserId(String)++设置了认证用户,那么也可以在历史中获取该认证用户信息。使用++HistoricProcessInstance.getStartUserId()++获取启动表单的认证用户信息,任务表单则需使用++HistoricActivityInstance.getAssignee()++。 diff --git a/docs/userguide/src/zh_CN/bpmn/ch10-JPA.adoc b/docs/userguide/src/zh_CN/bpmn/ch10-JPA.adoc deleted file mode 100644 index ed04308bead..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch10-JPA.adoc +++ /dev/null @@ -1,232 +0,0 @@ - -== JPA - -You can use JPA-Entities as process variables, allowing you to: - -* Updating existing JPA-entities based on process variables that can be filled in on a form in a userTask or generated in a serviceTask. -* Reusing existing domain model without having to write explicit services to fetch the entities and update the values -* Make decisions (gateways) based on properties of existing entities. -* ... - - -=== Requirements - -Only entities that comply with the following are supported: - -* Entities should be configured using JPA-annotations, we support both field and property-access. Mapped super classes can also be used. -* Entity should have a primary key annotated with +@Id+, compound primary keys are not supported (++@EmbeddedId++ and ++@IdClass++). The Id field/property can be of any type supported in the JPA-spec: Primitive types and their wrappers (excluding boolean), ++String++, ++BigInteger++, ++BigDecimal++, ++java.util.Date++ and ++java.sql.Date++. - -[[jpaconfiguration]] - - -=== Configuration - -To be able to use JPA-entities, the engine must have a reference to an +EntityManagerFactory+. This can be done by configuring a reference or by supplying a persistence-unit name. JPA-entities used as variables will be detected automatically and will be handled accordingly. - -The example configuration below uses the jpaPersistenceUnitName: - -[source,xml,linenums] ----- - - - - - - - - - - - - - - - - ----- - -The next example configuration below provides a +EntityManagerFactory+ which we define ourselves (in this case, an open-jpa entity manager). Note that the snippet only contains the beans that are relevant for the example, the others are omitted. Full working example with open-jpa entity manager can be found in the flowable-spring-examples (++/flowable-spring/src/test/java/org/flowable/spring/test/jpa/JPASpringTest.java++) - -[source,xml,linenums] ----- - - - - - - - - - - - - - - - - - - ----- - -The same configurations can also be done when building an engine programmatically, example: - -[source,java,linenums] ----- -ProcessEngine processEngine = ProcessEngineConfiguration - .createProcessEngineConfigurationFromResourceDefault() - .setJpaPersistenceUnitName("flowable-pu") - .buildProcessEngine(); ----- - -Configuration properties: - -* ++jpaPersistenceUnitName++: The name of the persistence-unit to use. (Make sure the persistence-unit is available on the classpath. According to the spec, the default location is ++/META-INF/persistence.xml++). Use either +jpaEntityManagerFactory+ or +jpaPersistenceUnitName+. -* ++jpaEntityManagerFactory++: An reference to a bean implementing +jakarta.persistence.EntityManagerFactory+ that will be used to load the Entities and flushing the updates. Use either _jpaEntityManagerFactory_ or _jpaPersistenceUnitName_. -* ++jpaHandleTransaction++: Flag indicating that the engine should begin and commit/rollback the transaction on the used _EntityManager_ instances. Set to false when _Java Transaction API (JTA)_ is used. -* ++jpaCloseEntityManager++: Flag indicating that the engine should close the +EntityManager+ instance that was obtained from the +EntityManagerFactory+. Set to false when the _EntityManager_ is container-managed (e.g. when using an Extended Persistence Context which isn't scoped to a single transaction'). - -=== Usage - -==== Simple Example - -Examples for using JPA variables can be found in JPAVariableTest in the Flowable source code. We'll explain +JPAVariableTest.testUpdateJPAEntityValues+ step by step. - -First of all, we create an _EntityManagerFactory_ for our persistence-unit, which is based on +META-INF/persistence.xml+. This contains classes which should be included in the persistence unit and some vendor-specific configuration. - -We are using a simple entity in the test, having an id and +String+ value property, which is also persisted. Before running the test, we create an entity and save this. - -[source,java,linenums] ----- -@Entity(name = "JPA_ENTITY_FIELD") -public class FieldAccessJPAEntity { - - @Id - @Column(name = "ID_") - private Long id; - - private String value; - - public FieldAccessJPAEntity() { - // Empty constructor needed for JPA - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } -} ----- - -We start a new process instance, adding the entity as a variable. As with other variables, they are stored in the persistent storage of the engine. When the variable is requested the next time, it will be loaded from the +EntityManager+ based on the class and Id stored. - -[source,java,linenums] ----- -Map variables = new HashMap(); -variables.put("entityToUpdate", entityToUpdate); - -ProcessInstance processInstance = runtimeService.startProcessInstanceByKey( - "UpdateJPAValuesProcess", variables); ----- - -The first node in our process definition contains a +serviceTask+ that will invoke the method +setValue+ on +entityToUpdate+, which resolves to the JPA variable we set earlier when starting the process instance and will be loaded from the +EntityManager+ associated with the current engine's context. - -[source,xml,linenums] ----- - ----- - -When the service-task is finished, the process instance waits in a userTask defined in the process definition, which allows us to inspect the process instance. At this point, the +EntityManager+ has been flushed and the changes to the entity have been pushed to the database. When we get the value of the variable +entityToUpdate+, it's loaded again and we get the entity with its +value+ property set to +updatedValue+. - -[source,java,linenums] ----- -// Servicetask in process 'UpdateJPAValuesProcess' should have set value on entityToUpdate. -Object updatedEntity = runtimeService.getVariable(processInstance.getId(), "entityToUpdate"); -assertTrue(updatedEntity instanceof FieldAccessJPAEntity); -assertEquals("updatedValue", ((FieldAccessJPAEntity)updatedEntity).getValue()); ----- - -==== Query JPA process variables - -You can query for ++ProcessInstance++s and ++Execution++s that have a certain JPA-entity as variable value. *Note that only +variableValueEquals(name, entity)+ is supported for JPA-Entities on +ProcessInstanceQuery+ and +ExecutionQuery+*. Methods +variableValueNotEquals+, +variableValueGreaterThan+, +variableValueGreaterThanOrEqual+, +variableValueLessThan+ and +variableValueLessThanOrEqual+ are unsupported and will throw an +FlowableException+ when a JPA-Entity is passed as value. - -[source,java,linenums] ----- - ProcessInstance result = runtimeService.createProcessInstanceQuery() - .variableValueEquals("entityToQuery", entityToQuery).singleResult(); ----- - -==== Advanced example using Spring beans and JPA - - -A more advanced example, +JPASpringTest+, can be found in +flowable-spring-examples+. It describes the following simple use case: - -* An existing Spring-bean which uses JPA entities already exists which allows for Loan Requests to be stored. -* Using Flowable, we can use the existing entities, obtained through the existing bean, and use them as variable in our process. Process is defined in the following steps: -** Service task that creates a new LoanRequest, using the existing +LoanRequestBean+ using variables received when starting the process (e.g. could come from a start form). The created entity is stored as a variable, using +flowable:resultVariable+ which stores the expression result as a variable. -** UserTask that allows a manager to review the request and approve/disapprove, which is stored as a boolean variable +approvedByManager+ -** ServiceTask that updates the loan request entity so the entity is in sync with the process. -** Depending on the value of the entity property +approved+, an exclusive gateway is used to make a decision about what path to take next: When the request is approved, process ends, otherwise, an extra task will become available (Send rejection letter), so the customer can be notified manually by a rejection letter. - -Please note that the process doesn't contain any forms, since it is only used in a unit test. - -image::images/jpa.spring.example.process.png[align="center"] - -[source,xml,linenums] ----- - - - - - - - - - - - - - - - - - - - ${loanRequest.approved} - - - ${!loanRequest.approved} - - - - - - - - - - ----- - - -Although the example above is quite simple, it shows the power of using JPA combined with Spring and parametrized method-expressions. The process requires no custom java-code at all (except for the Spring-bean off course) and speeds up development drastically. diff --git a/docs/userguide/src/zh_CN/bpmn/ch11-History.adoc b/docs/userguide/src/zh_CN/bpmn/ch11-History.adoc deleted file mode 100644 index 82873f83bfc..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch11-History.adoc +++ /dev/null @@ -1,243 +0,0 @@ -[[history]] - -== History - -History is the component that captures what happened during process execution and stores it permanently. In contrast to the runtime data, the history data will remain present in the DB also after process instances have completed. - -There are 6 history entities: - -* ++HistoricProcessInstance++s containing information about current and past process instances. -* ++HistoricVariableInstance++s containing the latest value of a process variable or task variable. -* ++HistoricActivityInstance++s containing information about a single execution of an activity (node in the process). -* ++HistoricTaskInstance++s containing information about current and past (completed and deleted) task instances. -* ++HistoricIdentityLink++s containing information about current and past identity links on tasks and process instances. -* ++HistoricDetail++s containing various kinds of information related to either a historic process instances, an activity instance or a task instance. - -Since the DB contains historic entities for past as well as ongoing instances, you might want to consider querying these tables in order to minimize access to the runtime process instance data and that way keeping the runtime execution performant. - - -[[historyQuery]] - - -=== Querying history - -In the API, it's possible to query all 6 of the History entities. The HistoryService exposes the methods +createHistoricProcessInstanceQuery()+, +createHistoricVariableInstanceQuery()+, +createHistoricActivityInstanceQuery()+, +getHistoricIdentityLinksForTask()+, +getHistoricIdentityLinksForProcessInstance()+, +createHistoricDetailQuery()+ and +createHistoricTaskInstanceQuery()+. - -Below are a couple of examples that show some of the possibilities of the query API for history. Full description of the possibilities can be found in the link:$$http://www.flowable.org/docs/javadocs/index.html$$[javadocs], in the +org.flowable.engine.history+ package. - -[[historyQueryProcessInstance]] - - -==== HistoricProcessInstanceQuery - -Get 10 +HistoricProcessInstances+ that are finished and which took the most time to complete (the longest duration) of all finished processes with definition 'XXX'. - -[source,java,linenums] ----- -historyService.createHistoricProcessInstanceQuery() - .finished() - .processDefinitionId("XXX") - .orderByProcessInstanceDuration().desc() - .listPage(0, 10); ----- - - -[[historyQueryVariableInstance]] - - -==== HistoricVariableInstanceQuery - -Get all +HistoricVariableInstances+ from a finished process instance with id 'xxx' ordered by variable name. - -[source,java,linenums] ----- -historyService.createHistoricVariableInstanceQuery() - .processInstanceId("XXX") - .orderByVariableName.desc() - .list(); ----- - -[[historyQueryActivityInstance]] - - -==== HistoricActivityInstanceQuery - -Get the last +HistoricActivityInstance+ of type 'serviceTask' that has been finished in any process that uses the processDefinition with id XXX. - -[source,java,linenums] ----- -historyService.createHistoricActivityInstanceQuery() - .activityType("serviceTask") - .processDefinitionId("XXX") - .finished() - .orderByHistoricActivityInstanceEndTime().desc() - .listPage(0, 1); ----- - -[[historyQueryDetail]] - - -==== HistoricDetailQuery - -The next example, gets all variable-updates that have been done in process with id 123. Only ++HistoricVariableUpdate++s will be returned by this query. Note that it's possible that a certain variable name has multiple +HistoricVariableUpdate+ entries, for each time the variable was updated in the process. You can use +orderByTime+ (the time the variable update was done) or +orderByVariableRevision+ (revision of runtime variable at the time of updating) to find out in what order they occurred. - -[source,java,linenums] ----- -historyService.createHistoricDetailQuery() - .variableUpdates() - .processInstanceId("123") - .orderByVariableName().asc() - .list() ----- - -This example gets all <> that were submitted in any task or when starting the process with id "123". Only ++HistoricFormProperties++s will be returned by this query. - -[source,java,linenums] ----- -historyService.createHistoricDetailQuery() - .formProperties() - .processInstanceId("123") - .orderByVariableName().asc() - .list() ----- - - -The last example gets all variable updates that were performed on the task with id "123". This returns all +HistoricVariableUpdates+ for variables that were set on the task (task local variables), and NOT on the process instance. - -[source,java,linenums] ----- -historyService.createHistoricDetailQuery() - .variableUpdates() - .taskId("123") - .orderByVariableName().asc() - .list() ----- - -Task local variables can be set using the +TaskService+ or on a +DelegateTask+, inside ++TaskListener++: - -[source,java,linenums] ----- -taskService.setVariableLocal("123", "myVariable", "Variable value"); ----- - -[source,java,linenums] ----- -public void notify(DelegateTask delegateTask) { - delegateTask.setVariableLocal("myVariable", "Variable value"); -} ----- - -[[historyQueryTaskInstance]] - - -==== HistoricTaskInstanceQuery - -Get 10 ++HistoricTaskInstance++s that are finished and which took the most time to complete (the longest duration) of all tasks. - -[source,java,linenums] ----- -historyService.createHistoricTaskInstanceQuery() - .finished() - .orderByHistoricTaskInstanceDuration().desc() - .listPage(0, 10); ----- - -Get ++HistoricTaskInstance++s that are deleted with a delete reason that contains "invalid", which were last assigned to user 'kermit'. - -[source,java,linenums] ----- -historyService.createHistoricTaskInstanceQuery() - .finished() - .taskDeleteReasonLike("%invalid%") - .taskAssignee("kermit") - .listPage(0, 10); ----- - - -[[historyConfig]] - -=== History configuration - -The history level can be configured programmatically, using the enum org.flowable.engine.impl.history.HistoryLevel (or _HISTORY_ constants defined on +ProcessEngineConfiguration+ for versions prior to 5.11): - -[source,java,linenums] ----- -ProcessEngine processEngine = ProcessEngineConfiguration - .createProcessEngineConfigurationFromResourceDefault() - .setHistory(HistoryLevel.AUDIT.getKey()) - .buildProcessEngine(); ----- - -The level can also be configured in flowable.cfg.xml or in a spring-context: - -[source,xml,linenums] ----- - - - ... - ----- - -Following history levels can be configured: - -* ++none++: skips all history archiving. This is the most performant for runtime process execution, but no historical information will be available. -* ++activity++: archives all process instances and activity instances. At the end of the process instance, the latest values of the top level process instance variables will be copied to historic variable instances. No details will be archived. -* ++audit++: This is the default. It archives all process instances, activity instances, keeps variable values continuously in sync and all form properties that are submitted so that all user interaction through forms is traceable and can be audited. -* ++full++: This is the highest level of history archiving and hence the slowest. This level stores all information as in the +audit+ level plus all other possible details, mostly this are process variable updates. - -*In older releases, the history level was stored in the database (table +$$ACT_GE_PROPERTY$$+, property with name ++historyLevel++). Starting from 5.11, this value is not used anymore and is ignored/deleted from the database. The history can now be changed between 2 boots of the engine, without an exception being thrown in case the level changed from the previous engine-boot.* - -[[asyncHistoryConfig]] - -=== Async History configuration - -[Experimental] Async History has been introduced with Flowable 6.1.0 and allows historic data to be persisted asynchronously using a history job executor. - - -[source,xml,linenums] ----- - - - - - ... - ----- - -With the ++asyncHistoryExecutorActivate++ property, the history job executor can be started automatically when booting the Process Engine. This would be only set to false for test cases (or if Async History is not enabled of course). -The ++asyncHistoryExecutorNumberOfRetries++ property configures the number of retries for an Async History job. This property is a bit different than that for a normal async job, because a history job may need more cycles before it can be handled successfully. For example, a historic task first has to be created in the ACT_HI_TASK_ table before the assignee can be updated by another history job. The default value for this property is set to 10 in the Process Engine configuration. When the number of retries has been reached, the history job will be ignored (and not written to a deadletter job table). - -In addition to these properties, the ++asyncHistoryExecutor++ property can be used to configure an AsyncExecutor in a similar way that you can do for the normal async job executor. - -When the history data is not to be persisted in the default history tables, but for example, is required in a NoSQL database (such as Elasticsearch, MongoDb, Cassandra and so on), or something completely different is to be done with it, the handler that is responsible for handling the job can be overridden: - -* Using the ++historyJobHandlers++ property, which is a map of all the custom history job handlers -* Or, configure the ++customHistoryJobHandlers++ list with all instances will be added to the ++historyJobHandlers++ map at boot time. - -Alternatively, it is also possible to use a Message Queue and configure the engine in such a way that a message will be sent when a new history job is available. This way, the historical data can be processed on different servers to where the engines are run. It's also possible to configure the engine and Message Queue using JTA (when using JMS) and not store the historical data in a job, but send it all data to a Message Queue that participates in a global transaction. - -See link:$$https://github.com/flowable/flowable-examples/tree/master/async-history$$[the Flowable Async History Examples] for various examples on how to configure the Async History, including the default way, using a JMS queue, using JTA or using a Message Queue and a Spring Boot application that acts as a message listener. - - -[[historyFormAuditPurposes]] - - -=== History for audit purposes - -When <> at least +audit+ level for configuration. Then all properties submitted through methods +FormService.submitStartFormData(String processDefinitionId, Map properties)+ and +FormService.submitTaskFormData(String taskId, Map properties)+ are recorded. - -Form properties can be retrieved with the query API like this: - -[source,java,linenums] ----- -historyService - .createHistoricDetailQuery() - .formProperties() - ... - .list(); ----- - -In that case only historic details of type +HistoricFormProperty+ are returned. - - -If you've set the authenticated user before calling the submit methods with +IdentityService.setAuthenticatedUserId(String)+ then that authenticated user who submitted the form will be accessible in the history as well with +HistoricProcessInstance.getStartUserId()+ for start forms and +HistoricActivityInstance.getAssignee()+ for task forms. diff --git a/docs/userguide/src/zh_CN/bpmn/ch11-IDM.adoc b/docs/userguide/src/zh_CN/bpmn/ch11-IDM.adoc deleted file mode 100755 index 6d8d5b80ffa..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch11-IDM.adoc +++ /dev/null @@ -1,89 +0,0 @@ -[[IDM]] - -== 身份管理 - -从Flowable V6起,身份管理(IDM IDentity Management)组件从Flowable引擎模块中抽出,并将其逻辑移至几个不同的模块:flowable-idm-api、flowable-idm-engine、flowable-idm-spring及flowable-idm-engine-configurator。分离IDM主要是因为它并不是Flowable引擎的核心,并且在很多将Flowable引擎嵌入应用的用例中,并不使用或需要这部分身份管理逻辑。 - -默认情况下,IDM引擎在Flowable引擎启动时初始化并启动。这样身份管理逻辑在Flowable V5中也可以使用。IDM引擎管理自己的数据库表结构及下列实体: - -* User与UserEntity,用户信息。 -* Group与GroupEntity,组信息。 -* MembershipEntity,组中的用户成员。 -* Privilege与PrivilegeEntity,权限定义(例如在Flowable Modeler与Flowable Task应用中,用于控制应用界面的访问)。 -* PrivilegeMappingEntity,将用户及/或组与权限关联。 -* Token与TokenEntity,应用界面程序使用的认证令牌。 - -历史与当前进行中的流程实例都在数据库中保存历史实体,因此可以选择直接查询历史表,以减少对运行时流程实例数据的访问,并提高运行时执行的性能。 - -[[_idm_engine_configuration]] - -=== 配置IDM引擎 - -默认情况下,IDM引擎使用++org.flowable.engine.impl.cfg.IdmEngineConfigurator++启动。这个配置器使用Flowable流程引擎配置中相同的数据源配置。这样使用身份管理就不需要进行额外的配置,就像在Flowable V5中一样。 - -如果Flowable引擎不需要身份管理,可以在流程引擎配置中禁用IDM引擎。 - -[source,xml,linenums] ----- - - - ... - ----- - -这意味着不能使用用户与组进行查询,也不能在任务查询中,按用户查询其所在的候选组。 - -默认情况下,用户的密码以明文保存在IDM数据库表中。可以在流程引擎配置中定义一个加密算法,以确保密码加密。 - -[source,xml,linenums] ----- - - - - - - - - - ... - ----- - -这里使用的是ShaPasswordEncoder,但也可以使用其他的加密算法,如org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder,不使用Spring的话也可以改用org.flowable.idm.engine.impl.authentication.ApacheDigester。 - -也可以覆盖默认的IDM引擎配置器,使用自定义方式初始化IDM引擎。LDAPConfigurator的实现就是一个很好的例子。它覆盖了默认的IDM引擎,使用LDAP服务代替了默认的IDM数据库表。流程引擎配置的++idmProcessEngineConfigurator++参数用于设置自定义的配置器,如LDAPConfigurator - -[source,xml,linenums] ----- - - ... - - - - - - - - - - - - - - - - - - - - - - - - - - - - ----- diff --git a/docs/userguide/src/zh_CN/bpmn/ch12-Designer.adoc b/docs/userguide/src/zh_CN/bpmn/ch12-Designer.adoc deleted file mode 100755 index a2681451f87..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch12-Designer.adoc +++ /dev/null @@ -1,735 +0,0 @@ -[[flowableDesigner]] - -== Eclipse Designer - -Flowable提供了名为Flowable Eclipse Designer的Eclipse插件,可以用于图形化地建模、测试与部署BPMN 2.0流程。 - - -[[eclipseDesignerInstallation]] - - -=== 安装 - -下面的安装指导在link:$$http://www.eclipse.org/downloads/$$[Eclipse Mars与Neon]下进行了验证。 - -选择**Help -> Install New Software**。在下图面板中,点击__Add__按钮,并填写下列字段: - -* **Name:** Flowable BPMN 2.0 designer -* **Location:** http://www.flowable.org/designer/update/ - -image::images/designer.add.update.site.png[align="center"] - -确保**已选中"Contact all updates sites.."**复选框。这样Eclipse就可以下载需要的所有插件。 - -[[eclipseDesignerEditorFeatures]] - - -=== Flowable Designer编辑器功能 - -* 创建Flowable项目与流程图(diagram)。 - -image::images/designer.create.flowable.project.png[align="center"] - -* Flowable Designer在创建新的Flowable流程图时,会创建一个.bpmn文件。当使用Flowable Diagram Editor(Flowable流程图编辑器)视图打开时,将提供图形化的模型画布与画板。这个文件也可以使用XML编辑器打开,将显示流程定义的BPMN 2.0 XML元素。也就是说,Flowable Designer只用一个文件,既是流程图,也是BPMN 2.0 XML。请注意在早期版本中,不支持使用.bpmn扩展名作为流程定义的部署包。可以使用Flowable Designer的"create deployment artifacts(创建部署包)"功能,生成一个BAR文件,其中有一个.bpmn20.xml文件,包含.bpmn文件的内容。也可以方便的自己重命名。请注意,也可以使用Flowable Diagram Editor打开.bpmn20.xml文件。 - -image::images/designer.bpmn.file.png[align="center"] - - -* BPMN 2.0 XML文件导入Flowable Designer会自动显示流程图。只需要将BPMN 2.0 XML文件复制到项目中,并使用Flowable Diagram Editor视图打开它。Flowable Designer使用文件中的BPMN DI信息来创建流程图。如果BPMN 2.0 XML文件中没有BPMN DI信息,会使用Flowable BPMN自动布局模块,创建流程图。 - -image::images/designer.open.importedfile.png[align="center", width="600"] - -* 可以使用Flowable Designer创建BAR文件或JAR文件进行部署。在包浏览器中的Flowable项目上点击右键,在弹出菜单的下方选择__Create deployment artifacts(创建部署包)__选项。要了解关于Designer部署功能的更多信息,请查看<>章节。 - -image::images/designer.create.deployment.png[align="center", width="500"] - -* 生成单元测试(在包浏览器中的BPMN 2.0 XML文件上点击右键,选择__generate unit test 生成单元测试__)。将创建一个单元测试及运行在嵌入式H2数据库上的Flowable配置。这样就可以运行单元测试,来测试你的流程定义。 - -image::images/designer.unittest.generate.png[align="center", width="600"] - -* Flowable项目可以生成为Maven项目。要配置依赖,需要运行__mvn eclipse:eclipse__。请注意在流程设计时不需要Maven依赖。只在运行单元测试时才需要依赖。 - -image::images/designer.project.maven.png[align="center", width="500"] - - -[[eclipseDesignerBPMNFeatures]] - - -=== Flowable Designer BPMN功能 - -* 支持空启动事件,错误启动事件,定时器启动事件,空结束事件,错误结束事件,顺序流,并行网关,排他网关,包容网关,事件网关,嵌入式子流程,事件子流程,调用活动,泳池,泳道,脚本任务,用户任务,服务任务,邮件任务,手动任务,业务规则任务,接收任务,定时器边界事件,错误边界事件,信号边界事件,定时器捕获事件,信号捕获事件,信号抛出事件,空抛出事件,以及四个Flowable特殊元素(用户,脚本,邮件任务与启动事件)。 - - -image::images/designer.model.process.png[align="center"] - -* 可以在元素上悬停并选择新的任务类型,快速改变任务的类型。 - -image::images/designer.model.quick.change.png[align="center"] - -* 可以在元素上悬停并选择新的元素类型,快速添加新的元素。 - -image::images/designer.model.quick.new.png[align="center"] - -* Java服务任务支持Java类,表达式或代理表达式配置。另外也可以配置字段扩展。 - -image::images/designer.servicetask.property.png[align="center"] - -* 支持泳池与泳道。但由于Flowable会将不同的泳池认作不同的流程定义,因此最好只使用一个泳池。如果使用多个泳池,要小心不要在泳池间画顺序流,否则会在Flowable引擎中部署流程时发生错误。可以在一个泳池中添加任意多的泳道。 - -image::images/designer.model.poolandlanes.png[align="center"] - -* 可以通过填写name参数,为顺序流添加标签。可以决定放置标签的位置,位置将保存为BPMN 2.0 XML DI信息的一部分。 - -image::images/designer.model.labels.png[align="center"] - -* 支持事件子流程。 - -image::images/designer.model.eventsubprocess.png[align="center"] - -* 支持展开嵌入式子流程。也可以在一个嵌入式子流程中加入另一个嵌入式子流程。 - -image::images/designer.embeddedprocess.canvas.png[align="center"] - -* 支持在任务与嵌入式子流程上的定时器边界事件。然而,在Flowable Designer中,在用户任务或嵌入式子流程上使用定时器边界事件最合理。 - -image::images/designer.timerboundary.canvas.png[align="center"] - -* 支持额外的Flowable扩展,例如邮件任务,用户任务的候选人配置,或脚本任务配置。 - -image::images/designer.mailtask.property.png[align="center"] - -* 支持Flowable执行与任务监听器。也可以为执行监听器添加字段扩展。 - -image::images/designer.listener.configuration.png[align="center"] - -* 支持在顺序流上添加条件。 - -image::images/designer.sequence.condition.png[align="center"] - - -[[eclipseDesignerDeployment]] - - -=== Flowable Designer部署功能 - -在Flowable引擎上部署流程定义与任务表单并不困难。只需要提供一个包含有流程定义BPMN 2.0 XML文件的BAR文件,与可选的用于在Flowable应用中查看的任务表单和流程图片。在Flowable Designer中,创建BAR文件十分简单。在完成流程实现后,只要在包浏览器中的Flowable项目上点击右键,在弹出菜单下方选择**Create deployment artifacts(创建部署包)**选项。 - -image::images/designer.create.deployment.png[align="center", width="600"] - -然后就会创建一个部署目录,包含BAR文件与可能的JAR文件。其中JAR文件包含Flowable项目中的Java类。 - -image::images/designer.deployment.dir.png[align="center"] - -这样就可以在Flowable Admin应用的部署页签中,将这个文件上传至Flowable引擎。 - -如果项目包含Java类,部署时要多做一些工作。在这种情况下,Flowable Designer的**Create deployment artifacts(创建部署包)**操作也会创建包含编译后类的JAR文件。这个JAR文件必须部署在Flowable Tomcat(或其它容器)安装目录的flowable-XXX/WEB-INF/lib目录下。这样Flowable引擎的classpath就会添加这些类。 - - -[[eclipseDesignerExtending]] - - -=== 扩展Flowable Designer - -可以扩展Flowable Designer提供的默认功能。这段文档介绍了可以使用哪些扩展,如何使用,并提供了一些例子。在建模业务流程时,如果默认功能不能满足需要,需要额外的功能,或有领域专门需求的时候,扩展Flowable Designer就很有用。扩展Flowable Designer分为两个不同领域,扩展画板与扩展输出格式。两者都需要专门的方法,与不同的技术知识。 - - -[NOTE] -==== -扩展Flowable Designer需要专业知识,更确切地说,Java编程的知识。取决于你想要创建的扩展类型,你可能需要熟悉Maven,Eclipse,OSGi,Eclipse扩展与SWT。 -==== - - -[[eclipseDesignerCustomizingPalette]] - - -==== 自定义画板 - -可以自定义为用户建模流程提供的画板。画板是形状的集合,显示在画布的右侧,可以将形状拖放至画布中的流程图上。在默认画板中可以看到,默认形状进行了分组(被称为“抽屉 drawer”),如事件,网关,等等。Flowable Designer提供了两种选择,用于自定义画板中的抽屉与形状: - -* 将你自己的形状/节点添加到已有或新建的抽屉 -* 禁用Flowable Designer提供的部分或全部BPMN 2.0默认形状,除了连线与选择工具 - -要自定义画板,需要创建一个JAR文件,并将其加入每一个Flowable Designer的安装目录(后面介绍<>)。这个JAR文件叫做__扩展(extension)__。通过编写扩展中包含的类,就能让Flowable Designer知道需要自定义的形状。为此需要实现特定的接口。Flowable提供了一个集成类库,包含这些接口以及用于扩展的基类。 - -可以在下列地方找到代码示例:Flowable link:$$https://github.com/flowable/flowable-designer/tree/master/examples$$[源码],++flowable-designer++仓库下的++examples/money-tasks++目录。 - - -[NOTE] -==== -可以使用你喜欢的任何工具设置项目,并使用你选择的构建工具构建JAR。在下面的介绍中,假设使用Eclipse Mars或Neon,并使用Maven(3.x)作为构建工具。但任何设置都可以创建相同的结果。 -==== - -[[_extension_setup_eclipse_maven]] -===== 设置扩展 (Eclipse/Maven) - -下载并解压缩link:$$http://www.eclipse.org/downloads$$[Eclipse](应该可以使用最新版本),与link:$$http://maven.apache.org/download.html$$[Apache Maven]近期的版本(3.x)。如果使用2.x版本的Maven,可能会在构建项目时遇到错误,因此请确保版本是最新的。我们假设你已经熟悉Eclipse中的基本功能以及Java编辑器。可以使用Eclipse的Maven功能,或直接从命令行运行Maven命令。 - -在Eclipse中创建一个新项目。可以是通用类型项目。在项目的根路径创建一个++pom.xml++文件,以包含Maven项目配置。同时创建++src/main/java++与++src/main/resources++目录,这是Maven约定的Java源文件与资源文件目录。打开++pom.xml++文件并添加下列行: - - -[source,xml,linenums] ----- - - - 4.0.0 - - org.acme - money-tasks - 1.0.0 - jar - Acme Corporation Money Tasks -... - ----- - - -可以看到,这只是一个基础的pom.xml文件,为项目定义了一个++groupId++、++artifactId++与++version++。我们会创建一个定制项,包含一个money业务要用的自定义节点。 - -在++pom.xml++文件中为项目添加这些集成库依赖: - - -[source,xml,linenums] ----- - - - org.flowable.designer - org.flowable.designer.integration - 5.22.0 - compile - - -... - - - Flowable - - ----- - - -最后,在++pom.xml++文件中,添加++maven-compiler-plugin++配置,设置Java源码级别为1.5以上(参见下面的代码片段)。要使用注解需要这个配置。也可以为Maven包含用于生成JAR的++MANIFEST.MF++文件。这不是必须的,但可以在这个manifest中使用特定参数,为你的扩展提供名字(这个名字可以在设计器的特定位置显示,主要用于在设计器中有多个扩展时使用)。如果想要这么做,在++pom.xml++中添加下列代码片段: - -[source,xml,linenums] ----- - - - - maven-compiler-plugin - - 1.8 - 1.8 - true - true - true - - - - org.apache.maven.plugins - maven-jar-plugin - 2.3.2 - - - true - - false - true - - - Acme Money - - - - - - ----- - - -扩展的名字使用++FlowableDesigner-Extension-Name++参数描述。现在只剩下让Eclipse按照++pom.xml++的指导设置项目。因此打开命令行,并转到Eclipse工作空间中你项目的根目录。然后执行下列Maven命令: - ----- -mvn eclipse:eclipse ----- - -等待构建完成。刷新项目(使用项目上下文菜单(右键点击),并选择++Refresh 刷新++)。现在Eclipse项目中应该已经建立了++src/main/java++与++src/main/resources++源码目录。 - - -[NOTE] -==== -当然也可以使用link:$$http://www.eclipse.org/m2e$$[m2eclipse]插件,并简单地在项目的上下文菜单(右键点击)中启用Maven依赖管理。然后在项目的上下文菜单中选择++Maven++ > ++Update project configuration(更新项目配置)++。这也将配置源代码目录。 -==== - - -这就完成了配置。现在可以开始为Flowable Designer创建自定义项了! - -[[eclipseDesignerApplyingExtension]] - - -===== 在Flowable Designer中应用你的扩展 - -你也许想知道如何将你的扩展加入Flowable Designer,以便应用你的自定义项。需要这些步骤: - -* 创建扩展JAR(例如,使用Maven构建时,在项目中运行mvn install)后,需要将扩展传递至Flowable Designer安装的计算机; -* 将扩展存储在硬盘上,方便记忆的位置。__请注意:__必须保存在Flowable Designer的Eclipse工作空间之外——将扩展保存在工作空间内,会导致弹出错误消息弹框,扩展将不可用; -* 启动Flowable Designer,从菜单中,选择++Window++ > ++Preferences++,或++Eclipse++ > ++Preferences++ -* 在Preferences界面,键入++user++作为关键字。将可以看到在Eclipse中++Java++段落内,++User Libraries++的选项。 - -image::images/designer.preferences.userlibraries.png[align="center", width="250"] - - -* 选择++User Libraries++选项,将在右侧显示树形界面,可以添加库。应该可以看到一个默认组,可以用于添加Flowable Designer的扩展(根据Eclipse安装不同,也可能看到几个其他的)。 - -image::images/designer.preferences.userlibraries.flowable.empty.png[align="center", width="600"] - - -* 选择++Flowable Designer Extensions++组,并点击++Add JARs...++或++Add External JARs...++按钮。跳转至存储扩展的目录,并选择希望添加的扩展文件。完成后,配置界面会将扩展作为++Flowable Designer Extensions++组的成员进行显示,像下面这样。 - -image::images/designer.preferences.userlibraries.flowable.moneytasks.png[align="center", width="600"] - - -* 点击++OK++按钮保存并关闭配置对话框。++Flowable Designer Extensions++会自动添加至你创建的新Flowable项目。可以在导航条或包管理器的项目树下的用户库条目中看到。如果工作空间中已经有了Flowable项目,也可以看到组中显示了新扩展,像下面这样。 - -image::images/designer.userlibraries.project.png[align="center", width="400"] - - -打开的流程图将在其画板上显示新扩展的图形(或者禁用部分图形,取决于扩展中的配置)。如果已经打开了流程图,关闭并重新打开就能在画板上看到变化。 - -[[_adding_shapes_to_the_palette]] -===== 为画板添加图形 - -项目配置完后,可以很轻松的为画板添加图形。每个添加的图形都表现为JAR中的一个类。请注意这些类并不是Flowable引擎运行时会使用的类。在扩展中可以为每个图形描述Flowable Designer可用的参数。在这些图形中,也可以定义运行时特性,并将由引擎在流程实例到达该节点时使用。运行时特性可以使用任何Flowable对普通++ServiceTask++支持的选项。查看<>了解更多信息。 - -图形的类是简单的Java类,加上一些注解。这个类需要实现++CustomServiceTask++接口,但不应该直接实现这个接口,而应该扩展++AbstractCustomServiceTask++基类(目前必须直接扩展这个类,而不能在中间使用abstract类)。在这个类的Javadoc中,可以看到其默认提供的,与需要覆盖的方法介绍。覆盖可以实现很多功能,例如为画板及画布中的图形提供图标(两个可以不一样),或者指定你希望节点实现的基图形(活动,时间,网关)。 - - -[source,java,linenums] ----- -/** - * @author John Doe - * @version 1 - * @since 1.0.0 - */ -public class AcmeMoneyTask extends AbstractCustomServiceTask { -... -} ----- - - -需要实现++getName()++方法,来决定节点在画板上的名字。也可以将节点放在自己的抽屉中,并提供图标,只需要覆盖++AbstractCustomServiceTask++的对应方法就可以。如果希望提供图标,请确保放在JAR的++src/main/resources++包中,需要是16X16像素的JPEG或PNG格式图片。你要提供的路径是到这个目录的相对路径。 - -可以通过在类中添加成员,并使用++@Property++注解,来为形状添加参数。像这样: - -[source,java,linenums] ----- -@Property(type = PropertyType.TEXT, displayName = "Account Number") -@Help(displayHelpShort = "提供一个账户编码 Provide an account number", displayHelpLong = HELP_ACCOUNT_NUMBER_LONG) -private String accountNumber; ----- - -可以使用多种++PropertyType++值,在<>中详细描述。可以通过将required属性设置为true,将一个字段设为必填。如果用户没有填写这个字段,将会提示消息,背景也会变红。 - -如果想要调整类中多个参数在参数界面上的显示顺序,需要指定++@Property++注解的order属性。 - -可以看到有个++@Help++注解,它用于为用户提供一些填写字段的指导。也可以在类本身上使用++@Help++注解——这个信息将在显示给用户的参数表格最上面显示。 - -下面是++MoneyTask++详细介绍的列表。添加了一个备注字段,也可以看到节点包含了一个图标。 - - -[source,java,linenums] ----- -/** - * @author John Doe - * @version 1 - * @since 1.0.0 - */ -@Runtime(javaDelegateClass = "org.acme.runtime.AcmeMoneyJavaDelegation") -@Help(displayHelpShort = "创建一个新的账户 Creates a new account", displayHelpLong = - "使用给定的账户编码,创建一个新的账户 Creates a new account using the account number specified") -public class AcmeMoneyTask extends AbstractCustomServiceTask { - - private static final String HELP_ACCOUNT_NUMBER_LONG = - "提供一个可用作账户编码的编码。 Provide a number that is suitable as an account number."; - - @Property(type = PropertyType.TEXT, displayName = "Account Number", required = true) - @Help(displayHelpShort = "提供一个账户编码 Provide an account number", displayHelpLong = HELP_ACCOUNT_NUMBER_LONG) - private String accountNumber; - - @Property(type = PropertyType.MULTILINE_TEXT, displayName = "Comments") - @Help(displayHelpShort = "提供备注 Provide comments", displayHelpLong = - "可以为节点添加备注,以提供详细说明。 You can add comments to the node to provide a brief description.") - private String comments; - - @Override - public String contributeToPaletteDrawer() { - return "Acme Corporation"; - } - - @Override - public String getName() { - return "Money node"; - } - - @Override - public String getSmallIconPath() { - return "icons/coins.png"; - } -} ----- - - -如果使用这个图形扩展Flowable Designer,画板与相应的图形将像是这样: - -image::images/designer.palette.add.money.png[align="center", width="250"] - - -money任务的参数界面在下面显示。请注意++accountNumber++字段的必填信息。 - -image::images/designer.palette.add.money.properties.required.png[align="center"] - - -在创建流程图、填写参数字段时,用户可以使用静态文本,或者使用流程变量的表达式(如"This little piggy went to ${piggyLocation}")。一般来说,用户可以在text字段自由填写任何文本。如果你希望用户使用表达式,并(使用++@Runtime++)为++CustomServiceTask++添加运行时行为,请确保在代理类中使用++Expression++字段,以便表达式可以在运行时正确解析。可以在<>找到更多关于运行时行为的信息。 - - -字段的帮助信息由每个参数右侧的按钮提供。点击该按钮将弹出显示下列内容。 - -image::images/designer.palette.add.money.help.png[align="center"] - - -[[eclipseDesignerConfiguringRuntime]] - -====== 配置自定义服务任务的运行时执行 - -当设置好字段,并将扩展应用至Designer后,用户就可以在建模流程时,配置服务任务的这些参数。在大多数情况下,会希望在Flowable执行流程时,使用这些用户配置参数。要做到这一点,必须告诉Flowable,当流程到达你++CustomServiceTask++时,需要使用哪个类。 - -有一个特别的注解,++@Runtime++,用于指定++CustomServiceTask++的运行时特性。这里有些如何使用的例子: - - -[source,java,linenums] ----- -@Runtime(javaDelegateClass = "org.acme.runtime.AcmeMoneyJavaDelegation") ----- - -使用时,++CustomServiceTask++将会表现为流程建模BPMN中的一个普通的++ServiceTask++。Flowable提供了<>定义++ServiceTask++的运行时特性。因此,++@Runtime++可以使用Flowable提供的三个属性中的一个: - -* ++javaDelegateClass++在BPMN输出中映射为++flowable:class++。指定一个实现了++JavaDelegate++的类的全限定类名。 -* ++expression++在BPMN输出中映射为++flowable:expression++。指定一个需要执行的方法的表达式,例如一个Spring Bean中的方法。当使用这个选项时,__不应__在字段上指定任何++@Property++注解。下面有更详细的说明。 -* ++javaDelegateExpression++在BPMN输出中映射为++flowable:delegateExpression++。指定一个实现了++JavaDelegate++的类的表达式。 - -如果在类中为Flowable提供了可以注入的成员,就可以将用户的参数至注入到运行时类中。名字需要与++CustomServiceTask++的成员名一致。查看用户手册的<>了解更多信息。请注意从Designer的5.11.0版本开始,可以为动态字段值使用++Expression++接口。这意味着Flowable Designer中参数的值必须要是表达式,并且这个表达式将在之后注入++JavaDelegate++实现类的++Expression++参数中。 - - -[NOTE] -==== - -可以在++CustomServiceTask++的成员上使用++@Property++注解,但如果使用++@Runtime++的++expression++属性,则++@Property++注解将不会生效。原因是指定的表达式将被Flowable尝试解析为__方法__,而不是类。因此,不会有对类的注入。如果在++@Runtime++注解中使用++expression++,则注解为++@Property++的成员将被Designer忽略。Designer不会将它们渲染为节点参数页面的可编辑字段,也不会为这些参数在流程的BPMN中生成输出。 -==== - -[NOTE] -==== -请注意不应该在你的扩展JAR中包括运行时类,因为它与Flowable库是分离的。Flowable需要在运行时能够找到它们,因此需要将其放在Flowable引擎的classpath中。 -==== - -Designer代码树中的示例项目包含了配置++@Runtime++的不同选项的例子。可以从查看money-tasks项目开始。引用代理类的示例在money-delegates项目中。 - - -[[eclipseDesignerPropertyTypes]] - - -===== 参数类型 - -这个章节介绍了++CustomServiceTask++能够使用的参数类型,可以将类型设置为++PropertyType++的值。 - -====== PropertyType.TEXT - -创建如下所示的单行文本字段。可以是必填字段,并将验证消息作为提示信息显示。验证失败会将字段的背景变为浅红色。 - -image::images/designer.property.text.invalid.png[align="center"] - -====== PropertyType.MULTILINE_TEXT - -创建如下所示的多行文本字段(高度固定为80像素)。可以是必填字段,并将验证消息作为提示信息显示。验证失败会将字段的背景变为浅红色。 - -image::images/designer.property.multiline.text.invalid.png[align="center"] - - -====== PropertyType.PERIOD - -创建一个组合编辑框,可以使用转盘控件编辑每一个单位的数量,来指定一段时间长度,结果如下所示。可以是必填字段(含义是不能所有的值都是0,也就是至少有一个部分要有非零值),并将验证消息作为提示信息显示。验证失败会将整个字段的背景变为浅红色。字段的值保存为1y 2mo 3w 4d 5h 6m 7s格式的字符串,代表1年,2月,3周,4天,6分钟及7秒。即使有部分为0,也总是存储整个字符串。 - -image::images/designer.property.period.png[align="center"] - - -====== PropertyType.BOOLEAN_CHOICE - -创建一个单独的boolean复选框,或者开关选择。请注意可以在++Property++注解上指定++required++属性,但不会生效,不然用户就无法选择是否选中复选框。流程图中存储的值为java.lang.Boolean.toString(boolean),其结果为"true"或"false"。 - -image::images/designer.property.boolean.choice.png[align="center"] - -====== PropertyType.RADIO_CHOICE - -创建如下所示的一组单选按钮。选中任何一个单选按钮都自动排除任何其他的选择(也就是说,单选)。可以是必填字段,并将验证消息作为提示信息显示。验证失败会将组的背景变为浅红色。 - -这个参数类型需要注解的类成员同时使用++@PropertyItems++注解(例如如下所示)。可以使用这个额外的注解,以字符串数组的方式,指定条目的列表。需要为每一个条目添加两个数组项:第一个,用于显示的标签;第二个,用于存储的值。 - -[source,java,linenums] ----- -@Property(type = PropertyType.RADIO_CHOICE, displayName = "Withdrawl limit", required = true) -@Help(displayHelpShort = "最大每日提款限额 The maximum daily withdrawl amount ", - displayHelpLong = "选择从该账户中每日最大能提取的额度。 Choose the maximum daily amount that can be withdrawn from the account.") -@PropertyItems({ LIMIT_LOW_LABEL, LIMIT_LOW_VALUE, LIMIT_MEDIUM_LABEL, LIMIT_MEDIUM_VALUE, - LIMIT_HIGH_LABEL, LIMIT_HIGH_VALUE }) -private String withdrawlLimit; ----- - -image::images/designer.property.radio.choice.png[align="center"] - -image::images/designer.property.radio.choice.invalid.png[align="center"] - - -====== PropertyType.COMBOBOX_CHOICE - -创建如下所示的,带有固定选项的下拉框。可以是必填字段,并将验证消息作为提示信息显示。验证失败会将下拉框的背景变为浅红色。 - -这个参数类型需要注解的类成员同时使用++@PropertyItems++注解(例如如下所示)。可以使用这个额外的注解,以字符串数组的方式,指定条目的列表。需要为每一个条目添加两个数组项:第一个,用于显示的标签;第二个,用于存储的值。 - -[source,java,linenums] ----- -@Property(type = PropertyType.COMBOBOX_CHOICE, displayName = "Account type", required = true) -@Help(displayHelpShort = "账户的类型 The type of account", - displayHelpLong = "从选项列表中选择账户的类型 Choose a type of account from the list of options") -@PropertyItems({ ACCOUNT_TYPE_SAVINGS_LABEL, ACCOUNT_TYPE_SAVINGS_VALUE, ACCOUNT_TYPE_JUNIOR_LABEL, - ACCOUNT_TYPE_JUNIOR_VALUE, ACCOUNT_TYPE_JOINT_LABEL, ACCOUNT_TYPE_JOINT_VALUE, - ACCOUNT_TYPE_TRANSACTIONAL_LABEL, ACCOUNT_TYPE_TRANSACTIONAL_VALUE, ACCOUNT_TYPE_STUDENT_LABEL, - ACCOUNT_TYPE_STUDENT_VALUE, ACCOUNT_TYPE_SENIOR_LABEL, ACCOUNT_TYPE_SENIOR_VALUE }) -private String accountType; ----- - -image::images/designer.property.combobox.choice.png[align="center"] - -image::images/designer.property.combobox.choice.invalid.png[align="center"] - - -====== PropertyType.DATE_PICKER - -创建如下所示的日期选择控件。可以是必填字段,并将验证消息作为提示信息显示(请注意,这个控件会自动填入当前系统时间,因此值很难为空)。验证失败会将控件的背景变为浅红色。 - -这个参数类型需要注解的类成员同时使用++@DatePickerProperty++注解(例如如下所示)。可以使用这个额外的注解,指定在流程图中存储日期时使用的日期格式,以及要用于显示的日期选择类型。这些属性都是可选的,当没有指定时会使用默认值(++DatePickerProperty++注解的静态变量)。++dateTimePattern++属性应该使用++SimpleDateFormat++类支持的格式。当使用++swtStyle++属性时,应该指定++SWT++的++DateTime++控件支持的整形值,因为将使用这个控件渲染这个类型的参数。 - -[source,java,linenums] ----- -@Property(type = PropertyType.DATE_PICKER, displayName = "Expiry date", required = true) -@Help(displayHelpShort = "账户过期的日期 The date the account expires.", - displayHelpLong = "选择一个日期,如果账户未在该日期前延期,则将过期。Choose the date when the account will expire if not extended before the date.") -@DatePickerProperty(dateTimePattern = "MM-dd-yyyy", swtStyle = 32) -private String expiryDate; ----- - -image::images/designer.property.date.picker.png[align="center"] - - - -====== PropertyType.DATA_GRID - -创建一个如下所示的数据表格控件。数据表格可以让用户输入任意行数据,并为每一行输入固定列数的值(每一组行列的组合代表一个单元格)。用户可以添加与删除行。 - -这个参数类型需要注解的类成员同时使用++@DataGridProperty++注解(例如如下所示)。可以使用这个额外的注解,指定数据表格的细节属性。需要用++itemClass++属性引用另一个类,来决定表格中有哪些列。Flowable Designer期望其成员类型为++List++。按照约定,可以将++itemClass++属性的类用作其泛型类型。如果,例如,在表格中编辑一个杂货清单,用++GroceryListItem++类定义表格的列。在++CustomServiceTask++中,可以这样引用它: - -[source,java,linenums] ----- -@Property(type = PropertyType.DATA_GRID, displayName = "Grocery List") -@DataGridProperty(itemClass = GroceryListItem.class) -private List groceryList; ----- - - -与++CustomServiceTask++一样,"itemClass"可以使用相同的注解指定字段类型(除了数据表格)。目前支持++TEXT++,+$$MULTILINE_TEXT$$+ 与++PERIOD++。你会注意到不论其++PropertyType++是什么,表格都会为每个字段创建一个单行文本控件。这是为了表格保持整洁与可读。如果考虑下++PERIOD++这种++PropertyType++的显示模式,就可以想象出它绝不适合在表格的单元格中显示。对于 +$$MULTILINE_TEXT$$+ 与++PERIOD++,会为每个字段添加双击机制,并会为该++PropertyType++弹出更大的编辑器。数值将在用户点击OK后存储至字段,因此可以在表格中显示。 - -必选属性使用与普通++TEXT++字段类似的方式处理,当任何字段失去焦点时,会验证整个表格。验证失败的单元格,背景色将变为浅红色。 - -默认情况下,这个组件允许用户添加行,但不能决定行的顺序。如果希望允许排序,需要将++orderable++属性设置为true,这将在每一行末尾启用按钮,以将该行在表格内上移或下移。 - -[NOTE] -==== -目前,这个参数类型不能正确注入运行时类。 -==== - -image::images/designer.property.datagrid.png[align="center"] - - -[[_disabling_default_shapes_in_the_palette]] -===== 在画板中禁用默认图形 - -这种自定义需要在你的扩展中引入一个实现了++DefaultPaletteCustomizer++接口的类。不应该直接实现这个接口,而要扩展++AbstractDefaultPaletteCustomizer++基类。目前,这个类不提供任何功能,但++DefaultPaletteCustomizer++未来的版本中会提供更多功能,这样基类将提供更多合理的默认值。因此最好使用它的子类,这样你的扩展将可以兼容未来的版本。 - -扩展++AbstractDefaultPaletteCustomizer++需要实现一个方法,++disablePaletteEntries()++,并必须返回一个++PaletteEntry++值的list。请注意如果从默认集合中移除图形,导致某个抽屉中没有图形,则该抽屉也会被移除。如果需要禁用所有的默认图形,只需要在结果中添加++PaletteEntry.ALL++。作为例子,下面的代码禁用了画板中的手动任务和脚本任务图形。 - -[source,java,linenums] ----- -public class MyPaletteCustomizer extends AbstractDefaultPaletteCustomizer { - - @Override - public List disablePaletteEntries() { - List result = new ArrayList(); - result.add(PaletteEntry.MANUAL_TASK); - result.add(PaletteEntry.SCRIPT_TASK); - return result; - } - -} ----- - - -应用这个扩展的结果在下图显示。可以看到,在++Tasks++抽屉中不再显示手动任务与脚本任务图形。 - -image::images/designer.palette.disable.manual.and.script.png[align="center"] - - -要禁用所有默认图形,需要使用类似下面的代码。 - -[source,java,linenums] ----- -public class MyPaletteCustomizer extends AbstractDefaultPaletteCustomizer { - - @Override - public List disablePaletteEntries() { - List result = new ArrayList(); - result.add(PaletteEntry.ALL); - return result; - } - -} ----- - - -结果像是这样(请注意画板中不再显示默认图形所在的抽屉): - -image::images/designer.palette.disable.all.png[align="center"] - -[[_validating_diagrams_and_exporting_to_custom_output_formats]] -==== 验证流程图与输出为自定义格式 - -除了自定义画板,也可以为Flowable Designer创建扩展,来进行流程图验证,以及将流程图的信息保存为Eclipse工作空间中的自定义资源。可以通过内建的扩展点实现 ,这个章节将介绍如何做。 - -[NOTE] -==== -保存功能最近正在重构。我们仍在开发验证功能。下面的文档记录的是旧的情况,并将在新功能可用后更新。 -==== - - -Flowable Designer可以编写用于验证流程图的扩展。默认情况已经可以在工具中验证BPMN结构,但你也可以添加自己的,如果希望验证额外的条目,例如建模约定,或者++CustomServiceTask++中的参数值。这些扩展被称作++Process Validators++。 - -也可以自定义配置,在Flowable Designer保存流程图时,发布为其它格式。这些扩展被称作++Export Marshallers++,将在每次用户进行保存操作时,由Flowable Designer自动调用。这个行为可以在Eclipse配置对话框中,为每一种扩展检测出的格式,分别启用或禁用。Designer会根据用户的配置,确保在保存流程图时,调用你的++ExportMarshaller++。 - -通常,会想要将++ProcessValidator++与++ExportMarshaller++一起使用。例如有一些++CustomServiceTask++,带有一些希望在流程中使用的参数。然而,在生成流程前,希望验证其中一些值。联合使用++ProcessValidator++与++ExportMarshaller++是最佳的方式,Flowable Designer也允许你无缝拼接扩展。 - -要创建一个++ProcessValidator++或++ExportMarshaller++,需要创建与扩展画板不同的扩展类型。原因很简单:你的代码会需访问比集成库中提供的更多的API。特别是,会需要使用Eclipse的类。因此从一开始,就需要创建一个Eclipse插件(可以使用Eclipse的PDE支持完成),并将其打包为自定义Eclipse产品或特性。解释开发Eclipse插件的所有细节,已经不是本用户手册的范畴,因此下面的介绍仅限于扩展Flowable Designer的功能。 - -扩展包需要依赖下列库: - -* org.eclipse.core.runtime -* org.eclipse.core.resources -* org.flowable.designer.eclipse -* org.flowable.designer.libs -* org.flowable.designer.util - -可选的,如果希望在扩展中使用,可以通过Designer使用org.apache.commons.lang包。 - - -++ProcessValidator++与++ExportMarshaller++都是通过扩展基类创建的。这些基类从其父类++AbstractDiagramWorker++继承了一些有用的方法。使用这些方法,可以创建在Eclipse问题视图中显示的提示信息,警告,错误标记,以便用户了解错误与重要的信息。可以以++Resources++与++InputStreams++的格式获取流程图的信息,这些信息由++DiagramWorkerContext++提供,在++AbstractDiagramWorker++中可用。 - -不论是++ProcessValidator++还是++ExportMarshaller++中,做任何事情前最好调用++clearMarkers()++;这将清除任何已有的标记(标记自动连接至操作,清除一个操作的标记不会影响其他操作的标记)。例如: - - -[source,java,linenums] ----- -// 首先清除流程图的标记 Clear markers for this diagram first -clearMarkersForDiagram(); ----- - -也需要使用(++DiagramWorkerContext++中)提供的进度监控,将你的进度报告给用户,因为验证与保存操作可能花费很多时间,而用户只能等待。报告进度需要了解如何使用Eclipse的功能。查看link:$$http://www.eclipse.org/articles/Article-Progress-Monitors/article.html$$[这篇文章]了解详细概念与用法。 - -[[_creating_a_processvalidator_extension]] -===== 创建ProcessValidator扩展 - -在你的++plugin.xml++文件中,创建一个++org.flowable.designer.eclipse.extension.validation.ProcessValidator++扩展点的扩展。这个扩展点需要扩展++AbstractProcessValidator++类。 - -[source,xml,linenums] ----- - - - - - - - ----- - - -[source,java,linenums] ----- -public class AcmeProcessValidator extends AbstractProcessValidator { -} ----- - - -需要实现一些方法。最重要的是实现++getValidatorId()++,为验证器返回全局唯一ID。这将使你可以在++ExportMarshaller++中调用它,或者允许其他++ExportMarshaller++调用你的验证器。实现++getValidatorName()++,为验证器返回逻辑名字。这个名字将在对话框中显示给用户。++getFormatName()++可以返回这个验证器通常验证的流程图类型。 - -验证工作通过++validateDiagram()++方法实现。从这里开始,就是你自己的功能代码了。然而,通常你会想从获取流程中的所有节点开始,这样就可以迭代访问,收集、比较与验证数据了。这段代码展示了如何进行这些操作: - -[source,java,linenums] ----- -final EList contents = getResourceForDiagram(diagram).getContents(); -for (final EObject object : contents) { - if (object instanceof StartEvent ) { - // 验证启动事件 Perform some validations for StartEvents - } - // 其它节点类型与验证 Other node types and validations -} ----- - - -别忘了在验证过程中调用++addProblemToDiagram()++与/或++addWarningToDiagram()++等等。确保在结束时返回正确的boolean结果,以指示验证成功还是失败。可以由后续调用的++ExportMarshaller++判断下一步操作。 - -[[_creating_an_exportmarshaller_extension]] -===== 创建ExportMarshaller扩展 - -在你的++plugin.xml++文件中,创建一个++org.flowable.designer.eclipse.extension.ExportMarshaller++扩展点的扩展。这个扩展点需要扩展++AbstractExportMarshaller++类。这个基类提供了一些在保存为你自己的格式时有用的方法,但最重要的是提供了将资源保存至工作空间,以及调用验证器的功能。 - -Designer的示例目录下有一个示例实现。这个示例展示了如何使用基类中的方法完成基本操作,例如访问流程图的++InputStream++,使用其++BpmnModel++,以及将资源保存至工作空间。 - -[source,xml,linenums] ----- - - - - - - - ----- - - -[source,java,linenums] ----- -public class AcmeExportMarshaller extends AbstractExportMarshaller { -} ----- - -需要实现一些方法,例如++getMarshallerName()++与++getFormatName()++。这些方法用来为用户显示选项,并在流程对话框中显示信息,因此请确保你返回的描述反映了正在进行的操作。 - -大部分工作主要在++doMarshallDiagram()++方法中进行。 - -如果需要先进行一些验证,可以直接从保存器中调用验证器。从验证器可以获得boolean结果,就可以知道验证是否成功。在大多数情况下,在流程图验证失败时不会想要进行保存,但你也可以选择仍然继续,甚至在验证失败时创建不同的资源。 - -一旦获取了所有需要的数据,就可以调用++saveResource()++方法创建保存有数据的文件。在一个保存器中,可以调用++saveResource()++任意多次;因此一个验证器可以创建多于一个输出文件。 - -可以使用++AbstractDiagramWorker++类的++saveResource()++方法构建输出资源的文件名。可以使用一些有用的变量用于创建文件名,例如_original-filename__my-format-name.xml。这些变量在Javadocs中描述,通过++ExportMarshaller++接口定义。如果希望自行解析保存位置,也可以在一个字符串(例如一个路径)上使用++resolvePlaceholders()++。++getURIRelativeToDiagram()++会为你调用它。 - -应该使用提供的进度监控将你的进度报告给用户。link:$$http://www.eclipse.org/articles/Article-Progress-Monitors/article.html$$[这个文章]描述了如何做。 diff --git a/docs/userguide/src/zh_CN/bpmn/ch12-IDM.adoc b/docs/userguide/src/zh_CN/bpmn/ch12-IDM.adoc deleted file mode 100644 index ad7cc3c8984..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch12-IDM.adoc +++ /dev/null @@ -1,89 +0,0 @@ -[[IDM]] - -== Identity management -(开源版与商业版逻辑不一样 盘古BPM) -从Flowable V6开始,身份管理(IDM)组件已经从Flowable engine模块中提取出来,逻辑转移到几个单独的模块:Flowable IDM api、Flowable IDM engine、Flowable IDM spring和Flowable IDM engine configurator。分离IDM逻辑的主要原因是它不是Flowable引擎的核心,在很多情况下,当Flowable引擎嵌入到应用程序中时,标识逻辑不被使用或不需要。 -默认情况下,IDM引擎在可流动引擎启动时初始化并启动。这将导致在FlowableV5中执行和可用相同的标识逻辑。idm引擎管理自己的数据库架构和以下实体: -* User and UserEntity, the user information. -* Group and GroupEntity, the group information. -* MembershipEntity, the memberships of users in groups -* Privilege and PrivilegeEntity, a privilege definition (for example used for controlling access to the UI apps, such as the Flowable Modeler and Flowable Task app) -* PrivilegeMappingEntity, linking a user and/or group to a privilege -* Token and TokenEntity, an authentication token used by the UI apps - -由于数据库包含过去和正在进行的实例的历史实体,因此您可能需要考虑查询这些表,以尽量减少对运行时流程实例数据的访问,从而保持运行时执行的性能。 - -[[IDM engine configuration]] - - -=== IDM engine configuration - -默认情况下,可流动发动机以+org.flowable.idm.engine.configurator.IdmEngineConfigurator+. 此配置程序使用与可流动流程引擎配置相同的数据源配置。使用标识组件不需要额外的配置,因为它是在Flowable v5中配置的。 - -当流程引擎中不需要标识逻辑时,可以在流程引擎配置中禁用IDM引擎。 - -[source,xml,linenums] ----- - - - ... - ----- - -这意味着不能使用任何用户和组查询,并且不能为用户检索任务查询中的候选组。 - - -默认情况下,用户密码将以纯文本形式保存在IDM数据库表中。为了确保密码已编码,您可以在流程引擎配置中定义密码编码器。 -[source,xml,linenums] ----- - - - - - - - - - ... - ----- - -在本例中,使用了ShaPasswordEncoder,但也可以使用org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder 例如。不使用弹簧时,也可以使用org.flowable.idm.engine.impl.authentication.ApacheDigester 对密码进行编码。 -默认的IDM引擎配置器也可以被重写,以自定义方式初始化IDM引擎。LDAPConfigurator就是一个很好的例子 - -重写默认IDM引擎以使用LDAP服务器而不是默认IDM数据库表的实现。process engine配置的+idmProcessEngineConfigurator+属性可用于设置自定义配置程序,如LDAPConfigurator - -[source,xml,linenums] ----- - - ... - - - - - - - - - - - - - - - - - - - - - - - - - - - - ----- diff --git a/docs/userguide/src/zh_CN/bpmn/ch13-Designer.adoc b/docs/userguide/src/zh_CN/bpmn/ch13-Designer.adoc deleted file mode 100644 index 295f0902068..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch13-Designer.adoc +++ /dev/null @@ -1,739 +0,0 @@ -[[flowableDesigner]] - -== Eclipse Designer - -Flowable comes with an Eclipse plugin, the Flowable Eclipse Designer, that can be used to graphically model, test and deploy BPMN 2.0 processes. - - -[[eclipseDesignerInstallation]] - - -=== Installation - -The following installation instructions are verified on link:$$http://www.eclipse.org/downloads/$$[Eclipse Mars and Neon]. - -Go to *Help -> Install New Software*. In the following panel, click on _Add_ button and fill in the following fields: - -* **Name:** Flowable BPMN 2.0 designer -* **Location:** http://www.flowable.org/designer/update/ - -image::images/designer.add.update.site.png[align="center"] - -Make sure the *"Contact all updates sites.."* checkbox is *checked*, because all the necessary plugins will then be downloaded by Eclipse. - -[[eclipseDesignerEditorFeatures]] - - -=== Flowable Designer editor features - -* Create Flowable projects and diagrams. - -image::images/designer.create.flowable.project.png[align="center"] - -* The Flowable Designer creates a .bpmn file when creating a new Flowable diagram. When opened with the Flowable Diagram Editor view this will provide a graphical modeling canvas and palette. The same file can however be opened with an XML editor and it then shows the BPMN 2.0 XML elements of the process definition. So, the Flowable Designer works with a single file for both the graphical diagram as well as the BPMN 2.0 XML. Note that in old releases, the .bpmn extension was not supported as a deployment artifact for a process definition. Therefore, the "create deployment artifacts" feature of the Flowable Designer can be used to generate a BAR file containing a .bpmn20.xml file with the content of the .bpmn file. You can also do a quick file rename yourself. Also note that you can open a .bpmn20.xml file with the Flowable Diagram Editor view as well. - -image::images/designer.bpmn.file.png[align="center"] - - -* BPMN 2.0 XML files can be imported into the Flowable Designer and a diagram will be displayed. Just copy the BPMN 2.0 XML file to your project and open the file with the Flowable Diagram Editor view. The Flowable Designer uses the BPMN DI information of the file to create the diagram. If you have a BPMN 2.0 XML file without BPMN DI information, the Flowable BPMN autolayout module is used to created a graphical representation of the process. - -image::images/designer.open.importedfile.png[align="center", width="600"] - - -* For deployment, a BAR file and optionally a JAR file is created by the Flowable Designer by right-clicking on a Flowable project in the package explorer and choosing the _Create deployment artifacts_ option at the bottom of the popup menu. For more information about the deployment functionality of the Designer look at the <> section. - -image::images/designer.create.deployment.png[align="center", width="500"] - - -* Generate a unit test (right click on a BPMN 2.0 XML file in the package explorer and select __generate unit test__) A unit test is generated with a Flowable configuration that runs on an embedded H2 database. You can now run the unit test to test your process definition. - -image::images/designer.unittest.generate.png[align="center", width="600"] - - -* The Flowable project is generated as a Maven project. To configure the dependencies you need to run _mvn eclipse:eclipse_ and the Maven dependencies will be configured as expected. Note that for process design Maven dependencies are not needed. They are only needed to run unit tests. - -image::images/designer.project.maven.png[align="center", width="500"] - - -[[eclipseDesignerBPMNFeatures]] - - -=== Flowable Designer BPMN features - -* Support for start none event, start error event, timer start event, end none event, end error event, sequence flow, parallel gateway, exclusive gateway, inclusive gateway, event gateway, embedded sub process, event sub process, call activity, pool, lane, script task, user task, service task, mail task, manual task, business rule task, receive task, timer boundary event, error boundary event, signal boundary event, timer catching event, signal catching event, signal throwing event, none throwing event and four Flowable specific elements (user, script, mail tasks and start event). - -image::images/designer.model.process.png[align="center"] - -* You can quickly change the type of a task by hovering over the element and choosing the new task type. - -image::images/designer.model.quick.change.png[align="center"] - -* You can quickly add new elements hovering over an element and choosing a new element type. - -image::images/designer.model.quick.new.png[align="center"] - -* Java class, expression or delegate expression configuration is supported for the Java service task. In addition, field extensions can be configured. - -image::images/designer.servicetask.property.png[align="center"] - -* Support for pools and lanes. Because Flowable reads different pools as different process definitions, it makes the most sense to use only one pool. If you use multiple pools, be aware that drawing sequence flows between the pools will result in problems when deploying the process in the Flowable engine. You can add as many lanes to a pool as you want. - -image::images/designer.model.poolandlanes.png[align="center"] - -* You can add labels to sequence flows by filling in the name property. You can position the labels yourself and the position is saved as part of the BPMN 2.0 XML DI information. - -image::images/designer.model.labels.png[align="center"] - -* Support for event sub processes. - -image::images/designer.model.eventsubprocess.png[align="center"] - -* Support for expanded embedded sub processes. You can also add an embedded sub process in another embedded sub process. - -image::images/designer.embeddedprocess.canvas.png[align="center"] - -* Support for timer boundary events on tasks and embedded sub processes. Although, the timer boundary event makes most sense when using it on a user task or an embedded sub process in the Flowable Designer. - -image::images/designer.timerboundary.canvas.png[align="center"] - -* Support for additional Flowable extensions, such as the Mail task, the candidate configuration of User tasks and Script task configuration. - -image::images/designer.mailtask.property.png[align="center"] - -* Support for the Flowable execution and task listeners. You can also add field extensions for execution listeners. - -image::images/designer.listener.configuration.png[align="center"] - -* Support for conditions on sequence flows. - -image::images/designer.sequence.condition.png[align="center"] - - -[[eclipseDesignerDeployment]] - - -=== Flowable Designer deployment features - -Deploying process definitions and task forms on the Flowable engine is not hard. You need a BAR file containing the process definition BPMN 2.0 XML file and optionally task forms and an image of the process that can be viewed in the Flowable app. In the Flowable Designer it's made very easy to create a BAR file. When you've finished your process implementation just right-click on your Flowable project in the package explorer and choose for the *Create deployment artifacts* option at the bottom of the popup menu. - -image::images/designer.create.deployment.png[align="center", width="600"] - -Then a deployment directory is created containing the BAR file and optionally a JAR file with the Java classes of your Flowable project. - -image::images/designer.deployment.dir.png[align="center"] - -This file can now be uploaded to the Flowable engine using the deployments tab in Flowable Admin app, and you are ready to go. - -When your project contains Java classes, the deployment is a bit more work. In this case, the *Create deployment artifacts* step in the Flowable Designer will also generate a JAR file containing the compiled classes. This JAR file must be deployed to the flowable-XXX/WEB-INF/lib directory in your Flowable Tomcat (or other container) installation directory. This makes the classes available on the classpath of the Flowable Engine. - - -[[eclipseDesignerExtending]] - - -=== Extending Flowable Designer - -You can extend the default functionality offered by Flowable Designer. This section documents which extensions are available, how they can be used and provides some usage examples. Extending Flowable Designer is useful in cases where the default functionality doesn't suit your needs, you require additional capabilities or have domain-specific requirements when modeling business processes. Extension of Flowable Designer falls into two distinct categories: extending the palette and extending output formats. Each of these extension types requires a specific approach and different technical expertise. - - -[NOTE] -==== -Extending Flowable Designer requires technical knowledge and, more specifically, knowledge of programming in Java. Depending on the type of extension you want to create, you might also need to be familiar with Maven, Eclipse, OSGi, Eclipse extensions and SWT. -==== - - -[[eclipseDesignerCustomizingPalette]] - - -==== Customizing the palette - -You can customize the palette that is offered to users when modeling processes. The palette is the collection of shapes that can be dragged onto the canvas in a process diagram and is displayed to the right-hand side of the canvas. As you can see in the default palette, the default shapes are grouped together (these are called "drawers") for Events, Gateways and so on. There are two options built-in to Flowable Designer to customize the drawers and shapes in the palette: - -* Adding your own shapes / nodes to existing or new drawers -* Disabling any or all of the default BPMN 2.0 shapes offered by Flowable Designer, with the exception of the connection and selection tools - -In order to customize the palette, you create a JAR file that is needs to be added to every installation of Flowable Designer (more on <> later). Such a JAR file is called an _extension_. By writing classes that are included in your extension, Flowable Designer understands which customizations you wish to make. In order for this to work, your classes should implement certain interfaces. There is an integration library available with those interfaces and base classes to extend, which you should add to your project's classpath. - -You can find the code examples listed below in source control with Flowable Designer. Take a look in the +examples/money-tasks+ directory in the +flowable-designer+ repository of Flowable's link:$$https://github.com/flowable/flowable-designer/tree/master/examples$$[source code]. - - -[NOTE] -==== -You can setup your project in whichever tool you prefer and build the JAR with the build tool of your choice. For the instructions below, a setup is assumed with Eclipse Mars or Neon, using Maven (3.x) as build tool, but any setup should enable you to create the same results. -==== - - -===== Extension setup (Eclipse/Maven) - -Download and extract link:$$http://www.eclipse.org/downloads$$[Eclipse] (most recent versions should work) and a recent version (3.x) of link:$$http://maven.apache.org/download.html$$[Apache Maven]. If you use a 2.x version of Maven, you will run into problems when building your project, so make sure your version is up to date. We assume you are familiar with using basic features and the Java editor in Eclipse. It's up to you whether you prefer to use Eclipse's features for Maven or run Maven commands from a command prompt. - -Create a new project in Eclipse. This can be a general project type. Create a +pom.xml+ file at the root of the project to contain the Maven project setup. Also create folders for the +src/main/java+ and +src/main/resources+ folders, which are Maven conventions for your Java source files and resources respectively. Open the +pom.xml+ file and add the following lines: - - -[source,xml,linenums] ----- - - - 4.0.0 - - org.acme - money-tasks - 1.0.0 - jar - Acme Corporation Money Tasks -... - ----- - - -As you can see, this is just a basic pom.xml file that defines a +groupId+, +artifactId+ and +version+ for the project. We will create a customization that includes a single custom node for our money business. - -Add the integration library to your project's dependencies by including this dependency in your +pom.xml+ file: - - -[source,xml,linenums] ----- - - - org.flowable.designer - org.flowable.designer.integration - 5.22.0 - compile - - -... - - - Flowable - - ----- - - -Finally, in the++ pom.xml++ file, add the configuration for the ++maven-compiler-plugin++ so the Java source level is at least 1.5 (see snippet below). You will need this in order to use annotations. You can also include instructions for Maven to generate the JAR's ++MANIFEST.MF++ file. This is not required, but you can use a specific property in the manifest to provide a name for your extension (this name may be shown at certain places in the designer and is primarily intended for future use if you have several extensions in the designer). If you wish to do so, include the following snippet in ++pom.xml++: - -[source,xml,linenums] ----- - - - - maven-compiler-plugin - - 1.8 - 1.8 - true - true - true - - - - org.apache.maven.plugins - maven-jar-plugin - 2.3.2 - - - true - - false - true - - - Acme Money - - - - - - ----- - - -The name for the extension is described by the +FlowableDesigner-Extension-Name+ property. The only thing left to do now is tell Eclipse to setup the project according to the instructions in +pom.xml+. So open up a command shell and go to the root folder of your project in the Eclipse workspace. Then, execute the following Maven command: - ----- -mvn eclipse:eclipse ----- - -Wait until the build is successful. Refresh the project (use the project's context menu (right-click) and select ++Refresh++). You should now have the +src/main/java+ and +src/main/resources+ folders as source folders in the Eclipse project. - - -[NOTE] -==== -You can, of course, also use the link:$$http://www.eclipse.org/m2e$$[m2eclipse] plugin and simply enable Maven dependency management from the context menu (right-click) of the project. Then choose +Maven+ > +Update project configuration+ from the project's context menu. That should setup the source folders as well. -==== - - -That's it for the setup. Now you're ready to start creating customizations to Flowable Designer! - -[[eclipseDesignerApplyingExtension]] - - -===== Applying your extension to Flowable Designer - -You might be wondering how you can add your extension to Flowable Designer so your customizations are applied. These are the steps to do just that: -* Once you've created your extension JAR (for instance, by performing a mvn install in your project to build it with Maven), you need to transfer the extension to the computer where Flowable Designer is installed; -* Store the extension somewhere on the hard drive where it will be able to remain, and remember the location. _Note:_ the location must be outside the Eclipse workspace of Flowable Designer - storing the extension inside the workspace will lead to the user getting a popup error message and the extensions being unavailable; -* Start Flowable Designer and from the menu, select +Window+ > +Preferences+ or +Eclipse+ > +Preferences+ -* In the preferences screen, type +user+ as keyword. You should see an option to access the +User Libraries+ in Eclipse in the +Java+ section. - -image::images/designer.preferences.userlibraries.png[align="center", width="250"] - - -* Select the User Libraries item and a tree view shows up to the right where you can add libraries. You should see the default group where you can add extensions to Flowable Designer (depending on your Eclipse installation, you might see several others as well). - -image::images/designer.preferences.userlibraries.flowable.empty.png[align="center", width="600"] - - -* Select the +Flowable Designer Extensions+ group and click the +Add JARs...+ or +Add External JARs...+ button. Navigate to the folder where your extension is stored and select the extension file you want to add. After completing this, your preferences screen should show the extension as part of the +Flowable Designer Extensions+ group, as shown below. - -image::images/designer.preferences.userlibraries.flowable.moneytasks.png[align="center", width="600"] - - -* Click the +OK+ button to save and close the preferences dialog. The +Flowable Designer Extensions+ group is automatically added to new Flowable projects you create. You can see the user library as an entry in the project's tree in the Navigator or Package Explorer. If you already had Flowable projects in the workspace, you should also see the new extensions show up in the group. An example is shown below. - -image::images/designer.userlibraries.project.png[align="center", width="400"] - - -Diagrams you open will now have the shapes from the new extension in their palette (or shapes disabled, depending on the customizations in your extension). If you already had a diagram opened, close and reopen it to see the changes in the palette. - - -===== Adding shapes to the palette - -With your project set up, you can now easily add shapes to the palette. Each shape you wish to add is represented by a class in your JAR. Take note that these classes are not the classes that will be used by the Flowable engine during runtime. In your extension you describe the properties that can be set in Flowable Designer for each shape. From these shapes, you can also define the runtime characteristics that should be used by the engine when a process instance reaches the node in the process. The runtime characteristics can use any of the options that Flowable supports for regular ++ServiceTask++s. See <> for more details. - -A shape's class is a simple Java class, to which a number of annotations are added. The class should implement the +CustomServiceTask+ interface, but you shouldn't implement this interface yourself. Extend the +AbstractCustomServiceTask+ base class instead (at the moment you MUST extend this class directly, so no abstract classes in between). In the Javadoc for that class you can find instructions on the defaults it provides and when you should override any of the methods it already implements. Overrides allow you to do things such as providing icons for the palette and in the shape on the canvas (these can be different) and specifying the base shape you want the node to have (activity, event, gateway). - - -[source,java,linenums] ----- -/** - * @author John Doe - * @version 1 - * @since 1.0.0 - */ -public class AcmeMoneyTask extends AbstractCustomServiceTask { -... -} ----- - - -You will need to implement the +getName()+ method to determine the name the node will have in the palette. You can also put the nodes in their own drawer and provide an icon. Override the appropriate methods from +AbstractCustomServiceTask+. If you want to provide an icon, make sure it's in the +src/main/resources+ package in your JAR and is about 16x16 pixels and in JPEG or PNG format. The path you supply is relative to that folder. - -You can add properties to the shape by adding members to the class and annotating them with the +@Property+ annotation like this: - -[source,java,linenums] ----- -@Property(type = PropertyType.TEXT, displayName = "Account Number") -@Help(displayHelpShort = "Provide an account number", displayHelpLong = HELP_ACCOUNT_NUMBER_LONG) -private String accountNumber; ----- - -There are several +PropertyType+ values you can use, which are described in more detail in <>. You can make a field required by setting the required attribute to true. A message and red background will appear if the user doesn't fill in the field. - -If you want to fix the order of the various properties in your class as they appear in the property screen, you should specify the order attribute of the +@Property+ annotation. - -As you can see, there's also a +@Help+ annotation that's used to provide the user some guidance when filling in the field. You can also use the +@Help+ annotation on the class itself - this information is shown at the top of the property sheet presented to the user. - -Below is the listing for further elaboration of the +MoneyTask+. A comment field has been added and you can see an icon is included for the node. - - -[source,java,linenums] ----- -/** - * @author John Doe - * @version 1 - * @since 1.0.0 - */ -@Runtime(javaDelegateClass = "org.acme.runtime.AcmeMoneyJavaDelegation") -@Help(displayHelpShort = "Creates a new account", displayHelpLong = - "Creates a new account using the account number specified") -public class AcmeMoneyTask extends AbstractCustomServiceTask { - - private static final String HELP_ACCOUNT_NUMBER_LONG = - "Provide a number that is suitable as an account number."; - - @Property(type = PropertyType.TEXT, displayName = "Account Number", required = true) - @Help(displayHelpShort = "Provide an account number", displayHelpLong = HELP_ACCOUNT_NUMBER_LONG) - private String accountNumber; - - @Property(type = PropertyType.MULTILINE_TEXT, displayName = "Comments") - @Help(displayHelpShort = "Provide comments", displayHelpLong = - "You can add comments to the node to provide a brief description.") - private String comments; - - @Override - public String contributeToPaletteDrawer() { - return "Acme Corporation"; - } - - @Override - public String getName() { - return "Money node"; - } - - @Override - public String getSmallIconPath() { - return "icons/coins.png"; - } -} ----- - - -If you extend Flowable Designer with this shape, the palette and corresponding node will look like this: - -image::images/designer.palette.add.money.png[align="center", width="250"] - - -The properties screen for the money task is shown below. Note the required message for the +accountNumber+ field. - -image::images/designer.palette.add.money.properties.required.png[align="center"] - - -Users can enter static text or use expressions that use process variables in the property fields when creating diagrams (for example, "This little piggy went to ${piggyLocation}"). Generally, this applies to text fields where users are free to enter any text. If you expect users to want to use expressions and you apply runtime behavior to your +CustomServiceTask+ (using ++@Runtime++), make sure to use +Expression+ fields in the delegate class so the expressions are correctly resolved at runtime. More information on runtime behavior can be found in <>. - - -The help for fields is offered by the buttons to the right of each property. Clicking on the button shows a popup as displayed below. - -image::images/designer.palette.add.money.help.png[align="center"] - - -[[eclipseDesignerConfiguringRuntime]] - -====== Configuring runtime execution of Custom Service Tasks - -With your fields set up and your extension applied to Designer, users can configure the properties of the service task when modelling a process. In most cases, you will want to use these user-configured properties when the process is executed by Flowable. To do this, you must tell Flowable which class to instantiate when the process reaches your +CustomServiceTask+. - -There is a special annotation for specifying the runtime characteristics of your +CustomServiceTask+, the +@Runtime+ annotation. Here's an example of how to use it: - - -[source,java,linenums] ----- -@Runtime(javaDelegateClass = "org.acme.runtime.AcmeMoneyJavaDelegation") ----- - - -Your +CustomServiceTask+ will result in a normal +ServiceTask+ in the BPMN output of processes modeled with it. Flowable enables <> to define the runtime characteristics of ++ServiceTask++s. Therefore, the +@Runtime+ annotation can take one of three attributes, which match directly to the options Flowable provides, like this: - -* +javaDelegateClass+ maps to +flowable:class+ in the BPMN output. Specify the fully qualified classname of a class that implements +JavaDelegate+. -* +expression+ maps to +flowable:expression+ in the BPMN output. Specify an expression to a method to be executed, such as a method in a Spring Bean. You should _not_ specify any +@Property+ annotations on fields when using this option. For more information, see below. -* +javaDelegateExpression+ maps to +flowable:delegateExpression+ in the BPMN output. Specify an expression to a class that implements +JavaDelegate+. - - -The user's property values will be injected into the runtime class if you provide members in the class for Flowable to inject into. The names should match the names of the members in your +CustomServiceTask+. For more information, consult <> of the userguide. Note that from version 5.11.0 of the Designer, you can use the +Expression+ interface for dynamic field values. This means that the value of the property in the Flowable Designer must contain an expression, and this expression will then be injected into an +Expression+ property in the +JavaDelegate+ implementation class. - - -[NOTE] -==== - -You can use +@Property+ annotations on members of your +CustomServiceTask+, but this will not work if you use ++@Runtime++'s +expression+ attribute. The reason for this is that the expression you specify will be attempted to be resolved to a _method_ by Flowable, not to a class. Therefore, no injection into a class will be performed. Any members marked with +@Property+ will be ignored by Designer if you use +expression+ in your +@Runtime+ annotation. Designer will not render them as editable fields in the node's property pane and will produce no output for the properties in the process' BPMN. -==== - -[NOTE] -==== -Note that the runtime class shouldn't be in your extension JAR, as it's dependent on the Flowable libraries. Flowable needs to be able to find it at runtime, so it needs to be on the Flowable engine's classpath. -==== - -The examples project in Designer's source tree contains examples of the different options for configuring +@Runtime+. Take a look in the money-tasks project for some starting points. The examples refer to delegate class examples that are in the money-delegates project. - - -[[eclipseDesignerPropertyTypes]] - - -===== Property types - -This section describes the property types you can use for a +CustomServiceTask+ by setting its type to a +PropertyType+ value. - -====== PropertyType.TEXT - -Creates a single-line text field as shown below. Can be a required field and shows validation messages as a tooltip. Validation failures are displayed by changing the background of the field to a light red color. - -image::images/designer.property.text.invalid.png[align="center"] - -====== PropertyType.MULTILINE_TEXT - -Creates a multiline text field as shown below (height is fixed at 80 pixels). Can be a required field and shows validation messages as a tooltip. Validation failures are displayed by changing the background of the field to a light red color. - -image::images/designer.property.multiline.text.invalid.png[align="center"] - - -====== PropertyType.PERIOD - -Creates a structured editor for specifying a period of time by editing amounts of each unit with a spinner control. The result is shown below. Can be a required field (which is interpreted such that not all values can be 0, so at least 1 part of the period must have a non-zero value) and shows validation messages as a tooltip. Validation failures are displayed by changing the background of the entire field to a light red color. The value of the field is stored as a string of the form 1y 2mo 3w 4d 5h 6m 7s, which represents 1 year, 2 months, 3 weeks, 4 days, 6 minutes and 7 seconds. The entire string is always stored, even if parts are 0. - -image::images/designer.property.period.png[align="center"] - - -====== PropertyType.BOOLEAN_CHOICE - -Creates a single checkbox control for boolean or toggle choices. Note that you can specify the +required+ attribute on the +Property+ annotation, but it will not be evaluated because that would leave the user without a choice whether to check the box or not. The value stored in the diagram is java.lang.Boolean.toString(boolean), which results in "true" or "false". - -image::images/designer.property.boolean.choice.png[align="center"] - -====== PropertyType.RADIO_CHOICE - -Creates a group of radio buttons as shown below. Selection of any of the radio buttons is mutually exclusive with selection of any of the others (in other words, only one selection allowed). Can be a required field and shows validation messages as a tooltip. Validation failures are displayed by changing the background of the group to a light red color. - -This property type expects the class member you have annotated to also have an accompanying +@PropertyItems+ annotation (for an example, see below). Using this additional annotation, you can specify the list of items that should be offered in an array of Strings. Specify the items by adding two array entries for each item: first, the label to be shown; second, the value to be stored. - -[source,java,linenums] ----- -@Property(type = PropertyType.RADIO_CHOICE, displayName = "Withdrawal limit", required = true) -@Help(displayHelpShort = "The maximum daily withdrawal amount ", - displayHelpLong = "Choose the maximum daily amount that can be withdrawn from the account.") -@PropertyItems({ LIMIT_LOW_LABEL, LIMIT_LOW_VALUE, LIMIT_MEDIUM_LABEL, LIMIT_MEDIUM_VALUE, - LIMIT_HIGH_LABEL, LIMIT_HIGH_VALUE }) -private String withdrawalLimit; ----- - -image::images/designer.property.radio.choice.png[align="center"] - -image::images/designer.property.radio.choice.invalid.png[align="center"] - - -====== PropertyType.COMBOBOX_CHOICE - -Creates a combobox with fixed options as shown below. Can be a required field and shows validation messages as a tooltip. Validation failures are displayed by changing the background of the combobox to a light red color. - -This property type expects the class member you have annotated to also have an accompanying +@PropertyItems+ annotation (for an example, see below). Using this additional annotation, you can specify the list of items that should be offered in an array of Strings. Specify the items by adding two array entries for each item: first, the label to be shown; second, the value to be stored. - -[source,java,linenums] ----- -@Property(type = PropertyType.COMBOBOX_CHOICE, displayName = "Account type", required = true) -@Help(displayHelpShort = "The type of account", - displayHelpLong = "Choose a type of account from the list of options") -@PropertyItems({ ACCOUNT_TYPE_SAVINGS_LABEL, ACCOUNT_TYPE_SAVINGS_VALUE, ACCOUNT_TYPE_JUNIOR_LABEL, - ACCOUNT_TYPE_JUNIOR_VALUE, ACCOUNT_TYPE_JOINT_LABEL, ACCOUNT_TYPE_JOINT_VALUE, - ACCOUNT_TYPE_TRANSACTIONAL_LABEL, ACCOUNT_TYPE_TRANSACTIONAL_VALUE, ACCOUNT_TYPE_STUDENT_LABEL, - ACCOUNT_TYPE_STUDENT_VALUE, ACCOUNT_TYPE_SENIOR_LABEL, ACCOUNT_TYPE_SENIOR_VALUE }) -private String accountType; ----- - -image::images/designer.property.combobox.choice.png[align="center"] - -image::images/designer.property.combobox.choice.invalid.png[align="center"] - - -====== PropertyType.DATE_PICKER - -Creates a date selection control as shown below. Can be a required field and shows validation messages as a tooltip (note, that the control used will auto-set the selection to the date on the system, so the value is seldom empty). Validation failures are displayed by changing the background of the control to a light red color. - -This property type expects the class member you have annotated to also have an accompanying +@DatePickerProperty+ annotation (for an example, see below). Using this additional annotation, you can specify the date time pattern to be used to store dates in the diagram and the type of datepicker you would like to be shown. Both attributes are optional and have default values that will be used if you don't specify them (these are static variables in the +DatePickerProperty+ annotation). The +dateTimePattern+ attribute should be used to supply a pattern to the +SimpleDateFormat+ class. When using the +swtStyle+ attribute, you should specify an integer value that is supported by ++SWT++'s +DateTime+ control, because this is the control that is used to render this type of property. - -[source,java,linenums] ----- -@Property(type = PropertyType.DATE_PICKER, displayName = "Expiry date", required = true) -@Help(displayHelpShort = "The date the account expires.", - displayHelpLong = "Choose the date when the account will expire if not extended before the date.") -@DatePickerProperty(dateTimePattern = "MM-dd-yyyy", swtStyle = 32) -private String expiryDate; ----- - -image::images/designer.property.date.picker.png[align="center"] - - - -====== PropertyType.DATA_GRID - -Creates a data grid control as shown below. A data grid can be used to allow the user to enter an arbitrary amount of rows of data and enter values for a fixed set of columns in each of those rows (each individual combination of row and column is referred to as a cell). Rows can be added and removed as the user sees fit. - -This property type expects the class member you have annotated to also have an accompanying +@DataGridProperty+ annotation (for an example, see below). Using this additional annotation, you can specify some specific attributes of the data grid. You are required to reference a different class to determine which columns go into the grid with the +itemClass+ attribute. Flowable Designer expects the member type to be a +List+. By convention, you can use the class of the +itemClass+ attribute as its generic type. If, for example, you have a grocery list that you edit in the grid, you would define the columns of the grid in the +GroceryListItem+ class. From your +CustomServiceTask+, you would refer to it like this: - -[source,java,linenums] ----- -@Property(type = PropertyType.DATA_GRID, displayName = "Grocery List") -@DataGridProperty(itemClass = GroceryListItem.class) -private List groceryList; ----- - - -The "itemClass" class uses the same annotations you would otherwise use to specify fields of a +CustomServiceTask+ (with the exception of a data grid). Specifically, +TEXT+, +$$MULTILINE_TEXT$$+ and +PERIOD+ are currently supported. You'll notice the grid will create single line text controls for each field, regardless of the +PropertyType+. This is done on purpose to keep the grid graphically appealing and readable. If you consider the regular display mode for a +PERIOD+ +PropertyType+ for instance, you can imagine it would never properly fit in a grid cell without cluttering the screen. For +$$MULTILINE_TEXT$$+ and +PERIOD+, a double-click mechanism is added to each field which pops up a larger editor for the +PropertyType+. The value is stored to the field after the user clicks OK and is therefore readable within the grid. - -Required attributes are handled in a similar manner to regular fields of type +TEXT+ and the entire grid is validated as soon as any field loses focus. The background color of the text control in a specific cell of the data grid is changed to light red if there are validation failures. - -By default, the component allows the user to add rows, but not to determine the order of those rows. If you wish to allow this, you should set the +orderable+ attribute to true, which enables buttons at the end of each row to move it up or down in the grid. - -[NOTE] -==== -At the moment, this property type is not correctly injected into your runtime class. -==== - -image::images/designer.property.datagrid.png[align="center"] - - - -===== Disabling default shapes in the palette - -This customization requires you to include a class in your extension that implements the +DefaultPaletteCustomizer+ interface. You should not implement this interface directly, but subclass the +AbstractDefaultPaletteCustomizer+ base class. Currently, this class provides no functionality, but future versions of the +DefaultPaletteCustomizer+ interface will offer more capabilities for which this base class will provide some sensible defaults, so it's best to subclass it to be sure your extension will be compatible with future releases. - -Extending the +AbstractDefaultPaletteCustomizer+ class requires you to implement one method, +disablePaletteEntries()+, from which you must return a list of +PaletteEntry+ values. For each of the default shapes, you can disable it by adding its corresponding +PaletteEntry+ value to your list. Note that if you remove shapes from the default set and there are no remaining shapes in a particular drawer, that drawer will be removed from the palette in its entirety. If you wish to disable all of the default shapes, you only need to add +PaletteEntry.ALL+ to your result. As an example, the code below disables the Manual task and Script task shapes in the palette. - -[source,java,linenums] ----- -public class MyPaletteCustomizer extends AbstractDefaultPaletteCustomizer { - - @Override - public List disablePaletteEntries() { - List result = new ArrayList(); - result.add(PaletteEntry.MANUAL_TASK); - result.add(PaletteEntry.SCRIPT_TASK); - return result; - } - -} ----- - - -The result of applying this extension is shown in the image below. As you can see, the manual task and script task shapes are no longer available in the +Tasks+ drawer. - -image::images/designer.palette.disable.manual.and.script.png[align="center"] - - -To disable all of the default shapes, you could use something similar to the code below. - -[source,java,linenums] ----- -public class MyPaletteCustomizer extends AbstractDefaultPaletteCustomizer { - - @Override - public List disablePaletteEntries() { - List result = new ArrayList(); - result.add(PaletteEntry.ALL); - return result; - } - -} ----- - - -The result will look like this (notice that the drawers the default shapes were in are no longer in the palette): - -image::images/designer.palette.disable.all.png[align="center"] - - -==== Validating diagrams and exporting to custom output formats - -Besides customizing the palette, you can also create extensions to Flowable Designer that can perform validations and save information from the diagram to custom resources in the Eclipse workspace. There are built-in extension points for doing this and this section explains how to use them. - -[NOTE] -==== -The ExportMarshaller functions were reintroduced recently. We are still working on the validation functionality. The documentation below details the old behavior and will be updated when the new functionality is available. -==== - - -Flowable Designer allows you to write extensions that validate diagrams. There are already validations of BPMN constructs in the tool by default, but you can add your own if you want to validate additional items, such as modeling conventions or the values in properties of ++CustomServiceTask++s. These extensions are known as +Process Validators+. - -You can also customize Flowable Designer to publish to additional formats when saving diagrams. These extensions are called +Export Marshallers+ and are invoked automatically by Flowable Designer on each save action by the user. This behavior can be enabled or disabled by setting a preference in Eclipse's preferences dialog for each format for which there is an extension detected. Designer will make sure your +ExportMarshaller+ is invoked when saving the diagram, depending on the user's preference. - -Often, you will want to combine a +ProcessValidator+ and an +ExportMarshaller+. Let's say you have a number of ++CustomServiceTask++s in use that have properties you would like to use in the process that gets generated. However, before the process is generated, you want to validate some of those values first. Combining a +ProcessValidator+ and +ExportMarshaller+ is the best way to accomplish this and Flowable Designer enables you to plug your extensions into the tool seamlessly. - -To create a +ProcessValidator+ or an +ExportMarshaller+, you need to create a different kind of extension than for extending the palette. The reason for this is simple: from your code you will need access to more APIs than those that are offered by the integration library. In particular, you will need classes that are available in Eclipse itself. So to get started, you should create an Eclipse plugin (which you can do by using Eclipse's PDE support) and package it in a custom Eclipse product or feature. It's beyond the scope of this user guide to explain all the details involved in developing Eclipse plugins, so the instructions below are limited to the functionality for extending Flowable Designer. - -Your bundle should be dependent on the following libraries: - -* org.eclipse.core.runtime -* org.eclipse.core.resources -* org.flowable.designer.eclipse -* org.flowable.designer.libs -* org.flowable.designer.util - -Optionally, the org.apache.commons.lang bundle is available through Designer if you'd like to use that in your extension. - - -Both ++ProcessValidator++s and ++ExportMarshaller++s are created by extending a base class. These base classes inherit some useful methods from their superclass, the +AbstractDiagramWorker+ class. Using these methods you can create information, warning and error markers that show up in Eclipse's problems view for the user to figure out what's wrong or important. You can get to information about the diagram in the form of +Resources+ and +InputStreams+. This information is provided from the +DiagramWorkerContext+, which is available from the +AbstractDiagramWorker+ class. - -It's probably a good idea to invoke +clearMarkers()+ as one of the first things you do in either a +ProcessValidator+ or an ++ExportMarshaller++; this will clear any previous markers for your worker (markers are automatically linked to the worker and clearing markers for one worker leaves other markers untouched). For example: - - -[source,java,linenums] ----- -// Clear markers for this diagram first -clearMarkersForDiagram(); ----- - -You should also use the progress monitor provided (in the ++DiagramWorkerContext++) to report your progress back to the user, because validations and marshalling actions can take up some time during which the user is forced to wait. Reporting progress requires some knowledge of how you should use Eclipse's features. Take a look at link:$$http://www.eclipse.org/articles/Article-Progress-Monitors/article.html$$[this article] for a thorough explanation of the concepts and usage. - -===== Creating a ProcessValidator extension - - -Create an extension to the +org.flowable.designer.eclipse.extension.validation.ProcessValidator+ extension point in your +plugin.xml+ file. For this extension point, you are required to subclass the +AbstractProcessValidator+ class. - -[source,xml,linenums] ----- - - - - - - - ----- - - -[source,java,linenums] ----- -public class AcmeProcessValidator extends AbstractProcessValidator { -} ----- - - -You have to implement a number of methods. Most importantly, implement +getValidatorId()+ so you return a globally unique ID for your validator. This will enable you to invoke it from an +ExportMarshaller+, or even let someone _else_ invoke your validator from their +ExportMarshaller+. Implement +getValidatorName()+ and return a logical name for your validator. This name is shown to the user in dialogs. In +getFormatName()+, you can return the type of diagram the validator typically validates. - -The validation work itself is done in the +validateDiagram()+ method. From this point on, it's up to your specific functionality as to what you code here. Typically, however, you will want to start by getting hold of the nodes in the diagram's process, so you can iterate through them, collect, compare and validate data. This snippet shows you how to do this: - -[source,java,linenums] ----- -final EList contents = getResourceForDiagram(diagram).getContents(); -for (final EObject object : contents) { - if (object instanceof StartEvent ) { - // Perform some validations for StartEvents - } - // Other node types and validations -} ----- - - -Don't forget to invoke +addProblemToDiagram()+ and/or +addWarningToDiagram()+, and so on as you go through your validations. Make sure you return a correct boolean result at the end to indicate whether you consider the validation as having succeeded or failed. This can be used by invoking +ExportMarshaller+ to determine the next course of action. - - -===== Creating an ExportMarshaller extension - -Create an extension to the +org.flowable.designer.eclipse.extension.ExportMarshaller+ extension point in your +plugin.xml+ file. For this extension point, you are required to subclass the +AbstractExportMarshaller+ class. This abstract base class provides you with a number of useful methods when marshalling to your own format, but most importantly, it allows you to save resources to the workspace and to invoke validators. - -An example implementation is available in Designer's examples folder. This example shows how to use the methods in the base class to get the basics done, such as accessing the diagram's +InputStream+, using its +BpmnModel+ and saving resources to the workspace. - -[source,xml,linenums] ----- - - - - - - - ----- - - -[source,java,linenums] ----- -public class AcmeExportMarshaller extends AbstractExportMarshaller { -} ----- - -You are required to implement some methods, such as +getMarshallerName()+ and +getFormatName()+. These methods are used to display options to the user and to show information in progress dialogs, so make sure the descriptions you return reflect the functionality you are implementing. - -The bulk of your work is performed in the +doMarshallDiagram()+ method. - -If you want to perform a certain validation first, you can invoke the validator directly from your marshaller. You receive a boolean result from the validator, so you know whether validation succeeded. In most cases you won't want to proceed with marshalling the diagram if it's not valid, but you might choose to go ahead anyway or even create a different resource if validation fails. - - -Once you have all the data you need, you should invoke the +saveResource()+ method to create a file containing your data. You can invoke +saveResource()+ as many times as you wish from a single ExportMarshaller; a marshaller can therefore be used to create more than one output file. - -You can construct a filename for your output resource(s) by using the +saveResource()+ method in the +AbstractDiagramWorker+ class. There are a couple of useful variables you can have substituted, allowing you to create filenames such as _original-filename__my-format-name.xml. These variables are described in the Javadocs and defined by the +ExportMarshaller+ interface. You can also use +resolvePlaceholders()+ on a string (for example, a path) if you want to substitute the placeholders yourself. +getURIRelativeToDiagram()+ will invoke this for you. - -You should use the progress monitor provided to report your progress back to the user. How to do this is described in link:$$http://www.eclipse.org/articles/Article-Progress-Monitors/article.html$$[this article]. diff --git a/docs/userguide/src/zh_CN/bpmn/ch13-UI.adoc b/docs/userguide/src/zh_CN/bpmn/ch13-UI.adoc deleted file mode 100755 index 9bd11e2a639..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch13-UI.adoc +++ /dev/null @@ -1,912 +0,0 @@ -[[flowableUIApps]] - -== Flowable UI应用 - -Flowable提供了几个web应用,用于演示及介绍Flowable项目提供的功能: - -* Flowable IDM: 身份管理应用。为所有Flowable UI应用提供单点登录认证功能,并且为拥有IDM管理员权限的用户提供了管理用户、组与权限的功能。 -* Flowable Modeler: 让具有建模权限的用户可以创建流程模型、表单、选择表与应用定义。 -* Flowable Task: 运行时任务应用。提供了启动流程实例、编辑任务表单、完成任务,以及查询流程实例与任务的功能。 -* Flowable Admin: 管理应用。让具有管理员权限的用户可以查询BPMN、DMN、Form及Content引擎,并提供了许多选项用于修改流程实例、任务、作业等。管理应用通过REST API连接至引擎,并与Flowable Task应用及Flowable REST应用一同部署。 - -所有其他的应用都需要Flowable IDM提供认证。每个应用的WAR文件可以部署在相同的servlet容器(如Apache Tomcat)中,也可以部署在不同的容器中。由于每个应用使用相同的cookie进行认证,因此应用需要运行在相同的域名下。 - -应用基于Spring Boot 2.0。也就是说WAR文件实际上可以作为独立应用直接运行。参见Spring Boot文档中的link:$$https://docs.spring.io/spring-boot/docs/current/reference/html/build-tool-plugins-maven-plugin.html#build-tool-plugins-maven-packaging$$[可执行的Jar]章节。 - -[[uiAppInstallation]] - -=== 安装 - -如前所述,全部四个UI应用可以部署在同一个Tomcat服务器里,并且作为入门,这大概也是最简单的方式。也可以选择只安装Modeler应用,但是必须也要部署、运行Flowable IDM应用。在这个安装指导中,我们会介绍如何将所有的四个应用安装至Tomcat服务。 - -1. 下载最新稳定版本的link:$$http://tomcat.apache.org$$[Apache Tomcat]。 -2. 下载最新稳定版本的link:$$http://www.flowable.org/downloads.html$$[Flowable 6]。 -3. 将Flowable发行包中,__wars__文件夹下的flowable-admin.war、flowable-idm.war、flowable-modeler.war与flowable-task.war文件,复制到Tomcat的webapps文件夹下。 -4. 运行bin/startup.sh(在Mac OS或Linux下),或bin/startup.bat(在Windows下)脚本,启动Tomcat服务器。 -5. 打开web浏览器,访问link:$$http://localhost:8080/flowable-modeler$$[http://localhost:8080/flowable-modeler]。 - -这样所有的Flowable UI应用都将运行在H2内存数据库下,并且可以在浏览器中看到如下登录界面: - -image::images/flowable_idm_login_screen.png[align="center"] - -默认情况下,Flowable IDM应用将创建一个具有访问所有Flowable UI应用所需的权限的admin用户。使用admin/test登录,浏览器会跳转至Flowable Modeler应用: - -image::images/flowable_modeler_startup_screen.png[align="center"] - -作为可执行的Spring Boot应用,可以直接以独立应用模式运行UI,而不需要应用服务器。 -可以像这样启动一个应用: - -``` -java -jar flowable-idm.war -``` - -通常会需要将默认的H2内存数据库配置,修改为MySQL或Postgres(或其他持久化数据库)。 -可以修改每个应用__WEB-INF/classes/__文件夹下的application.properties。 -也可以使用Spring Boot的link:$$https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html$$[显式配置]。 -link:$$https://github.com/flowable/flowable-engine/blob/master/modules/flowable-ui-task/flowable-ui-task-app/src/main/resources/application.properties$$[Github]上也提供了配置示例。 -要将默认配置修改为MySQL,需要如下修改配置文件: - - -[source,linenums] ----- -spring.datasource.driver-class-name=com.mysql.jdbc.Driver -spring.datasource.url=jdbc:mysql://127.0.0.1:3306/flowable?characterEncoding=UTF-8 -spring.datasource.username=flowable -spring.datasource.password=flowable ----- - -这个配置需要MySQL服务器中有一个flowable数据库,UI应用会自动生成必要的数据库表。对于Postgres,需要做如下修改: - -[source,linenums] ----- -spring.datasource.driver-class-name=org.postgresql.Driver -spring.datasource.url=jdbc:postgresql://localhost:5432/flowable -spring.datasource.username=flowable -spring.datasource.password=flowable ----- - -除了修改配置,还需要确保在classpath中有对应的数据库驱动。类似的,可以对每个web应用分别操作,将驱动JAR文件添加到WEB-INF/lib目录下;也可以直接将JAR文件添加到Tomcat的lib目录下。MySQL与Postgres的数据库驱动可以从这里下载: - -* MySQL: link:$$https://dev.mysql.com/downloads/connector/j$$[https://dev.mysql.com/downloads/connector/j] -* Postgres: link:$$https://jdbc.postgresql.org/$$[https://jdbc.postgresql.org/] - -以独立应用方式运行应用时,可以使用 `loader.path` 参数添加数据库驱动。 - -``` -java -Dloader.path=/location/to/your/driverfolder -jar flowable-idm.war -``` - -参阅Spring Boot文档link:$$https://docs.spring.io/spring-boot/docs/current/reference/html/executable-jar.html#executable-jar-property-launcher-features$$[`PropertiesLauncher` 功能]介绍了解更多信息。 - -[[_flowable_ui_applications_configurations]] -=== 配置Flowable UI应用 - -作为Spring Boot应用,Flowable UI应用可以使用Spring Boot提供的全部参数。 -参阅Spring Boot文档的link:$$https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html$$[显式配置]章节,了解如何进行自定义配置。 - -提示:也可以使用YAML格式的配置文件。 - -.通用UI应用参数 -[cols="4*",options="header"] -|=============== -|参数名 -|原参数 -|默认值 -|描述 - -|flowable.common.app.idm-url -|idm.app.url -|- -|IDM应用的URL,用于获取用户信息与令牌信息的REST GET调用。也用做UI应用重定向的登录页。 - -|flowable.common.app.idm-redirect-url -|idm.app.redirect.url -|- -|IDM应用的重定向URL,在未设置cookie或cookie失效时,重定向至该页面进行登录。 - -|flowable.common.app.redirect-on-auth-success -|app.redirect.url.on.authsuccess -|- -|登录成功后需要重定向的页面URL。 - -|flowable.common.app.role-prefix -|- -|ROLE_ -|Spring Security需要的默认角色前缀。 - -|flowable.common.app.tenant-id -|- -|- -|DefaultTenantProvider所用的静态租户id。modeler用来判断需要将模型存储及发布在哪个租户id下。 - 当未设置该值、值为空,或只包含空白时:如果能够获取用户的租户id,则会使用该租户id;否则不使用租户id。 - -|flowable.common.app.cache-login-tokens.max-age -|cache.login-tokens.max.age -|30 -|login token的缓存时间,以秒记。 - -|flowable.common.app.cache-login-tokens.max-size -|cache.login-tokens.max.size -|2048 -|login token缓存的最大尺寸。 - -|flowable.common.app.cache-login-users.max-age -|cache.login-users.max.age -|30 -|login user的缓存时间,以秒记。 - -|flowable.common.app.cache-login-users.max-size -|cache.login-users.max.size -|2048 -|login user缓存的最大尺寸。 - -|flowable.common.app.cache-users.max-age -|cache.users.max.age -|30 -|user的缓存时间,以秒记。 - -|flowable.common.app.cache-users.max-size -|cache.users.max.size -|2048 -|user缓存的最大尺寸。 - -|flowable.common.app.idm-admin.password -|idm.admin.password -|test -|对IDM REST服务进行REST调用(使用基础认证)的密码。 - -|flowable.common.app.idm-admin.user -|idm.admin.user -|admin -|对IDM REST服务进行REST调用(使用基础认证)的用户名。 - -|flowable.rest.app.authentication-mode -|rest.authentication.mode -|verify-privilege -|配置REST API验证用户身份的方式: - __any-user__ :用户存在且密码匹配。任何用户都可以进行调用(6.3.0之前的方式) - __verify-privilege__ :用户存在且密码匹配,并且用户拥有__rest-api__权限 - -|=============== - -一些旧参数改由Flowable Spring Boot starter(或Spring Boot)进行管理 - -.由Flowable Spring Boot Starter管理的旧参数 -[cols="4*",options="header"] -|=============== -|参数名 -|原参数 -|默认值 -|描述 - -|flowable.async-executor-activate -|engine.process.asyncexecutor.activate -|true -|是否启用异步执行器。 - -|flowable.database-schema-update -|engine.process.schema.update -|true -|是否执行数据库表结构升级。 - -|flowable.history-level -|engine.process.history.level -|- -|历史级别。 - -|flowable.process.servlet.name -|flowable.rest-api-servlet-name -|Flowable BPMN Rest API -|流程servlet的名字。 - -|flowable.process.servlet.path -|flowable.rest-api-mapping -|/process-api -|流程REST servlet的上下文路径。 - -|flowable.content.storage.create-root -|contentstorage.fs.create-root -|true -|如果root目录不存在,是否需要创建它? - -|flowable.content.storage.root-folder -|contentstorage.fs.root-folder -|- -|存储内容文件(任务附件、表单上传文件等)的root目录。 - -|flowable.idm.enabled -|flowable.db-identity-used -|true -|是否启动IDM引擎。 - -|flowable.idm.password-encoder -|security.passwordencoder -|- -|密码加密方式。 - -|flowable.idm.ldap.base-dn -|ldap.basedn -|- -|查询用户及组的基础DN(__标识名 distinguished name__)。如果用户及组使用不同的基础DN,请改用__user-base-dn__及__group-base-dn__。 - -|flowable.idm.ldap.enabled -|ldap.enabled -|false -|是否启用LDAP IDM服务。 - -|flowable.idm.ldap.password -|ldap.password -|- -|连接LDAP系统所用的密码。 - -|flowable.idm.ldap.port -|ldap.port -|-1 -|LDAP系统的端口号。 - -|flowable.idm.ldap.server -|ldap.server -|- -|LDAP系统所在的服务器地址。例如__ldap://localhost__。 - -|flowable.idm.ldap.user -|ldap.user -|- -|连接LDAP系统所用的用户ID。 - -|flowable.idm.ldap.attribute.email -|ldap.attribute.email -|- -|代表用户邮件地址的LDAP属性名。用于查询并将LDAP对象映射至Flowable __org.flowable.idm.api.User__对象。 - -|flowable.idm.ldap.attribute.first-name -|ldap.attribute.firstname -|- -|代表用户名字的LDAP属性名。用于查询并将LDAP对象映射至Flowable __org.flowable.idm.api.User__对象。 - -|flowable.idm.ldap.attribute.group-id -|ldap.attribute.groupid -|- -|代表用户组ID的LDAP属性名。用于查询并将LDAP对象映射至Flowable __org.flowable.idm.api.Group__对象。 - -|flowable.idm.ldap.attribute.group-name -|ldap.attribute.groupname -|- -|代表用户组名称的LDAP属性名。用于查询并将LDAP对象映射至Flowable __org.flowable.idm.api.Group__对象。 - -|flowable.idm.ldap.attribute.last-name -|ldap.attribute.lastname -|- -|代表用户姓的LDAP属性名。用于查询并将LDAP对象映射至Flowable __org.flowable.idm.api.User__对象。 - -|flowable.idm.ldap.attribute.user-id -|ldap.attribute.userid -|- -|代表用户ID的LDAP属性名。用于查询并将LDAP对象映射至Flowable __org.flowable.idm.api.User__对象。仅在使用Flowable API查询__org.flowable.idm.api.User__对象时需要设置。 - -|flowable.idm.ldap.cache.group-size -|ldap.cache.groupsize -|-1 -|设置__org.flowable.ldap.LDAPGroupCache__缓存的尺寸。 -这是用户所在组的LRU缓存。避免每次需要查询用户所在组时都访问LDAP系统。 -若值小于0,则不会启用缓存。默认值为-1,所以不会进行缓存。 -请注意组缓存在__org.flowable.ldap.LDAPIdentityServiceImpl__中初始化。 -因此,自行实现__org.flowable.ldap.LDAPIdentityServiceImpl__时,请不要忘记添加组缓存功能。 - -|flowable.idm.ldap.query.all-groups -|ldap.query.groupall -|- -|查询所有组所用的语句。 - -|flowable.idm.ldap.query.all-users -|ldap.query.userall -|- -|查询所有用户所用的语句。 - -|flowable.idm.ldap.query.groups-for-user -|ldap.query.groupsforuser -|- -|查询给定用户所在组所用的语句。 - 比如:`(&(objectClass=groupOfUniqueNames)(uniqueMember={0}))` - 返回LDAP中所有__groupOfUniqueNames__类、DN为__uniqueMember__的对象。 - 上例中,使用{@link java.text.MessageFormat}即__{0}__注入用户ID。 - 如果不能通过简单的语句进行查询,可以改用 `org.flowable.ldap.LDAPQueryBuilder` ,进行定制化查询。 - -|flowable.idm.ldap.query.user-by-full-name-like -|ldap.query.userbyname -|- -|通过全名查询用户所用的语句。 - 比如:`(&(objectClass=inetOrgPerson)(\|({0}=**{1}**)({2}={3})))` - 返回LDAP中所有__inetOrgPerson__类、姓或名匹配的对象。 - 注入到表达式中的值:{0} : 名字属性名 {1} : 查询文本 {2} : 姓属性名 {3} : 查询文本 - 如果不能通过简单的语句进行查询,可以改用 `org.flowable.ldap.LDAPQueryBuilder`,进行定制化查询。 - -|flowable.idm.ldap.query.user-by-id -|ldap.query.userbyid -|- -|通过ID查询用户所用的语句。 - 比如:`(&(objectClass=inetOrgPerson)(uid={0}))` - 返回LDAP中所有__inetOrgPerson__类、__uid__属性值匹配的对象。 - 上例中,使用{@link java.text.MessageFormat}即__{0}__注入用户ID。 - 如果不能通过简单的语句进行查询,可以改用 `org.flowable.ldap.LDAPQueryBuilder` ,进行定制化查询。 - -|flowable.mail.server.host -|email.host -|localhost -|邮件服务器地址。 - -|flowable.mail.server.password -|email.password -|- -|邮件服务器的密码。 - -|flowable.mail.server.port -|email.port -|1025 -|邮件服务器的端口号。 - -|flowable.mail.server.ssl-port -|email.ssl-port -|1465 -|SSL邮件服务器的端口号。 - -|flowable.mail.server.use-ssl -|email.use-ssl -|false -|是否需要为SMTP协议启用SSL/TLS加密(即SMTPS/POPS)。 - -|flowable.mail.server.use-tls -|email.use-tls -|false -|是否启用STARTTLS加密。 - -|flowable.mail.server.username -|email.username -|- -|邮件服务器的用户名。 - 为空则不进行认证。 - -|flowable.process.definition-cache-limit -|flowable.process-definitions.cache.max -|-1 -|流程定义缓存的最大数量。 - 默认值为-1,即缓存所有流程定义。 -|=============== - -.由Spring Boot管理的旧参数 -[cols="4*",options="header"] -|=============== -|参数名 -|原参数 -|默认值 -|描述 - -|spring.datasource.driver-class-name -|datasource.driver -|- -|JDBC驱动的全限定名。默认通过URL自动检测。 - -|spring.datasource.jndi-name -|datasource.jndi.name -|- -|数据源的JNDI。若设置JNDI,则忽略Class、url、username及password设置。 - -|spring.datasource.password -|datasource.password -|- -|数据库的登录密码。 - -|spring.datasource.url -|datasource.url -|- -|数据库的JDBC URL。 - -|spring.datasource.username -|datasource.username -|- -|数据库的登录用户名 - -|spring.datasource.hikari.connection-test-query -|datasource.preferred-test-query -|- -|用于验证连接的SQL语句。 - -|spring.datasource.hikari.connection-timeout -|datasource.connection.timeout -|- -|客户端等待获取连接的最大时间,以毫秒计。如果获取连接超时,会抛出SQLException。 - -|spring.datasource.hikari.idle-timeout -|datasource.connection.idletimeout -|- -|连接池中连接的最大空闲时间,以毫秒计。 - 实际销毁连接前,会多等平均+15秒,最大+30秒的额外时间。 - 不会在空闲超时前销毁连接。 - 值为0代表连接池不会销毁空闲连接。 - -|spring.datasource.hikari.max-lifetime -|datasource.connection.maxlifetime -|- -|连接池中连接的最大存活时间。如果连接超过存活时间,即使该连接刚被使用过,也会被连接池销毁。不会销毁正在使用的连接,只会销毁空闲的连接。 - -|spring.datasource.hikari.maximum-pool-size -|datasource.connection.maxpoolsize -|- -|连接池的最大容量,包括空闲及使用中的连接。这个配置决定了到数据库的实际连接数。如果连接池尺寸到达上限,且没有可用的空闲连接,则getConnection()会等待connectionTimeout设置的时间,然后超时。 - -|spring.datasource.hikari.minimum-idle -|datasource.connection.minidle -|- -|HikariCP连接池保留的最小空闲连接数量。如果空闲连接数量少于设置,HikariCP会尽最大努力尽快有效地恢复。 - -|spring.servlet.multipart.max-file-size -|file.upload.max.size -|10MB -|文件的最大尺寸,可以使用“MB”或“KB”后缀。 -|=============== - - -.不再使用的旧参数 -[cols="2*",options="header"] -|=============== -|旧参数 -|描述 - -|datasource.jndi.resource-ref -|Spring Boot不支持配置JNDI resourceRef,而是按名称直接引用。 - -|email.use-credentials -|如果邮件服务器不使用认证,直接将用户名及密码置空即可。 -|=============== - - -[[flowableIDMApp]] - -=== Flowable IDM应用 - -Flowable IDM应用,用于其他三个Flowable web应用的认证与授权。因此如果你想要运行Modeler,Task或者Admin应用,就需要运行IDM应用。Flowable IDM应用是一个简单的身份管理应用,目标是为Flowable web应用提供单点登录能力,并提供定义用户、组与权限的能力。 - -IDM应用在启动时启动IDM引擎,并按照配置参数中定义的数据源创建IDM引擎所需的身份表。 - -当Flowable IDM应用部署及启动时,将检查是否在ACT_ID_USER表中有用户。如果没有,将在表中使用 `flowable.common.app.idm-admin.user` 参数创建默认管理员用户。 -同时也会为新创建的管理员用户添加Flowable项目中的所有权限: - -* access-idm: 提供管理用户、组与权限的权限 -* access-admin: 使用户可以登录Flowable Admin应用,管理Flowable引擎,以及访问所有应用的Actuator Endpoint。 -* access-modeler: 提供访问Flowable Modeler应用的权限 -* access-task: 提供访问Flowable Task应用的权限 -* access-rest-api: 提供调用REST API的权限。否则调用会返回403(无权限)HTTP状态码。请注意需要将__flowable.rest.app.authentication-mode__设置为__verify-privilege__,即默认设置。 - -第一次使用admin/test登录link:$$http://localhost:8080/flowable-idm$$[http://localhost:8080/flowable-idm]时,会显示如下用户总览界面: - -image::images/flowable_idm_startup_screen.png[align="center"] - -在这个界面中,可以添加、删除与更新用户。组页签用于创建、删除与更新组。在组详情界面中,可以向组添加与删除用户。权限界面为用户与组添加及删除权限: - -image::images/flowable_idm_privilege_screen.png[align="center"] - -暂时还不能定义新的权限。但是可以为用户与组添加及删除已有的四个权限。 - -下表是IDM UI应用的专用参数。 - -.IDM UI应用参数 -[cols="4*",options="header"] -|=============== -|参数名 -|原参数 -|默认值 -|描述 - -|flowable.idm.app.bootstrap -|idm.bootstrap.enabled -|true -|是否为IDM应用启用bootstrap。 - -|flowable.idm.app.rest-enabled -|rest.idm-app.enabled -|true -|启用REST API(指的是使用基础身份认证的API,而不是UI使用的REST API)。 - -|flowable.idm.app.admin.email -|admin.email -|- -|admin用户的邮箱。 - -|flowable.idm.app.admin.first-name -|admin.firstname -|- -|admin用户的名字。 - -|flowable.idm.app.admin.last-name -|admin.lastname -|- -|admin用户的姓。 - -|flowable.idm.app.admin.password -|admin.password -|- -|admin用户的密码。 - -|flowable.idm.app.admin.user-id -|admin.userid -|- -|admin用户的ID。 - -|flowable.idm.app.security.remember-me-key -|security.rememberme.key -|testKey -|Spring Security对密码加密时所用的哈希值。请一定要修改这个参数。 - -|flowable.idm.app.security.user-validity-period -|cache.users.recheck.period -|30000 -|对于可缓存的CustomUserDetailsService服务,缓存用户的时间。 - -|flowable.idm.app.security.cookie.domain -|security.cookie.domain -|- -|cookie的域。 - -|flowable.idm.app.security.cookie.max-age -|security.cookie.max-age -|2678400 -|cookie的存活时间,以秒记。默认为31天。 - -|flowable.idm.app.security.cookie.refresh-age -|security.cookie.refresh-age -|86400 -|cookie的刷新周期,以秒记。默认为1天。 -|=============== - -除了使用默认的身份表之外,IDM应用也可以使用LDAP服务。 -在application.properties文件中(或使用其他配置方式)加入下列配置: - -[source,linenums] ----- -# -# LDAP -# -flowable.idm.ldap.enabled=true -flowable.idm.ldap.server=ldap://localhost -flowable.idm.ldap.port=10389 -flowable.idm.ldap.user=uid=admin, ou=system -flowable.idm.ldap.password=secret -flowable.idm.ldap.base-dn=o=flowable -flowable.idm.ldap.query.user-by-id=(&(objectClass=inetOrgPerson)(uid={0})) -flowable.idm.ldap.query.user-by-full-name-like=(&(objectClass=inetOrgPerson)(|({0}=*{1}*)({2}=*{3}*))) -flowable.idm.ldap.query.all-users=(objectClass=inetOrgPerson) -flowable.idm.ldap.query.groups-for-user=(&(objectClass=groupOfUniqueNames)(uniqueMember={0})) -flowable.idm.ldap.query.all-groups=(objectClass=groupOfUniqueNames) -flowable.idm.ldap.attribute.user-id=uid -flowable.idm.ldap.attribute.first-name=cn -flowable.idm.ldap.attribute.last-name=sn -flowable.idm.ldap.attribute.group-id=cn -flowable.idm.ldap.attribute.group-name=cn -flowable.idm.ldap.cache.group-size=10000 -flowable.idm.ldap.cache.group-expiration=180000 ----- - -`flowable.idm.ldap.enabled` 参数设置为true时,需要同时填入其他的LDAP参数。 -在这个示例配置中使用Apache Directory的服务器配置 + LDAP查询。 -其他LDAP服务器如Active Directory使用不同的配置值。 - -配置LDAP后将通过LDAP服务器进行认证及从组中获取用户,但仍然从Flowable身份表中获取权限。因此需要确保每一个LDAP用户都在IDM应用中定义了正确的权限。 - -如果IDM应用配置为使用LDAP,则启动时将检查Flowable身份表中是否存在权限。 -(第一次启动时)如果没有权限,则会创建4个默认权限,并为ID为(application.properties或其他配置环境中的) `flowable.common.app.idm-admin.user` 参数的用户赋予这4个权限。 -因此请确保 `flowable.common.app.idm-admin.user` 参数设置为有效的LDAP用户,否则将没有人能够登录任何Flowable UI应用。 - -[[flowableModelerApp]] - -=== Flowable Modeler应用 - -Flowable Modeler用于建模BPMN流程、DMN选择表、表单定义,以及创建应用定义。BPMN Modeler使用与Flowable 5相同的Oryx与Angular架构,只是迁移为独立的Modeler应用中。在使用Flowable Modeler应用时,请确保Flowable IDM应用已经部署并正常运行(用于认证与授权)。 - -使用自己的账户(或者默认的admin/test用户)登录Modeler应用后(link:$$http://localhost:8080/flowable-modeler$$[http://localhost:8080/flowable-modeler]),可以看到流程总览页面。可以点击Create Process(创建流程)按钮或Import Process(导入流程)按钮,创建新的BPMN流程模型。 - -image::images/flowable_modeler_createmodel_popup.png[align="center", width="600"] - -在创建流程模型(以及其他模型)时,需要谨慎选择模型key。模型key是模型仓库中该模型的唯一标识。如果使用了已经存在的模型key,则会显示错误,模型也不会保存。 - -在弹出窗口中创建模型后,会显示BPMN模型画布。这个BPMN编辑器与Flowable 5中(作为Explorer的组件)的BPMN编辑器十分相像。在设计流程模型时,可以使用Flowable引擎支持的所有BPMN元素。 - -image::images/flowable_modeler_design_screen.png[align="center"] - -BPMN编辑器分为4个部分: - -* 画板(Palette): 用于设计流程模型的所有BPMN元素 -* 工具条(Toolbar): 修改模型画布的操作。如缩放、布局、保存等 -* 模型画布(Model canvas): 在模型画布上拖放BPMN元素,设计流程模型 -* 参数面板(Properties panel): 如果没有选择元素,则显示主流程模型的参数;否则显示所选中BPMN元素的参数 - -用户任务元素的参数面板中有一个__Referenced form(引用表单)__参数。选择这个参数会弹出窗口,使你可以在仓库中选择一个表单定义,或者创建一个新的表单。如果选择创建一个新的表单,会显示一个类似于流程模型创建对话框的弹窗。填入表单名及表单模型key之后,就会打开表单编辑器。 - -image::images/flowable_modeler_formdesign_screen.png[align="center"] - -可以从表单画板中将表单字段拖入表单画布。在这个例子中,在表单画布上添加了一个Name(姓名)文本框,两个日期框,以及一个Remarks(说明)多行文本框。在编辑表单字段时,可以配置Label(标签)、Id、Required(是否必填),以及Placeholder(占位符)。 - -image::images/flowable_modeler_editfield_popup.png[align="center", width="600"] - -id是一个重要的参数。流程使用这个id为表单字段创建流程变量。填写label参数时,会自动为id参数赋值。如果需要的话,也可以选中Override Id?(覆盖Id)复选框,并填入所需的id。 - -保存表单模型并关闭表单编辑器之后,(如果表单编辑器是从BPMN编辑器打开的话)会自动跳转回流程模型。再次选择用户任务元素,并点击__Referenced form__参数,就可以看到已经将新创建的表单定义附加至用户任务。点击Modeler应用头部的__Form(表单)__页签,也可以看到模型仓库中保存的所有表单定义。 - -image::images/flowable_modeler_formoverview_screen.png[align="center"] - -可以打开表单定义的详情界面,查看各表单定义。在详情页面中,可以修改表单名、key及描述,也可以查阅表单模型的修改历史。也可以复制表单定义,创建一个具有相同表单字段的新的表单定义。 - -接下来,再次打开BPMN编辑器中的vacation request(请假)流程模型,向流程模型中添加一个脚本任务,用于计算假期开始到结束之间的日数。点击__Script form(脚本表单)__参数,填入__groovy__,这样Flowable引擎就会使用Groovy脚本引擎。然后点击__Script(脚本)__参数,并填入用于计算日数的脚本。 - -image::images/flowable_modeler_script_popup.png[align="center", width="600"] - -这样就定义了__amountOfVacationDays__流程变量,接下来可以在流程模型中添加一个选择任务(Decision task)。选择任务用于在Flowable DMN引擎中执行DMN选择表。使用__Decision table reference(引用选择表)__参数,创建一个新的选择表模型,并打开DMN编辑器。 - -image::images/flowable_modeler_dmneditor_screen.png[align="center"] - -DMN编辑器提供了一个列表式的编辑器。包括输入列——使用流程中的流程变量定义输入条件;以及输出列——定义输出变量。在这个简单的例子里,只使用一个输入列,并使用__amountOfVacationDays__变量。如果天数少于10,__managerApprovalNeeded__变量返回值false。否则返回true。可以定义多个输入列,每条规则也可以有多个输入条件。也可以将一个输入列置空,代表其永远为true。也可以定义一个或多个输出变量。 - -DMN选择表定义的另一个重要部分是命中策略(Hit Policy)。目前,Flowable支持第一(First)与任意(Any)命中策略。对于第一命中策略,DMN会返回第一条计算为true的规则定义的输出变量,并停止计算。对于任意命中策略,会计算所有的规则,并输出计算为true的最后一条规则定义的输出变量。 - -保存并关闭DMN编辑器后,Modeler应用跳转回BPMN编辑器,并将新创建的DMN选择表附加至选择任务。在BPMN XML中生成如下的选择任务: - -[source,xml,linenums] ----- - - - - - - - ----- - -这样就可以创建带有一个条件顺序流的排他网关,以使用DMN引擎的计算结果,即__managerApprovalNeeded__变量。 - -image::images/flowable_modeler_sequenceflowcondition_popup.png[align="center", width="500"] - -完整的BPMN流程模型为: - -image::images/flowable_modeler_vacationrequest_screen.png[align="center"] - -完成流程模型之后,就可以创建应用定义(app definition),将一个或多个流程模型及关联的模型(如选择表和表单定义)打包为一个整体。应用定义可以导出为BAR文件(zip格式),并可以在Flowable引擎中部署。创建完成请假应用定义后,应用编辑器将如下显示。 - -image::images/flowable_modeler_appeditor_screen.png[align="center"] - -还可以在应用编辑器中选择图标和主题色,调整Flowable Task应用在看板(dashboard)中的显示效果。重点步骤是添加请假流程模型,并通过选择流程模型,自动引入对应的表单定义和DMN选择表。 - -image::images/flowable_modeler_modelselection_popup.png[align="center"] - -点击预览图选中流程模型。选择一个或多个模型之后,就可以关闭弹窗,保存并关闭应用定义。在详情页面查看新创建的请假应用定义,如下所示: - -image::images/flowable_modeler_appdetails_screen.png[align="center"] - -在这个页面中,可以通过两种不同格式下载应用定义。第一个下载按钮(带有下箭头)下载每个模型的JSON格式模型文件,用于在不同的Flowable Modeler应用之间共享应用定义。第二个下载按钮(带有指向右上的箭头)下载应用定义模型的BAR文件,用于在Flowable引擎中部署。在BAR文件中,只包含了可以部署的工件,如BPMN 2.0 XML文件和DMN XML文件,而不会包含JSON模型文件。这是因为在Flowable引擎部署时,BAR文件中的所有文件都会保存在数据库中。因此需要避免将不需要部署的文件放在BAR中。 - - -在应用定义详情页面,也可以直接向Flowable引擎__发布(Publish)__应用定义。Flowable Modeler使用application.properties文件中,__flowable.modeler.app.deployment-api-url__参数设置的URL部署应用定义。默认部署URL配置为Flowable Task应用。但也可以修改,比如改为使用Flowable REST应用。确保Flowable Task应用正在运行,点击__Publish__按钮。这样应用定义就会做为一个BAR文件部署到Flowable Task应用。 - -下表是Modeler UI应用的专用参数。 - -.Modeler UI应用参数 -[cols="4*",options="header"] -|=============== -|参数名 -|原参数 -|默认值 -|描述 - -|flowable.modeler.app.data-source-prefix -|datasource.prefix -|- -|数据库表名的前缀。 - -|flowable.modeler.app.deployment-api-url -|deployment.api.url -|http://localhost:8080/flowable-task/process-api -|Flowable引擎REST服务的根URL,Flowable Modeler用来向引擎部署应用定义BAR文件。 - Flowable Task应用的默认URL为 - http://localhost:8080/flowable-task/process-api - -|flowable.modeler.app.rest-enabled -|rest.modeler-app.enabled -|true -|启用REST API(指的是使用基础身份认证的API,而不是UI使用的REST API)。 -|=============== - - -[[flowableTaskApp]] - -=== Flowable Task应用 - -Flowable Task应用是Flowable项目的运行时应用,默认包括Flowable BPMN、DMN、Form以及Content引擎。可以使用Flowable Task应用,启动新流程实例、完成任务、渲染任务表单等。在之前的章节中,已经通过Flowable Task应用REST API在Flowable引擎中部署了请假应用定义。在Flowable数据库中可以看到BPMN引擎的ACT_RE_DEPLOYMENT表中已经创建了新的部署实体。DMN引擎的ACT_DMN_DEPLOYMENT,和Form引擎的ACT_FO_FORM_DEPLOYMENT表中也创建了新的实体。 - -在link:$$http://localhost:8080/flowable-task$$[http://localhost:8080/flowable-task]的看板中,可以看到请假应用及默认的Task应用,和其他已经在Flowable引擎中部署的应用。 - -image::images/flowable_task_dashboard_screen.png[align="center"] - -点击请假应用,会显示当前登录用户的任务列表(现在很可能是空的)。 - -image::images/flowable_task_tasklist_screen.png[align="center"] - -点击打开__Processes(流程)__页签后,可以点击__Start a process(启动流程)__按钮,启动一个新的流程实例。会列表显示当前应用定义上下文中所有可用的流程定义。选择请假流程定义后,可以点击__Start process__按钮,启动一个新的请假流程实例。 - -Flowable Task应用将自动跳转至流程实例详情页面。可以看到已经激活了__Provide vacation information(提供请假信息)__任务。可以添加备注,或者使用__Show diagram(显示流程图)__按钮,图形化显示流程实例状态。 - -image::images/flowable_task_processdetails_screen.png[align="center"] - -转至任务列表,也可以看到这里也列出了__Provide vacation information__任务。这个界面会显示任务详情及渲染的请假信息表单。也可以点击__Show details(显示详情)__按钮,转至详情页面。在详情页面中,可以添加备注,引入用户,为任务添加附件,或者修改任务的到期时间和办理人。 - -image::images/flowable_task_taskdetails_screen.png[align="center"] - -开始填写表单并完成任务。首先,选择间隔超过10天的开始日期和结束日期。这样就可以生成__Manager approval(经理审批)__任务。请假信息表单填写完毕后,点击__Complete(完成)__按钮,Flowable Task应用就会跳转至__Manager approval__任务界面。直接完成这个任务(不需要填写任务表单),流程实例就结束了。 - -返回__Processes__页签,点击__Showing running processes(显示运行中的流程)__选项,可以选择__show completed process instances(显示已完成的流程实例)__。这样就会显示已完成的流程实例列表。点击刚才完成的请假流程,可以看到两个完成的任务。 - -image::images/flowable_task_processhistory_screen.png[align="center"] - -每个任务的完成表单(complete form)都存储在Flowable Form引擎的ACT_FO_FORM_INSTANCE表中。因此,在查看完成的任务时,就可以看到每一个完成表单的数据。 - -image::images/flowable_task_completedform_screen.png[align="center"] - -请确保选择回__showing running processes__,否则就不能看到新启动的流程实例。也可以在任务列表界面进行过滤,选择查找任务名、任务状态,特定流程定义的任务,以及指定的办理人。 - -image::images/flowable_task_taskfilter_screen.png[align="center", width="400"] - -默认情况下,办理人过滤设置为__Tasks where I am involved(我参与的任务)__。这样不会显示用户作为候选人而没有指定为办理人的任务。要显示候选任务,可以选择__Tasks where I am one of the candidates(我参与候选的任务)__。 - -下表是Task UI应用的专用参数。 - -.Task UI应用参数 -[cols="4*",options="header"] -|=============== -|参数名 -|原参数 -|默认值 -|描述 - -|flowable.experimental.debugger.enabled -|debugger.enabled -|false -|是否启用流程调试器。 - -|flowable.task.app.rest-enabled -|rest.task-app.enabled -|true -|启用REST API(指的是使用基础身份认证的API,而不是UI使用的REST API)。 -|=============== - - -[[flowableAdminApp]] - -=== Flowable Admin应用 - -Flowable Admin应用是Flowable项目提供的第四个UI应用。用于查询BPMN、DMN及Form引擎中的部署,也可以显示流程实例的当前状态,包括当前的任务和流程变量。也提供了将任务指派给不同的办理人,以及完成任务的操作。Flowable Admin应用使用REST API与Flowable引擎通信。默认情况下,配置为连接至Flowable Task REST API,但是也可以很容易的修改为连接至Flowable REST应用的REST API。访问link:$$http://localhost:8080/flowable-admin$$[http://localhost:8080/flowable-admin]时会显示配置界面(也可以直接点击Flowable logo右上方的箭头)。 - -image:images/flowable_admin_configuration_screen.png[align="center"] - -每一个引擎都可以配置REST端点的基本认证。每个引擎需要单独配置,因为有可能会分开部署引擎,比如将DMN引擎与BPMN引擎部署在不同的服务器上。 - -如果配置正确,就可以选择__Process Engine(流程引擎)__来管理Flowable BPMN引擎。默认情况下,会显示Flowable BPMN引擎的部署情况。 - -image::images/flowable_admin_deployments_screen.png[align="center"] - -可以使用名字及租户id过滤查找部署。也可以为Flowable引擎部署新的BPMN XML或BAR文件。点击其中一个部署,会显示部署详情界面。 - -image::images/flowable_admin_deploymentdetails_screen.png[align="center"] - -这里会显示部署的详细信息,以及部署中包含的流程定义。也可以删除部署。如果希望删除已部署的应用定义,也可以在Flowable Task应用看板中删除应用定义。点击其中一个流程定义,会显示流程定义详情页面。 - -image::images/flowable_admin_processdefinitiondetails_screen.png[align="center"] - -在流程定义详情页面中,首先显示的是流程实例,以及流程定义中使用的选择表定义和表单定义。请假流程定义有一个关联的选择表,以及一个关联的表单定义。点击选择表定义,就会从Flowable Admin应用跳转至DMN引擎。可以点击__Parent Deployment ID(父部署ID)__链接,返回流程引擎。 - -除了部署与定义之外,还可以查询流程引擎中的流程实例、任务、作业,以及事件订阅情况。界面与前面介绍的类似。 - -下表是Admin UI应用的专用参数。 - -.Admin UI应用参数 -[cols="4*",options="header"] -|=============== -|参数名 -|原参数 -|默认值 -|描述 - -|flowable.admin.app.data-source-prefix -|datasource.prefix -| -|数据库表名的前缀。 - -|flowable.admin.app.security.encryption.credentials-i-v-spec -|security.encryption.credentials-i-v-spec -|- -|创建IvParameterSpec对象所用的bytes。 - -|flowable.admin.app.security.encryption.credentials-secret-spec -|security.encryption.credentials-secret-spec -|- -|创建SecretKeySpec对象所用的bytes。 -|=============== - -除了这些参数之外,Flowable Admin应用还有一些其他参数。可以在link:{sc-flowable-ui-admin}/flowable-ui-admin-app/src/main/resources/application.properties[Github]查看配置文件的完整内容。这些参数主要用于为不同的引擎定义REST端点的初始值。 -Admin应用使用这些配置连接Flowable引擎。可以使用Admin应用的配置界面修改这些值。这些值保存在__ACT_ADM_SERVER_CONFIG__表中。 -下面是一个BPMN引擎REST的配置示例: - -[source,linenums] ----- -flowable.admin.app.server-config.process.app.name=Flowable Process app -flowable.admin.app.server-config.process.description=Flowable Process REST config -flowable.admin.app.server-config.process.server-address=http://localhost -flowable.admin.app.server-config.process.app.port=8080 -flowable.admin.app.server-config.process.context-root=flowable-task -flowable.admin.app.server-config.process.rest-root=process-api -flowable.admin.app.server-config.process.app.user=admin -flowable.admin.app.server-config.process.app.password=test ----- - -在Flowable Task应用(及全部Flowable引擎)由Flowable Admin应用管理时,可以使用这些参数。 - -.由Spring Boot管理的Admin UI应用参数 -[cols="2*",options="header"] -|=============== -|原参数 -|描述 - -|message.reloading.enabled -|改为使用Spring Boot MessageSourceAutoConfiguration的 `spring.messages.cache-duration` 设置。 -|=============== - -[[_internationalization]] -=== 国际化 - -Flowable UI应用支持国际化(internationalization, i18n)。项目组维护英语版本。但也可以使用自己的翻译文件支持其他语言。 - -link:$$https://github.com/angular-translate/angular-translate[Angular Translate]库会试着基于浏览器的语言代码,从(每一个UI应用的)__i18n__目录下载入对应的语言文件。如果无法加载匹配的语言文件,框架会退回使用英语版本。 - -也可以(在Angular应用配置中),将多个浏览器语言代码关联至某个翻译文件: - - -[source,linenums] ----- -// 初始化angular-translate -$translateProvider.useStaticFilesLoader({ - prefix: './i18n/', - suffix: '.json' -}) -/* - 将多个浏览器语言代码映射至同一个翻译。 -*/ -// .registerAvailableLanguageKeys(['en'], { -// 'en-*': 'en' -// }) -.useCookieStorage() -.useSanitizeValueStrategy('sanitizeParameters') -.uniformLanguageTag('bcp47') -.determinePreferredLanguage(); ----- - -例如,如果浏览器配置为使用英语(美国)——English (United States),即语言代码为__en-US__。如果不做映射配置,Angular Translate会尝试获取对应的语言文件__en-US.json__。(如果无法加载,会退回为__en__,并加载__en.json__语言文件) - -取消注释__.registerAvailableLanguageKeys__块,就可以将__en-US__(以及所有其他的__en__语言代码)映射至__en.json__语言文件。 - -[[_production_ready_endpoints]] -=== 生产可用的端点 - -所有应用都可以使用Spring Boot提供的link:$$https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html$$[生产可用的端点]。参阅link:$$https://docs.spring.io/spring-boot/docs/current/actuator-api/html/$$[Actuator Web API Documentation]了解所有可用的端点。 - -默认使用下列配置: - -[source,linenums] ------ -# 暴露所有Actuator Endpoint -# 尽管会暴露所有的端点,但非认证用户无法访问,认证用户可以访问/info及/health,只有具有access-admin权限的用户可以访问其他端点 -management.endpoints.web.exposure.include=* -# 只有认证用户可以访问完整的健康度信息 -management.endpoint.health.show-details=when_authorized -# 只有access-admin角色可以访问完整的健康度信息 -management.endpoint.health.roles=access-admin ------ - -安全策略配置为:只有认证用户可以访问 `info` 及 `health` 端点。 -只有 `access-admin` 角色可以查看 `health` 端点的完整信息。 -只有 `access-admin` 角色可以查看其他的任何端点。 diff --git a/docs/userguide/src/zh_CN/bpmn/ch14-Applications.adoc b/docs/userguide/src/zh_CN/bpmn/ch14-Applications.adoc deleted file mode 100644 index 8f4627468f7..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch14-Applications.adoc +++ /dev/null @@ -1,1033 +0,0 @@ -[[flowableApps]] - -== Flowable applications - -Flowable provides several ui web applications to demonstrate and leverage the functionality provided by the Flowable project: - -* Flowable IDM: an Identity Management application that provides single sign-on authentication functionality for all the Flowable UI applications, and, for users with the IDM administrative privilege, it also provides functionality to manage users, groups and privileges. -* Flowable Modeler: an application that allows users with modeler privileges to model processes, forms, decision tables and application definitions. -* Flowable Task: a runtime task application that provides functionality to start process instances, edit task forms, complete tasks and query on tasks and process instances. -* Flowable Admin: an administrative application that allows users with admin privilege to query the BPMN, DMN, form and content engines and provides several options to change process instances, tasks, jobs and so on. The admin application connects to the engines through the REST API that is deployed together with the Flowable Task app and the Flowable REST app. - -The Flowable IDM is required for all other apps to enable authentication. The WAR files for each app can be deployed to the same servlet container (such as Apache Tomcat), but can also be deployed on different servlet containers. Because the same cookie is used for authentication with each app, the apps need to run on the same domain. - -Flowable also provides the `flowable-rest.war` which contains the Flowable REST API. More about this can be read in the <> chapter. - -The apps are Spring Boot 2.0 based, which means that that the WAR files are actually executable and can be run as a normal standalone applications. -See https://docs.spring.io/spring-boot/docs/current/reference/html/build-tool-plugins-maven-plugin.html#build-tool-plugins-maven-packaging[The Executable Jar Format] in the Spring Boot reference documentation. - - -[[uiAppInstallation]] - -=== Flowable UI Applications installation - -As mentioned before, all four UI apps can be deployed together on the same Tomcat server, and to get started this is probably the easiest approach. You can choose to only install the Modeler app, for example, but make sure the Flowable IDM app is always running/deployed as well. For this installation guide we'll describe the installation of all four apps to a Tomcat server. - -1. Download a recent stable version of link:$$http://tomcat.apache.org$$[Apache Tomcat]. -2. Download the latest stable link:$$http://www.flowable.org/downloads.html$$[Flowable 6 version]. -3. Copy the flowable-admin.war, flowable-idm.war, flowable-modeler.war and flowable-task.war files from the Flowable distribution __wars__ folder to the Tomcat webapps folder. -4. Startup the Tomcat server by running the bin/startup.sh (Mac OS and Linux) or bin/startup.bat (Windows) script. -5. Open a web browser and go to link:$$http://localhost:8080/flowable-modeler$$[http://localhost:8080/flowable-modeler]. - -All Flowable UI apps should now be running with an H2 in-memory database and the following login screen should be shown in your web browser: - -image::images/flowable_idm_login_screen.png[align="center"] - -By default, the Flowable IDM application will create an admin user that has privileges to all the Flowable UI apps. You can login with admin/test and the browser should redirect to the Flowable Modeler application: - -image::images/flowable_modeler_startup_screen.png[align="center"] - -Since the UI apps are Spring Boot executable apps it is possible to run them as standalone applications without the need of an application server. -Starting single application looks like: - -``` -java -jar flowable-idm.war -``` - -Usually, you will want to change the default H2 in-memory database configuration to a MySQL or Postgres (or other persistent database) configuration. -You can do this per app by changing the application.properties file in the _WEB-INF/classes/_ directory of each app. -However, it is easier to use the Spring Boot https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html[Externalized Configuration]. -An example configuration can be found on link:$$https://github.com/flowable/flowable-engine/blob/master/modules/flowable-ui-task/flowable-ui-task-app/src/main/resources/flowable-default.properties$$[Github] -To change the default configuration to MySQL the following changes are needed to the properties file: - -[source,linenums] ----- -spring.datasource.driver-class-name=com.mysql.jdbc.Driver -spring.datasource.url=jdbc:mysql://127.0.0.1:3306/flowable?characterEncoding=UTF-8 -spring.datasource.username=flowable -spring.datasource.password=flowable ----- - -This configuration will expect a flowable database to be present in the MySQL server and the UI apps will automatically generate the necessary database tables. For Postgres the following changes are necessary: - -[source,linenums] ----- -spring.datasource.driver-class-name=org.postgresql.Driver -spring.datasource.url=jdbc:postgresql://localhost:5432/flowable -spring.datasource.username=flowable -spring.datasource.password=flowable ----- - -In addition to changing the configuration, make sure the database driver is available on the classpath. Again, you could do this for every web application separately by adding the driver JAR file to the WEB-INF/lib folder, but you can also copy the JAR file once to the Tomcat lib folder. For MySQL and Postgres the database drivers can be downloaded from: - -* MySQL: link:$$https://dev.mysql.com/downloads/connector/j$$[https://dev.mysql.com/downloads/connector/j] -* Postgres: link:$$https://jdbc.postgresql.org/$$[https://jdbc.postgresql.org/] - -When running the apps as standalone applications the database driver can be added by using the `loader.path` property. - -``` -java -Dloader.path=/location/to/your/driverfolder -jar flowable-idm.war -``` - -See the https://docs.spring.io/spring-boot/docs/current/reference/html/executable-jar.html#executable-jar-property-launcher-features[`PropertiesLauncher` Features] in the Spring Boot reference documentation for more information. - -=== Flowable UI Applications Configurations - -As the Flowable UI apps are Spring Boot applications you can use all the properties Spring Boot provides. -In order to provide custom configuration for the apps have a look at the https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html[Externalized Configuration] section of the Spring Boot documentation. - -[TIP] ------ -You can also use YAML based properties. ------ - -.Common UI App Properties -[cols="4*",options="header"] -|=============== -|Property name -|Old Property -|Default value -|Description - -|flowable.common.app.idm-url -|idm.app.url -|- -|The URL to the IDM application, used for the user info and token info REST GET calls. It's also used as a fallback for the redirect url to the login page in the UI apps. - -|flowable.common.app.idm-redirect-url -|idm.app.redirect.url -|- -|The redirect URL to the IDM application, used for the login redirect when the cookie isn't set or is invalid. - -|flowable.common.app.redirect-on-auth-success -|app.redirect.url.on.authsuccess -|- -|The URL to which the redirect should occur after a successful authentication. - -|flowable.common.app.role-prefix -|- -|ROLE_ -|The default role prefix that needs to be used by Spring Security. - -|flowable.common.app.tenant-id -|- -|- -|The static tenant id used for the DefaultTenantProvider. The modeler app uses this to determine under which tenant id to store and publish models. - When not provided, empty or only contains whitespace it defaults to the user's tenant id if available otherwise it uses no tenant id. - -|flowable.common.app.cache-login-tokens.max-age -|cache.login-tokens.max.age -|30 -|The max age in seconds after which the entry should be invalidated. - -|flowable.common.app.cache-login-tokens.max-size -|cache.login-tokens.max.size -|2048 -|The maximum number of entries that the cache should contain. - -|flowable.common.app.cache-login-users.max-age -|cache.login-users.max.age -|30 -|The max age in seconds after which the entry should be invalidated. - -|flowable.common.app.cache-login-users.max-size -|cache.login-users.max.size -|2048 -|The maximum number of entries that the cache should contain. - -|flowable.common.app.cache-users.max-age -|cache.users.max.age -|30 -|The max age in seconds after which the entry should be invalidated. - -|flowable.common.app.cache-users.max-size -|cache.users.max.size -|2048 -|The maximum number of entries that the cache should contain. - -|flowable.common.app.idm-admin.password -|idm.admin.password -|- -|The password used for executing the REST calls (with basic auth) to the IDM REST services. Default is test. - -|flowable.common.app.idm-admin.user -|idm.admin.user -|admin -|The username used for executing the REST calls (with basic auth) to the IDM REST services. Default is admin - -|flowable.rest.app.authentication-mode -|rest.authentication.mode -|verify-privilege -|Configures the way user credentials are verified when doing a REST API call: - 'any-user' : the user needs to exist and the password need to match. Any user is allowed to do the call (this is the pre 6.3.0 behavior) - 'verify-privilege' : the user needs to exist, the password needs to match and the user needs to have the 'rest-api' privilege - If nothing set, defaults to 'verify-privilege' -|=============== - - -Some of the old properties have been moved to be managed by the Flowable Spring Boot starter (or Spring Boot itself) - -.Old properties managed by the Flowable Spring Boot Starter -[cols="4*",options="header"] -|=============== -|Property name -|Old Property -|Default value -|Description - -|flowable.async-executor-activate -|engine.process.asyncexecutor.activate -|true -|Whether the async executor should be activated. - -|flowable.database-schema-update -|engine.process.schema.update -|true -|The strategy that should be used for the database schema. - -|flowable.history-level -|engine.process.history.level -|- -|The history level that needs to be used. - -|flowable.process.servlet.name -|flowable.rest-api-servlet-name -|Flowable BPMN Rest API -|The name of the Process servlet. - -|flowable.process.servlet.path -|flowable.rest-api-mapping -|/process-api -|The context path for the Process rest servlet. - -|flowable.content.storage.create-root -|contentstorage.fs.create-root -|true -|If the root folder doesn't exist, should it be created? - -|flowable.content.storage.root-folder -|contentstorage.fs.root-folder -|- -|Root folder location where content files will be stored, for example, task attachments or form file uploads. - -|flowable.idm.enabled -|flowable.db-identity-used -|true -|Whether the idm engine needs to be started. - -|flowable.idm.password-encoder -|security.passwordencoder -|- -|The type of the password encoder that needs to be used. - -|flowable.idm.ldap.base-dn -|ldap.basedn -|- -|The base 'distinguished name' (DN) from which the searches for users and groups are started. Use 'user-base-dn' or 'group-base-dn' when needing to differentiate between user and group base DN. - -|flowable.idm.ldap.enabled -|ldap.enabled -|false -|Whether to enable LDAP IDM Service. - -|flowable.idm.ldap.password -|ldap.password -|- -|The password that is used to connect to the LDAP system. - -|flowable.idm.ldap.port -|ldap.port -|-1 -|The port on which the LDAP system is running. - -|flowable.idm.ldap.server -|ldap.server -|- -|The server host on which the LDAP system can be reached. For example 'ldap://localhost'. - -|flowable.idm.ldap.user -|ldap.user -|- -|The user id that is used to connect to the LDAP system. - -|flowable.idm.ldap.attribute.email -|ldap.attribute.email -|- -|Name of the attribute that matches the user email. -This property is used when looking for an 'org.flowable.idm.api.User' object and the mapping between the LDAP object and the Flowable 'org.flowable.idm.api.User' object is done. - -|flowable.idm.ldap.attribute.first-name -|ldap.attribute.firstname -|- -|Name of the attribute that matches the user first name. -This property is used when looking for a 'org.flowable.idm.api.User' object and the mapping between the LDAP object and the Flowable 'org.flowable.idm.api.User' object is done. - -|flowable.idm.ldap.attribute.group-id -|ldap.attribute.groupid -|- -|Name of the attribute that matches the group id. -This property is used when looking for a 'org.flowable.idm.api.Group' object and the mapping between the LDAP object and the Flowable 'org.flowable.idm.api.Group' object is done. - -|flowable.idm.ldap.attribute.group-name -|ldap.attribute.groupname -|- -|Name of the attribute that matches the group name. -This property is used when looking for a 'org.flowable.idm.api.Group' object and the mapping between the LDAP object and the Flowable 'org.flowable.idm.api.Group' object is done. - -|flowable.idm.ldap.attribute.last-name -|ldap.attribute.lastname -|- -|Name of the attribute that matches the user last name. -This property is used when looking for a 'org.flowable.idm.api.User' object and the mapping between the LDAP object and the Flowable 'org.flowable.idm.api.User' object is done. - -|flowable.idm.ldap.attribute.user-id -|ldap.attribute.userid -|- -|Name of the attribute that matches the user id. -This property is used when looking for a 'org.flowable.idm.api.User' object and the mapping between the LDAP object and the Flowable 'org.flowable.idm.api.User' object is done. This property is optional and is only needed if searching for 'org.flowable.idm.api.User' objects using the Flowable API. - -|flowable.idm.ldap.cache.group-size -|ldap.cache.groupsize -|-1 -|Allows to set the size of the 'org.flowable.ldap.LDAPGroupCache'. -This is an LRU cache that caches groups for users and thus avoids hitting the LDAP system each time the groups of a user needs to be known. -The cache will not be instantiated if the value is less then zero. By default set to -1, so no caching is done. -Note that the group cache is instantiated on the 'org.flowable.ldap.LDAPIdentityServiceImpl'. -As such, if you have a custom implementation of the 'org.flowable.ldap.LDAPIdentityServiceImpl', do not forget to add the group cache functionality. - -|flowable.idm.ldap.query.all-groups -|ldap.query.groupall -|- -|The query that is executed when searching for all groups. - -|flowable.idm.ldap.query.all-users -|ldap.query.userall -|- -|The query that is executed when searching for all users. - -|flowable.idm.ldap.query.groups-for-user -|ldap.query.groupsforuser -|- -|The query that is executed when searching for the groups of a specific user. - For example: `(&(objectClass=groupOfUniqueNames)(uniqueMember={0}))` - Here, all the objects in LDAP with the class 'groupOfUniqueNames' and where the provided DN is a 'uniqueMember' are returned. - As shown in the example, the user id is injected by the typical {@link java.text.MessageFormat}, ie by using _{0}_ - If setting the query alone is insufficient for your specific LDAP setup, you can alternatively plug in a different - `org.flowable.ldap.LDAPQueryBuilder`, which allows for more customization than only the query. - -|flowable.idm.ldap.query.user-by-full-name-like -|ldap.query.userbyname -|- -|The query that is executed when searching for a user by full name. - For example: `(&(objectClass=inetOrgPerson)(\|({0}=**{1}**)({2}={3})))` - Here, all the objects in LDAP with the class 'inetOrgPerson' and who have the matching first name or last name will be returned - Several things will be injected in the expression: {0} : the first name attribute {1} : the search text {2} : the last name attribute {3} : the search text - If setting the query alone is insufficient for your specific LDAP setup, you can alternatively plug in a different - 'org.flowable.ldap.LDAPQueryBuilder', which allows for more customization than only the query. - -|flowable.idm.ldap.query.user-by-id -|ldap.query.userbyid -|- -|The query that is executed when searching for a user by userId. - For example: `(&(objectClass=inetOrgPerson)(uid={0}))` - Here, all the objects in LDAP with the class 'inetOrgPerson' and who have the matching 'uid' attribute value will be returned. - As shown in the example, the user id is injected by the typical {@link java.text.MessageFormat}, ie by using _{0}_ - If setting the query alone is insufficient for your specific LDAP setup, you can alternatively plug in a different - 'org.flowable.ldap.LDAPQueryBuilder', which allows for more customization than only the query. - -|flowable.mail.server.host -|email.host -|localhost -|The host of the mail server. - -|flowable.mail.server.password -|email.password -|- -|The password for the mail server authentication. - -|flowable.mail.server.port -|email.port -|1025 -|The port of the mail server. - -|flowable.mail.server.ssl-port -|email.ssl-port -|1465 -|The SSL port of the mail server. - -|flowable.mail.server.use-ssl -|email.use-ssl -|false -|Sets whether SSL/TLS encryption should be enabled for the SMTP transport upon connection (SMTPS/POPS). - -|flowable.mail.server.use-tls -|email.use-tls -|false -|Set or disable the STARTTLS encryption. - -|flowable.mail.server.username -|email.username -|- -|The username that needs to be used for the mail server authentication. - If empty no authentication would be used. - -|flowable.process.definition-cache-limit -|flowable.process-definitions.cache.max -|-1 -|The maximum amount of process definitions available in the process definition cache. - Per default it is -1 (all process definitions). -|=============== - -.Old properties managed by Spring Boot -[cols="4*",options="header"] -|=============== -|Property name -|Old Property -|Default value -|Description - -|spring.datasource.driver-class-name -|datasource.driver -|- -|Fully qualified name of the JDBC driver. Auto-detected based on the URL by default. - -|spring.datasource.jndi-name -|datasource.jndi.name -|- -|JNDI location of the datasource. Class, url, username & password are ignored when - set. - -|spring.datasource.password -|datasource.password -|- -|Login password of the database. - -|spring.datasource.url -|datasource.url -|- -|JDBC URL of the database. - -|spring.datasource.username -|datasource.username -|- -|Login username of the database. - -|spring.datasource.hikari.connection-test-query -|datasource.preferred-test-query -|- -|The SQL query to be executed to test the validity of connections. - -|spring.datasource.hikari.connection-timeout -|datasource.connection.timeout -|- -|The maximum number of milliseconds that a client will wait for a connection from the pool. If this time is exceeded without a connection becoming available, a SQLException will be thrown when getting a connection. - -|spring.datasource.hikari.idle-timeout -|datasource.connection.idletimeout -|- -|The maximum amount of time (in milliseconds) that a connection is allowed to sit idle in the pool. -Whether a connection is retired as idle or not is subject to a maximum variation of +30 seconds, and average variation of +15 seconds. -A connection will never be retired as idle before this timeout. -A value of 0 means that idle connections are never removed from the pool. - -|spring.datasource.hikari.max-lifetime -|datasource.connection.maxlifetime -|- -|This property controls the maximum lifetime of a connection in the pool. When a connection reaches this -timeout, even if recently used, it will be retired from the pool. An in-use connection will never be -retired, only when it is idle will it be removed. - -|spring.datasource.hikari.maximum-pool-size -|datasource.connection.maxpoolsize -|- -|The property controls the maximum size that the pool is allowed to reach, including both idle and in-use -connections. Basically this value will determine the maximum number of actual connections to the database -backend. -When the pool reaches this size, and no idle connections are available, calls to getConnection() will -block for up to connectionTimeout milliseconds before timing out. - -|spring.datasource.hikari.minimum-idle -|datasource.connection.minidle -|- -|The property controls the minimum number of idle connections that HikariCP tries to maintain in the pool, -including both idle and in-use connections. If the idle connections dip below this value, HikariCP will -make a best effort to restore them quickly and efficiently. - -|spring.servlet.multipart.max-file-size -|file.upload.max.size -|10MB -|Max file size. Values can use the suffixes "MB" or "KB" to indicate megabytes or kilobytes, respectively. -|=============== - - -.Not used old properties -[cols="2*",options="header"] -|=============== -|Old property -|Description - -|datasource.jndi.resource-ref -|Spring Boot does not support configuring JNDI resourceRef. Use entire resource reference in the name. - -|email.use-credentials -|In case you don't want to use credentials, set the password and user to empty. -|=============== - - - -[[flowableIDMApp]] - -=== Flowable IDM application - -The Flowable IDM application is used by all other three Flowable web applications for authentication and authorization and is therefore required to be available when you want to run the Modeler, Task or Admin application. The Flowable IDM application is a simple identity management application and is targeted at providing single sign-on capabilities to the Flowable web applications, including providing a central place to define users, groups and privileges. - -The IDM application boots the IDM engine at startup and will create the identity tables as defined in the IDM engine in the datasource defined in the properties configuration. - -When the Flowable IDM application is deployed and started, it will check if there's a user available in the ACT_ID_USER table, and if not it will use the `flowable.common.app.idm-admin.user` property to create a new default admin user in this table. -It will also add all available privileges in the Flowable project to the newly created admin user: - -* access-idm: provides the privilege to manage users, groups and privileges -* access-admin: allows the user to login to the Flowable Admin application, manage the Flowable engines and access the Actuator endpoints of all the applications -* access-modeler: enables access to the Flowable Modeler application -* access-task: provides the privilege to login to the Flowable Task application -* access-rest-api: allows the user to do call the REST API. Otherwise a 403 (forbidden) http status will be returned. Note that _flowable.rest.app.authentication-mode_ nees to be set to _verify-privilege_, which is the default. - -When logging in to link:$$http://localhost:8080/flowable-idm$$[http://localhost:8080/flowable-idm] with admin/test for the first time the following user overview screen is shown: - -image::images/flowable_idm_startup_screen.png[align="center"] - -In this screen users can be added, removed and updated. The groups section can be used to create, delete and update groups. In the group details view you can also add and remove users to and from the group. The privilege screen allows you to add and remove privileges from users and groups: - -image::images/flowable_idm_privilege_screen.png[align="center"] - -There's no option to define new privileges yet, but you can add and remove users and groups for the existing four privileges. - -This are the IDM UI App specific properties. - -.IDM UI App Properties -[cols="4*",options="header"] -|=============== -|Property name -|Old Property -|Default value -|Description - -|flowable.idm.app.bootstrap -|idm.bootstrap.enabled -|true -|Whether the IDM App needs to be bootstrapped. - -|flowable.idm.app.rest-enabled -|rest.idm-app.enabled -|true -|Enables the REST API (this is not the REST api used by the UI, but an api that's available over basic auth authentication). - -|flowable.idm.app.admin.email -|admin.email -|- -|The email of the admin user. - -|flowable.idm.app.admin.first-name -|admin.firstname -|- -|The first name of the admin user. - -|flowable.idm.app.admin.last-name -|admin.lastname -|- -|The last name of the admin user. - -|flowable.idm.app.admin.password -|admin.password -|- -|The password for the admin user. - -|flowable.idm.app.admin.user-id -|admin.userid -|- -|The id of the admin user. - -|flowable.idm.app.security.remember-me-key -|security.rememberme.key -|testKey -|The hash key that is used by Spring Security to hash the password values in the applications. Make sure that you change the value of this property. - -|flowable.idm.app.security.user-validity-period -|cache.users.recheck.period -|30000 -|How long should a user be cached before invalidating it in the cache for the cacheable CustomUserDetailsService. - -|flowable.idm.app.security.cookie.domain -|security.cookie.domain -|- -|The domain for the cookie. - -|flowable.idm.app.security.cookie.max-age -|security.cookie.max-age -|2678400 -|The max age of the security cookie in seconds. Default is 31 days. - -|flowable.idm.app.security.cookie.refresh-age -|security.cookie.refresh-age -|86400 -|The refresh age of the cookie in seconds. Default is 1 day. -|=============== - -In addition to the default identity tables, the IDM application can also be configured to use an LDAP server. -To connect to a LDAP server, additional properties in the application.properties file (or any other way of configuring the application) are needed: - -[source,linenums] ----- -# -# LDAP -# -flowable.idm.ldap.enabled=true -flowable.idm.ldap.server=ldap://localhost -flowable.idm.ldap.port=10389 -flowable.idm.ldap.user=uid=admin, ou=system -flowable.idm.ldap.password=secret -flowable.idm.ldap.base-dn=o=flowable -flowable.idm.ldap.query.user-by-id=(&(objectClass=inetOrgPerson)(uid={0})) -flowable.idm.ldap.query.user-by-full-name-like=(&(objectClass=inetOrgPerson)(|({0}=*{1}*)({2}=*{3}*))) -flowable.idm.ldap.query.all-users=(objectClass=inetOrgPerson) -flowable.idm.ldap.query.groups-for-user=(&(objectClass=groupOfUniqueNames)(uniqueMember={0})) -flowable.idm.ldap.query.all-groups=(objectClass=groupOfUniqueNames) -flowable.idm.ldap.query.group-by-id=(&(objectClass=groupOfUniqueNames)(uniqueId={0})) -flowable.idm.ldap.attribute.user-id=uid -flowable.idm.ldap.attribute.first-name=cn -flowable.idm.ldap.attribute.last-name=sn -flowable.idm.ldap.attribute.group-id=cn -flowable.idm.ldap.attribute.group-name=cn -flowable.idm.ldap.cache.group-size=10000 -flowable.idm.ldap.cache.group-expiration=180000 ----- - -When the `flowable.idm.ldap.enabled` property is set to true, the IDM app will expect the other LDAP properties to have been filled-in. -In this example configuration the server configuration + LDAP queries for the Apache Directory Server are provided. -For other LDAP servers, like Active Directory, other configuration values are needed. - -When LDAP is configured, authentication and group retrieval for a user will be done through the LDAP server. Only privileges will still be retrieved from the Flowable identity tables. So make sure each LDAP user has the correct privileges defined in the IDM application. - -If the IDM application is booted with LDAP configuration the bootstrap logic will check if there are already privileges present in the Flowable identity tables. -If there are no privileges (only when booting the first time), the 4 default privileges will be created and the `flowable.idm.app.admin.user-id` property value (from application.properties or configured in the environment) will be used as the user id to get all 4 privileges. -So make sure that the `flowable.idm.app.admin.user-id` property value is set to a valid LDAP user, otherwise nobody will be able to login to any of the Flowable UI apps. - -[[flowableModelerApp]] - -=== Flowable Modeler application - -The Flowable Modeler application can be used to model BPMN processes, DMN decision table, Form definitions and create app definitions. The BPMN modeler uses the same Oryx and Angular foundation as in Flowable 5, but the functionality has now been moved into a separate Modeler application. When using the Flowable Modeler application, make sure the Flowable IDM application is deployed and running as well (for authentication and authorization purposes). - -When you login to the Modeler application (link:$$http://localhost:8080/flowable-modeler$$[http://localhost:8080/flowable-modeler]) with your user (or the default admin/test user), you will see the process overview screen. From here you can start creating new BPMN process models by clicking on the Create Process or Import Process button. - -image::images/flowable_modeler_createmodel_popup.png[align="center", width="600"] - -When creating a process model (but also any other model), it's important to think carefully about the model key value. The model key is a unique identifier for the model across the full model repository. If you choose a model key that already exists in the model repository, an error message is shown and the model is not saved. - -After creating the model with the popup, the BPMN modeling canvas is shown. The BPMN editor is very similar to the Flowable 5 BPMN editor that was part of the Explorer application. All BPMN elements supported by the Flowable engine are available to be used in the design of a process model. - -image::images/flowable_modeler_design_screen.png[align="center"] - -The BPMN editor is divided into 4 parts: - -* Palette: the palette of BPMN elements available to design a process model -* Toolbar: actions to change the model canvas, such as zooming, layout and saving a model -* Model canvas: the modeling canvas on which to drag and drop BPMN elements and design the process model -* Properties panel: the properties for the main process model if no element is select and otherwise the properties of the selected BPMN element - -For a User task element there's a _Referenced form_ property in the properties panel. If you select this property, a popup is opened where you can select a form definition from the repository or create a new form. When creating a new form, a similar create dialog to the process model create dialog is presented. After filling in the name and form model key, the form editor is opened. - -image::images/flowable_modeler_formdesign_screen.png[align="center"] - -Form fields can be dragged from the form palette on to the form canvas. In this example, a name textfield, two date fields and a remarks multiline textfield are added to the form canvas. When editing a form field, the label, id, required status and placeholder can be filled in. - -image::images/flowable_modeler_editfield_popup.png[align="center", width="600"] - -The id field is an important value, because a process variable will be created with the form field value using the id property value. When filling in the label property, the id property is automatically filled. If needed, you can also provide the id property value yourself by checking the override id checkbox. - -After saving the form model and closing the form editor, you are automatically navigated back to the process model (when the form editor was opened via the BPMN editor). When selecting the User task element again and clicking on the _Referenced form_ property you will see that the newly created form definition is now attached to the User task. When clicking on the _Form_ tab in the header of the Modeler application, all form definitions available in the model repository are shown. - -image::images/flowable_modeler_formoverview_screen.png[align="center"] - -You can preview every form definition by opening the details view of a form definition. In the details view, the form name, key and description can be edited and the history of form models is available. You can also duplicate the form definition to create a new form definition with the same form fields. - -Now let's open the vacation request process model in the BPMN editor again and add a Script task to the process model, that will calculate the number of days between the vacation start and end dates. Click on the _Script format_ property and fill in a value of _groovy_ to instruct the Flowable engine to use the Groovy scripting engine. Now click on the _Script_ property and fill in the script that calculates the number of days. - -image::images/flowable_modeler_script_popup.png[align="center", width="600"] - -Now we have a _amountOfVacationDays_ process variable we can add a Decision task to the process model. A decision task can be used to execute a DMN decision table in the Flowable DMN engine. Through the _Decision table reference_ property, a new decision table model can be created and the DMN editor is opened. - -image::images/flowable_modeler_dmneditor_screen.png[align="center"] - -The DMN editor provides a table editor with input columns, where input conditions can be defined with the process variables available in the process context, and output columns, where output variable values can be defined. In this very simple example there's one input column using the _amountOfVacationDays_ variable that checks if it's less than 10 or higher or equal to 10. When the amount of days is less than 10, an output variable _managerApprovalNeeded_ is returned with value false, and otherwise a value of true is returned. You can define multiple input columns and have multiple input conditions per rule. It's also possible to leave an input column empty, which means that it's evaluated to true for that part of the rule. You can define one or multiple output variables. - -Another important part of the DMN decision table definition is the hit policy. Currently, Flowable supports the First and Any hit policy. With the First hit policy, when the first rule is found that evaluates to true the DMN execution will stop and its output variables are returned. For the Any hit policy, all rules will be executed and the output variables for the last rule that evaluates to true are returned. - -When the DMN editor is saved and closed, the Modeler application navigates back to the BPMN editor and the newly created DMN decision table is now attached to the Decision task. The decision task will be generated in the BPMN XML like; - -[source,xml,linenums] ----- - - - - - - - ----- - -With the _managerApprovalNeeded_ variable available in the process instance context, we can now create an exclusive gateway with a sequence flow condition that evaluates the calculated value of the DMN Engine. - -image::images/flowable_modeler_sequenceflowcondition_popup.png[align="center", width="500"] - -The full BPMN process model now looks like this: - -image::images/flowable_modeler_vacationrequest_screen.png[align="center"] - -With the process model completed, we can now create an app definition that combines one or more process models with all their associated models (for example, decision tables and form definitions) into a single artifact. An app definition can be exported as a BAR file (zip format) that can be deployed on the Flowable engine. When creating a vacation request app definition, the app editor will look something like the screen below. - -image::images/flowable_modeler_appeditor_screen.png[align="center"] - -In the app editor, an icon and a theme color can be selected that will be used in the Flowable Task application to show the application in the dashboard. The important step is to add the vacation request process model, and by selecting the process model, automatically include any form definitions and DMN decision tables. - -image::images/flowable_modeler_modelselection_popup.png[align="center"] - -A process model can be selected by clicking on the model thumbnail. When one or more models are selected, you can close the popup, save the app definition and close it. When navigating to the details view of the newly created vacation request app definition, the following details screen is shown: - -image::images/flowable_modeler_appdetails_screen.png[align="center"] - -From this view, you can download the app definition in two different formats. The first download button (with the arrow pointing downwards) can be used to -download the app definition with the JSON model files for each included model. This makes it easy to share app definitions between different Flowable Modeler applications. The second download button (with the arrow point to upper right) will provide a BAR file of the app definition models, which can be deployed on the Flowable engine. In the BAR file, only the deployable artifacts are included, such as the BPMN 2.0 XML file and the DMN XML file, and not the JSON model files. All files in a BAR file deployed on a Flowable engine are stored in the database, so therefore only the deployable files are included. - -From the app definition details view, you can also _Publish_ the app definition directly to the Flowable engine. The Flowable Modeler uses the URL defined in the application.properties file with the _flowable.modeler.app.deployment-api-url_ property key. By default, the deployment URL is configured so the app definition will be deployed on the Flowable Task application when it's running. However, this can be changed to use the Flowable REST application, for example. Make sure the Flowable Task application is running and click on the _Publish_ button. The app definition is now deployed as a BAR file to the Flowable Task application. - -This are the Modeler UI App specific properties. - -.Modeler UI App Properties -[cols="4*",options="header"] -|=============== -|Property name -|Old Property -|Default value -|Description - -|flowable.modeler.app.data-source-prefix -|datasource.prefix -|- -|The prefix for the database tables. - -|flowable.modeler.app.deployment-api-url -|deployment.api.url -|http://localhost:8080/flowable-task/app-api -|The root URI to the REST services of the Flowable engine, used by the Flowable Modeler application to deploy the application definition BAR file to the engine. - Default url for the Flowable Task application is http://localhost:8080/flowable-task/app-api - -|flowable.modeler.app.rest-enabled -|rest.modeler-app.enabled -|true -|Enables the REST API (this is not the REST api used by the UI, but an api that's available over basic auth authentication). -|=============== - - -[[flowableTaskApp]] - -=== Flowable Task application - -The Flowable Task application is the runtime application of the Flowable project and includes the Flowable BPMN, DMN, Form and Content engines by default. With the Flowable Task application, new process instances can be started, tasks can be completed, task forms can be rendered and so on. In the previous section, the vacation request app definition was deployed on the Flowable Task application REST API, and through that deployed on the Flowable engine. If you look in the Flowable database, you can see a new deployment entry has been added to the ACT_RE_DEPLOYMENT table for the BPMN Engine. Also, new entries haven been created in the ACT_DMN_DEPLOYMENT and ACT_FO_FORM_DEPLOYMENT tables for the DMN and Form engines. - -On the dashboard on link:$$http://localhost:8080/flowable-task$$[http://localhost:8080/flowable-task], you can see a vacation request app in addition to the default Task app, and any other apps that have been deployed to the Flowable engine already. - -image::images/flowable_task_dashboard_screen.png[align="center"] - -When clicking on the vacation request app, the task list for the logged-in user is shown (which is probably empty for now). - -image::images/flowable_task_tasklist_screen.png[align="center"] - -When clicking on the _Processes_ tab you can choose to start a new process instance by clicking on the _Start a process_ button. The list of available process definitions within the context of this app definition is now displayed. In the general Task app this works in a similar way, but in the Task app, all process definitions deployed on the Flowable engine are shown. After selecting the vacation request process definition, the _Start process_ button can be clicked to start a new vacation request process instance. - -The Flowable Task application automatically navigates to the process instance details view. You can see the _Provide vacation information_ task is active and, for example, comments can be added and the process instance state can be shown diagrammatically using the _Show diagram_ button. - -image::images/flowable_task_processdetails_screen.png[align="center"] - -When navigating to the task list, you can also see the _Provide vacation information_ task listed there as well. The task details are shown in this view, with the vacation info form being rendered. You can also switch to the details view by clicking on the _Show details_ button. In the details view, comments can be added, users can involved in the task and attachments can be added to the task. You can also change the due date and the assignee of a task. - -image::images/flowable_task_taskdetails_screen.png[align="center"] - -Let's fill in the form and complete the task. First, select a start date and end date that have more than 10 days in between, so we can validate that a -_Manager approval_ task is being generated. After filling in the vacation info form and clicking the _Complete_ button, the Flowable task app navigates directly to the _Manager approval_ task view. When you also complete this task (without a task form), the process instance is completed. - -When navigating to the _Processes_ tab and clicking on the _Showing running processes_ section, you can select an option to show completed process instances. The list of completed process instances is now shown and when clicking on the just completed vacation request process you can see the two completed tasks. - -image::images/flowable_task_processhistory_screen.png[align="center"] - -The completed form of each task is stored in the ACT_FO_FORM_INSTANCE table of the Flowable Form engine. So it's possible to look at the values of each completed form when you navigate to the completed task. - -image::images/flowable_task_completedform_screen.png[align="center"] - -Make sure to switch back to showing running processes instead of the completed ones, otherwise you won't see newly started process instances. You can also filter tasks in the task list view. There are options to search on the name of a task, the task state, only tasks for a specific process definition and change the assignment filter. - -image::images/flowable_task_taskfilter_screen.png[align="center", width="400"] - -By default, the assignment filter is set to _Tasks where I am involved_. This doesn't show the tasks where you are a candidate, such as tasks that are available to a specific candidate group before they are assigned to a specific person. To show candidate tasks you can select the _Tasks where I am one of the candidates_ assignment filter option. - -This are the Task UI App specific properties. - -.Task UI App Properties -[cols="4*",options="header"] -|=============== -|Property name -|Old Property -|Default value -|Description - -|flowable.experimental.debugger.enabled -|debugger.enabled -|false -|Whether the process debugger should be enabled. - -|flowable.task.app.rest-enabled -|rest.task-app.enabled -|true -|Enables the REST API (this is not the REST api used by the UI, but an api that's available over basic auth authentication). - -|flowable.form-field-validation-enabled -| -|false -|Enable form field validation after form submission on the engine side. -|=============== - - -[[flowableAdminApp]] - -=== Flowable Admin application - -The fourth UI application the Flowable project provides is the Flowable Admin application. This application provides ways to, for example, query deployments in the BPMN, DMN and Form Engines, but also shows the active state of a process instance with its active tasks and process variables. It also provides actions to assign a task to a different assignee and to complete an active task. The Flowable Admin application uses the REST API to communicate with the Flowable engines. By default, it is configured to connect to the Flowable Task REST API, but you can easily change this to use the Flowable REST app REST API instead. When going to link:$$http://localhost:8080/flowable-admin$$[http://localhost:8080/flowable-admin], the configuration screen is shown (which is also available by clicking on the arrow at the top right near the Flowable logo). - -image:images/flowable_admin_configuration_screen.png[align="center"] - -For each engine, the REST endpoint can be configured with the basic authentication values. The configuration is done per engine, because it's possible to, for example, deploy the DMN Engine on a separate server from the BPMN Engine. - -When the configuration is defined with the correct values, the _Process Engine_ can be selected to administer the Flowable BPMN engine. By default, the deployments of the Flowable BPMN engine are shown. - -image::images/flowable_admin_deployments_screen.png[align="center"] - -You can filter the deployments based on name and tenant identifier. In this view, it's also possible to deploy a new BPMN XML file or BAR file to the Flowable engine. When clicking on one of the deployments, the deployment details view is shown. - -image::images/flowable_admin_deploymentdetails_screen.png[align="center"] - -More details of a deployment are shown here and also the process definitions that are part of this deployment on which you click to get more details. It's also possible to delete a deployment here. When you want to delete a deployed app definition, this is also the way to delete the app definition from the Flowable Task app dashboard. When clicking on one of the process definitions, the process definition details view is shown. - -image::images/flowable_admin_processdefinitiondetails_screen.png[align="center"] - -In the process definition details view, the first page of process instances is shown, together with optional decision table definitions and form definitions that are used in the process definition. For the vacation request process definition, there's one connected decision table and one connected form definition. Clicking on the decision table definition navigates the Flowable Admin application to the DMN engine. You can always navigate back to the Process engine by clicking on the _Parent Deployment ID_ link. - -In addition to the deployments and definitions, you can also query on process instances, tasks, jobs and event subscriptions in the Process engine. The views all work in a similar way to what's already been described. - -This are the Admin UI App specific properties - -.Admin UI App Properties -[cols="4*",options="header"] -|=============== -|Property name -|Old Property -|Default value -|Description - -|flowable.admin.app.data-source-prefix -|datasource.prefix -| -|The prefix for the database tables. - -|flowable.admin.app.security.encryption.credentials-i-v-spec -|security.encryption.credentials-i-v-spec -|- -|The string that needs to be used to create an IvParameterSpec object using it's the bytes. - -|flowable.admin.app.security.encryption.credentials-secret-spec -|security.encryption.credentials-secret-spec -|- -|The string that needs to be used to create a SecretKeySpec using it's bytes. - -|flowable.admin.app.security.preemptive-basic-authentication -| -|false -|Perform a preemptive basic authentication when issuing requests to the flowable REST API. -**NB:** This is an experimental property and might be removed without notice. -|=============== - -In addition to these properties, the Flowable admin application has a few more properties. The full -content of the properties file can be viewed on {sc-flowable-ui-admin}/flowable-ui-admin-app/src/main/resources/application.properties[Github]. -The additional properties are mainly used for defining the initial values for the REST endpoints for the different engines. -The Admin application uses the initial values to make a connection to the Flowable engines, but the values can be overridden in the Admin application configuration view and these values are stored in the __ACT\_ADM\_SERVER\_CONFIG__ table. -An example of the BPMN Engine REST properties is shown below: - -[source,linenums] ----- -flowable.admin.app.server-config.process.name=Flowable Process app -flowable.admin.app.server-config.process.description=Flowable Process REST config -flowable.admin.app.server-config.process.server-address=http://localhost -flowable.admin.app.server-config.process.port=8080 -flowable.admin.app.server-config.process.context-root=flowable-task -flowable.admin.app.server-config.process.rest-root=process-api -flowable.admin.app.server-config.process.user-name=admin -flowable.admin.app.server-config.process.password=test ----- - -These values can be used when the Flowable Task app (with all the Flowable engines included) is managed by the Flowable Admin application. - -.Admin UI App Properties managed by Spring Boot -[cols="2*",options="header"] -|=============== -|Old property -|Description - -|message.reloading.enabled -|Using Spring Boot MessageSourceAutoConfiguration. Set the duration with `spring.messages.cache-duration`. -|=============== - - -=== Internationalization - -The Flowable UI apps support internationalization (i18n). The project maintains the English translations. It is however possible to provide your own translation files in order to support other languages. - -The link:$$https://github.com/angular-translate/angular-translate[Angular Translate] library tries to load a specific translation file based on the browser's locale located in the _i18n_ folder (present in each UI module). When a matching translation file cannot be loaded the framework will fallback to the English translation. - -Mapping multiple browser locale keys to specific translations additional configuration can be provided (located in the Angular app config); - -[source,linenums] ----- -// Initialize angular-translate -$translateProvider.useStaticFilesLoader({ - prefix: './i18n/', - suffix: '.json' -}) -/* - This can be used to map multiple browser language keys to a - angular translate language key. -*/ -// .registerAvailableLanguageKeys(['en'], { -// 'en-*': 'en' -// }) -.useCookieStorage() -.useSanitizeValueStrategy('sanitizeParameters') -.uniformLanguageTag('bcp47') -.determinePreferredLanguage(); ----- - -For example; your browser is configured for English (United States) and provides the language key _en-US_. Without the mapping Angular Translate will try to fetch the corresponding translation file _en-US.json_. (If this is not available it will fallback to 'en' and load the _en.json_ translation file) - -By uncommenting the _.registerAvailableLanguageKeys_ block you can map _en-US_ (and all other _en_ language keys) to the _en.json_ language file. - -=== Production ready endpoints - -The https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html[Production ready endpoints] from Spring Boot are present for all applications. -To have an overview of all the available Endpoints have a look at the https://docs.spring.io/spring-boot/docs/current/actuator-api/html/[Actuator Web API Documentation]. - -This properties are set per default: - -[source,linenums] ------ -# Expose all actuator endpoints to the web -# They are exposed, but only authenticated users can see /info and /health abd users with access-admin can see the others -management.endpoints.web.exposure.include=* -# Full health details should only be displayed when a user is authorized -management.endpoint.health.show-details=when_authorized -# Only users with role access-admin can access full health details -management.endpoint.health.roles=access-admin ------ - -The security is configured in such way that the `info` and `health` endpoint are exposed to all authenticated users. -Full details of the `health` endpoint can only be seen by users with the privilege `access-admin`. -In case you want to change that you need to configure `management.endpoint.health.show-details`. -All the rest of the endpoints are accessing only to users with the `access-admin` privilege. - -[[custom-bean-deployment]] -=== Custom bean deployment - -There are multiple ways of providing custom beans to the Flowable applications. - - -[[custom-bean-deployment-spring-boot-auto]] -==== Using Spring Boot auto configuration - -The Flowable applications are Spring Boot 2 applications. -Which means that normal Spring Boot auto configuration can be used to make the beans to Flowable. -This can be done in the following manner - -``` -package com.your.own.package.configuration; - -@Configuration -@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE) // Makes sure that this configuration will be processed last by Spring Boot -@ConditionalOnBean(type = "org.flowable.engine.ProcessEngine") // The configuration will only be used when the ProcessEngine bean is present -public class YourOwnConfiguration { - - @Configuration - @ComponentScan ("com.your.own.package.beans") - public static class ComponentScanConfiguration { - // This class is needed in order to conditionally perform the component scan (i.e. when the ProcessEngine bean is present) - // It is an optional class, in case you don't need component scanning then you don't need to do this - } - - @Bean - public CustomBean customBean() { - // create your bean - } - - @Bean - public EngineConfigurationConfigurer customProcessEngineConfigurationConfigurer() { - return engineConfiguration -> { - // You can use this to add extra configuration to the process engine - } - } -} -``` - -Note that when using Spring Boot the configuration class can be under your own package and not under some Flowable package. - -In order to make this class an auto configuration class a file named `org.springframework.boot.autoconfigure.AutoConfiguration.imports` should be created in the `META-INF/spring` folder of your jar. -In this file you should add - -``` -com.your.own.package.configuration.YourOwnCustomConfiguration -``` - -In order to use this approach you would need to include your jar in the `WEB-INF/lib` folder of the exploded war. -Placing this jar in the lib folder of the servlet container (e.g. Tomcat) is not going to work due to the way Spring proxies the `@Configuration` classes. - - -[[custom-bean-deployment-component-scan]] -==== Component scan - -Another way to provide custom Spring beans to the Flowable engine is to put them under a certain package and have the Flowable application component scan that package. -Based on the used application this package is different: - -* `org.flowable.rest.app` for the `flowable-rest.war` -* `org.flowable.ui.task.application` for the `flowable-task.war` - - -The custom beans can be located in a single JAR and this jar should be present on the classpath when the applications are starting up. -Depending where there JAR is placed, the lib folder of the servlet container (e.g. Tomcat) or the `WEB-INF/lib` folder of the exploded war, there are different possibilities. - -When using the lib folder of the servlet container then the created classes should be self contained, i.e. they should only use classes from within the jar. -You can use any of the Spring `@Component` annotations (with the exception of `@Configuration`). -The reason for not being able to use `@Configuration` classes is the fact that each configuration class is proxied by Spring with the help of the `ConfigurationClassPostProcessor`. -However, the classloader loading the `@Configuration` class does not have access to the needed classes by Spring. - -When including the jar in the `WEB-INF/lib` folder of the exploded war then `@Configuration` classes and dependencies to other jars is possible. - -[[custom-bean-deployment-own-spring-boot]] -==== Creating your own Spring Boot application - -This approach is the most flexible and most powerful approach of all. -In order to follow this approach have a look at the <> section of this documentation. \ No newline at end of file diff --git a/docs/userguide/src/zh_CN/bpmn/ch15-REST.adoc b/docs/userguide/src/zh_CN/bpmn/ch15-REST.adoc deleted file mode 100644 index 7ae2c1bf06f..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch15-REST.adoc +++ /dev/null @@ -1,7210 +0,0 @@ - -=== Deployment - -*When using tomcat, please read <>.* - -==== List of Deployments - ----- -GET repository/deployments ----- - -.URL query parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|name|No|String|Only return deployments with the given name. -|nameLike|No|String|Only return deployments with a name like the given name. -|category|No|String|Only return deployments with the given category. -|categoryNotEquals|No|String|Only return deployments which don't have the given category. -|tenantId|No|String|Only return deployments with the given tenantId. -|tenantIdLike|No|String|Only return deployments with a tenantId like the given value. -|withoutTenantId|No|Boolean|If +true+, only returns deployments without a tenantId set. If +false+, the +withoutTenantId+ parameter is ignored. -|sort|No|'id' (default), 'name', 'deployTime' or 'tenantId'|Property to sort on, to be used together with the 'order'. -|The general <> can be used for this URL. - -|=============== - - -.REST Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the request was successful. - -|=============== - -*Success response body:* - -[source,json,linenums] ----- -{ - "data": [ - { - "id": "10", - "name": "flowable-examples.bar", - "deploymentTime": "2010-10-13T14:54:26.750+02:00", - "category": "examples", - "url": "http://localhost:8081/flowable-rest/service/repository/deployments/10", - "tenantId": null - } - ], - "total": 1, - "start": 0, - "sort": "id", - "order": "asc", - "size": 1 -} ----- - -==== Get a deployment - ----- -GET repository/deployments/{deploymentId} ----- - -.Get a deployment - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|deploymentId|Yes|String|The id of the deployment to get. - -|=============== - - -.Get a deployment - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the deployment was found and returned. -|404|Indicates the requested deployment was not found. - -|=============== - -*Success response body:* - -[source,json,linenums] ----- -{ - "id": "10", - "name": "flowable-examples.bar", - "deploymentTime": "2010-10-13T14:54:26.750+02:00", - "category": "examples", - "url": "http://localhost:8081/flowable-rest/service/repository/deployments/10", - "tenantId" : null -} ----- - -==== Create a new deployment - ----- -POST repository/deployments ----- - -*Request body:* - -The request body should contain data of type _multipart/form-data_. There should be exactly one file in the request, any additional files will be ignored. The deployment name is the name of the file-field passed in. If multiple resources need to be deployed in a single deployment, compress the resources in a zip and make sure the file-name ends with +.bar+ or +.zip+. - -An additional parameter (form-field) can be passed in the request body with name +tenantId+. The value of this field will be used as the id of the tenant this deployment is done in. - -.Create a new deployment - Response codes -[options="header"] -|=============== -|Response code|Description -|201|Indicates the deployment was created. -|400|Indicates there was no content present in the request body or the content mime-type is not supported for deployment. The status-description contains additional information. - -|=============== - -*Success response body:* - - -[source,json,linenums] ----- -{ - "id": "10", - "name": "flowable-examples.bar", - "deploymentTime": "2010-10-13T14:54:26.750+02:00", - "category": null, - "url": "http://localhost:8081/flowable-rest/service/repository/deployments/10", - "tenantId" : "myTenant" -} ----- - -==== Delete a deployment - ----- -DELETE repository/deployments/{deploymentId} ----- - -.Delete a deployment - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|deploymentId|Yes|String|The id of the deployment to delete. - -|=============== - - -.Delete a deployment - Response codes -[options="header"] -|=============== -|Response code|Description -|204|Indicates the deployment was found and has been deleted. Response-body is intentionally empty. -|404|Indicates the requested deployment was not found. - -|=============== - - -==== List resources in a deployment - ----- -GET repository/deployments/{deploymentId}/resources ----- - -.List resources in a deployment - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|deploymentId|Yes|String|The id of the deployment to get the resources for. - -|=============== - -.List resources in a deployment - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the deployment was found and the resource list has been returned. -|404|Indicates the requested deployment was not found. - -|=============== - -*Success response body:* - -[source,json,linenums] ----- -[ - { - "id": "diagrams/my-process.bpmn20.xml", - "url": "http://localhost:8081/flowable-rest/service/repository/deployments/10/resources/diagrams%2Fmy-process.bpmn20.xml", - "dataUrl": "http://localhost:8081/flowable-rest/service/repository/deployments/10/resourcedata/diagrams%2Fmy-process.bpmn20.xml", - "mediaType": "text/xml", - "type": "processDefinition" - }, - { - "id": "image.png", - "url": "http://localhost:8081/flowable-rest/service/repository/deployments/10/resources/image.png", - "dataUrl": "http://localhost:8081/flowable-rest/service/repository/deployments/10/resourcedata/image.png", - "mediaType": "image/png", - "type": "resource" - } -] ----- - - -* ++mediaType++: Contains the media-type the resource has. This is resolved using a (pluggable) +MediaTypeResolver+ and contains, by default, a limited number of mime-type mappings. -* ++type++: Type of resource, possible values: -* ++resource++: Plain old resource. -* ++processDefinition++: Resource that contains one or more process-definitions. This resource is picked up by the deployer. -* ++processImage++: Resource that represents a deployed process definition's graphical layout. - -_The dataUrl property in the resulting JSON for a single resource contains the actual URL to use for retrieving the binary resource._ - - -==== Get a deployment resource - ----- -GET repository/deployments/{deploymentId}/resources/{resourceId} ----- - -.Get a deployment resource - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|deploymentId|Yes|String|The id of the deployment the requested resource is part of. -|resourceId|Yes|String|The id of the resource to get. *Make sure you URL-encode the resourceId in case it contains forward slashes. Eg: use 'diagrams%2Fmy-process.bpmn20.xml' instead of 'diagrams/Fmy-process.bpmn20.xml'.* - -|=============== - - -.Get a deployment resource - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates both deployment and resource have been found and the resource has been returned. -|404|Indicates the requested deployment was not found or there is no resource with the given id present in the deployment. The status-description contains additional information. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "id": "diagrams/my-process.bpmn20.xml", - "url": "http://localhost:8081/flowable-rest/service/repository/deployments/10/resources/diagrams%2Fmy-process.bpmn20.xml", - "dataUrl": "http://localhost:8081/flowable-rest/service/repository/deployments/10/resourcedata/diagrams%2Fmy-process.bpmn20.xml", - "mediaType": "text/xml", - "type": "processDefinition" -} ----- - - -* ++mediaType++: Contains the media-type the resource has. This is resolved using a (pluggable) +MediaTypeResolver+ and contains, by default, a limited number of mime-type mappings. -* ++type++: Type of resource, possible values: -* ++resource++: Plain old resource. -* ++processDefinition++: Resource that contains one or more process-definitions. This resource is picked up by the deployer. -* ++processImage++: Resource that represents a deployed process definition's graphical layout. - - -==== Get a deployment resource content - ----- -GET repository/deployments/{deploymentId}/resourcedata/{resourceId} ----- - -.Get a deployment resource content - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|deploymentId|Yes|String|The id of the deployment the requested resource is part of. -|resourceId|Yes|String|The id of the resource to get the data for. *Make sure you URL-encode the resourceId in case it contains forward slashes. Eg: use 'diagrams%2Fmy-process.bpmn20.xml' instead of 'diagrams/Fmy-process.bpmn20.xml'.* - -|=============== - - - - - - - .Get a deployment resource content - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates both deployment and resource have been found and the resource data has been returned. -|404|Indicates the requested deployment was not found or there is no resource with the given id present in the deployment. The status-description contains additional information. - -|=============== - -*Success response body:* - - -The response body will contain the binary resource-content for the requested resource. The response content-type will be the same as the type returned in the resources 'mimeType' property. Also, a content-disposition header is set, allowing browsers to download the file instead of displaying it. - - -=== Process Definitions - - -==== List of process definitions - - ----- -GET repository/process-definitions ----- - -.List of process definitions - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|version|No|integer|Only return process definitions with the given version. -|name|No|String|Only return process definitions with the given name. -|nameLike|No|String|Only return process definitions with a name like the given name. -|key|No|String|Only return process definitions with the given key. -|keyLike|No|String|Only return process definitions with a name like the given key. -|resourceName|No|String|Only return process definitions with the given resource name. -|resourceNameLike|No|String|Only return process definitions with a name like the given resource name. -|category|No|String|Only return process definitions with the given category. -|categoryLike|No|String|Only return process definitions with a category like the given name. -|categoryNotEquals|No|String|Only return process definitions which don't have the given category. -|deploymentId|No|String|Only return process definitions which are part of a deployment with the given id. -|startableByUser|No|String|Only return process definitions which can be started by the given user. -|latest|No|Boolean|Only return the latest process definition versions. Can only be used together with 'key', 'keyLike', 'resourceName' and 'resourceNameLike' parameters, using any other parameter will result in a 400-response. -|suspended|No|Boolean|If +true+, only returns process definitions which are suspended. If +false+, only active process definitions (which are not suspended) are returned. -|sort|No|'name' (default), 'id', 'key', 'category', 'deploymentId' and 'version'|Property to sort on, to be used together with the 'order'. -|The general <> can be used for this URL. - -|=============== - - -.List of process definitions - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates request was successful and the process-definitions are returned -|400|Indicates a parameter was passed in the wrong format or that 'latest' is used with other parameters other than 'key' and 'keyLike'. The status-message contains additional information. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "data": [ - { - "id" : "oneTaskProcess:1:4", - "url" : "http://localhost:8182/repository/process-definitions/oneTaskProcess%3A1%3A4", - "version" : 1, - "key" : "oneTaskProcess", - "category" : "Examples", - "suspended" : false, - "name" : "The One Task Process", - "description" : "This is a process for testing purposes", - "deploymentId" : "2", - "deploymentUrl" : "http://localhost:8081/repository/deployments/2", - "graphicalNotationDefined" : true, - "resource" : "http://localhost:8182/repository/deployments/2/resources/testProcess.xml", - "diagramResource" : "http://localhost:8182/repository/deployments/2/resources/testProcess.png", - "startFormDefined" : false - } - ], - "total": 1, - "start": 0, - "sort": "name", - "order": "asc", - "size": 1 -} ----- - - -* ++graphicalNotationDefined++: Indicates the process definition contains graphical information (BPMN DI). -* ++resource++: Contains the actual deployed BPMN 2.0 xml. -* ++diagramResource++: Contains a graphical representation of the process, null when no diagram is available. - - -==== Get a process definition - ----- -GET repository/process-definitions/{processDefinitionId} ----- - -.Get a process definition - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|processDefinitionId|Yes|String|The id of the process definition to get. - -|=============== - - -.Get a process definition - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the process definition was found and returned. -|404|Indicates the requested process definition was not found. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "id" : "oneTaskProcess:1:4", - "url" : "http://localhost:8182/repository/process-definitions/oneTaskProcess%3A1%3A4", - "version" : 1, - "key" : "oneTaskProcess", - "category" : "Examples", - "suspended" : false, - "name" : "The One Task Process", - "description" : "This is a process for testing purposes", - "deploymentId" : "2", - "deploymentUrl" : "http://localhost:8081/repository/deployments/2", - "graphicalNotationDefined" : true, - "resource" : "http://localhost:8182/repository/deployments/2/resources/testProcess.xml", - "diagramResource" : "http://localhost:8182/repository/deployments/2/resources/testProcess.png", - "startFormDefined" : false -} ----- - -* ++graphicalNotationDefined++: Indicates the process definition contains graphical information (BPMN DI). -* ++resource++: Contains the actual deployed BPMN 2.0 xml. -* ++diagramResource++: Contains a graphical representation of the process, null when no diagram is available. - - -==== Update category for a process definition - ----- -PUT repository/process-definitions/{processDefinitionId} ----- - - -*Body JSON:* - -[source,json,linenums] ----- -{ - "category" : "updatedcategory" -} ----- - - -.Update category for a process definition - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the process was category was altered. -|400|Indicates no category was defined in the request body. -|404|Indicates the requested process definition was not found. - -|=============== - - -*Success response body:* see response for +repository/process-definitions/{processDefinitionId}+. - - -==== Get a process definition resource content - ----- -GET repository/process-definitions/{processDefinitionId}/resourcedata ----- - -.Get a process definition resource content - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|processDefinitionId|Yes|String|The id of the process definition to get the resource data for. - -|=============== - -*Response:* - -Exactly the same response codes/boy as +GET repository/deployment/{deploymentId}/resourcedata/{resourceId}+. - - -==== Get a process definition BPMN model - ----- -GET repository/process-definitions/{processDefinitionId}/model ----- - -.Get a process definition BPMN model - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|processDefinitionId|Yes|String|The id of the process definition to get the model for. - -|=============== - - -.Get a process definition BPMN model - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the process definition was found and the model is returned. -|404|Indicates the requested process definition was not found. - -|=============== - - -*Response body:* -The response body is a JSON representation of the +org.flowable.bpmn.model.BpmnModel+ and contains the full process definition model. - -[source,json,linenums] ----- -{ - "processes":[ - { - "id":"oneTaskProcess", - "xmlRowNumber":7, - "xmlColumnNumber":60, - "extensionElements":{ - - }, - "name":"The One Task Process", - "executable":true, - "documentation":"One task process description", - - ] -} ----- - - -==== Suspend a process definition - - ----- -PUT repository/process-definitions/{processDefinitionId} ----- - -*Body JSON:* - -[source,json,linenums] ----- -{ - "action" : "suspend", - "includeProcessInstances" : "false", - "date" : "2013-04-15T00:42:12Z" -} ----- - - -[[processDefinitionActionBodyParameters]] -.Suspend a process definition - JSON Body parameters -[options="header"] -|=============== -|Parameter|Description|Required -|action|Action to perform. Either +activate+ or +suspend+.|Yes -|includeProcessInstances|Whether or not to suspend/activate running process-instances for this process-definition. If omitted, the process-instances are left in the state they are.|No -|date|Date (ISO-8601) when the suspension/activation should be executed. If omitted, the suspend/activation is effective immediately.|No - -|=============== - - -.Suspend a process definition - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the process was suspended. -|404|Indicates the requested process definition was not found. -|409|Indicates the requested process definition is already suspended. - -|=============== - -*Success response body:* see response for +repository/process-definitions/{processDefinitionId}+. - -==== Activate a process definition - ----- -PUT repository/process-definitions/{processDefinitionId} ----- - -*Body JSON:* - -[source,json,linenums] ----- -{ - "action" : "activate", - "includeProcessInstances" : "true", - "date" : "2013-04-15T00:42:12Z" -} ----- - -See suspend process definition <>. - -.Activate a process definition - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the process was activated. -|404|Indicates the requested process definition was not found. -|409|Indicates the requested process definition is already active. - -|=============== - - -*Success response body:* see response for +repository/process-definitions/{processDefinitionId}+. - - -==== Get all candidate starters for a process-definition - ----- -GET repository/process-definitions/{processDefinitionId}/identitylinks ----- - - -.Get all candidate starters for a process-definition - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|processDefinitionId|Yes|String|The id of the process definition to get the identity links for. - -|=============== - - -.Get all candidate starters for a process-definition - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the process definition was found and the requested identity links are returned. -|404|Indicates the requested process definition was not found. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -[ - { - "url":"http://localhost:8182/repository/process-definitions/oneTaskProcess%3A1%3A4/identitylinks/groups/admin", - "user":null, - "group":"admin", - "type":"candidate" - }, - { - "url":"http://localhost:8182/repository/process-definitions/oneTaskProcess%3A1%3A4/identitylinks/users/kermit", - "user":"kermit", - "group":null, - "type":"candidate" - } -] ----- - - -==== Add a candidate starter to a process definition - - ----- -POST repository/process-definitions/{processDefinitionId}/identitylinks ----- - -.Add a candidate starter to a process definition - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|processDefinitionId|Yes|String|The id of the process definition. - -|=============== - - -*Request body (user):* - -[source,json,linenums] ----- -{ - "user" : "kermit" -} ----- - -*Request body (group):* - -[source,json,linenums] ----- -{ - "groupId" : "sales" -} ----- - -.Add a candidate starter to a process definition - Response codes -[options="header"] -|=============== -|Response code|Description -|201|Indicates the process definition was found and the identity link was created. -|404|Indicates the requested process definition was not found. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- - -{ - "url":"http://localhost:8182/repository/process-definitions/oneTaskProcess%3A1%3A4/identitylinks/users/kermit", - "user":"kermit", - "group":null, - "type":"candidate" -} ----- - - -==== Delete a candidate starter from a process definition - - ----- -DELETE repository/process-definitions/{processDefinitionId}/identitylinks/{family}/{identityId} ----- - -.Delete a candidate starter from a process definition - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|processDefinitionId|Yes|String|The id of the process definition. -|family|Yes|String|Either +users+ or +groups+, depending on the type of identity link. -|identityId|Yes|String|Either the userId or groupId of the identity to remove as candidate starter. - -|=============== - - -.Delete a candidate starter from a process definition - Response codes -[options="header"] -|=============== -|Response code|Description -|204|Indicates the process definition was found and the identity link was removed. The response body is intentionally empty. -|404|Indicates the requested process definition was not found or the process definition doesn't have an identity-link that matches the url. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- - -{ - "url":"http://localhost:8182/repository/process-definitions/oneTaskProcess%3A1%3A4/identitylinks/users/kermit", - "user":"kermit", - "group":null, - "type":"candidate" -} ----- - - -==== Get a candidate starter from a process definition - ----- -GET repository/process-definitions/{processDefinitionId}/identitylinks/{family}/{identityId} ----- - - -.Get a candidate starter from a process definition - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|processDefinitionId|Yes|String|The id of the process definition. -|family|Yes|String|Either +users+ or +groups+, depending on the type of identity link. -|identityId|Yes|String|Either the userId or groupId of the identity to get as candidate starter. - -|=============== - - -.Get a candidate starter from a process definition - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the process definition was found and the identity link was returned. -|404|Indicates the requested process definition was not found or the process definition doesn't have an identity-link that matches the url. - -|=============== - -*Success response body:* - -[source,json,linenums] ----- -{ - "url":"http://localhost:8182/repository/process-definitions/oneTaskProcess%3A1%3A4/identitylinks/users/kermit", - "user":"kermit", - "group":null, - "type":"candidate" -} ----- - -=== Models - - -==== Get a list of models - - ----- -GET repository/models ----- - -.Get a list of models - URL query parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|id|No|String|Only return models with the given id. -|category|No|String|Only return models with the given category. -|categoryLike|No|String|Only return models with a category like the given value. Use the +%+ character as wildcard. -|categoryNotEquals|No|String|Only return models without the given category. -|name|No|String|Only return models with the given name. -|nameLike|No|String|Only return models with a name like the given value. Use the +%+ character as wildcard. -|key|No|String|Only return models with the given key. -|deploymentId|No|String|Only return models which are deployed in the given deployment. -|version|No|Integer|Only return models with the given version. -|latestVersion|No|Boolean|If +true+, only return models which are the latest version. Best used in combination with +key+. If +false+ is passed in as value, this is ignored and all versions are returned. -|deployed|No|Boolean|If +true+, only deployed models are returned. If +false+, only undeployed models are returned (deploymentId is null). -|tenantId|No|String|Only return models with the given tenantId. -|tenantIdLike|No|String|Only return models with a tenantId like the given value. -|withoutTenantId|No|Boolean|If +true+, only returns models without a tenantId set. If +false+, the +withoutTenantId+ parameter is ignored. -|sort|No|'id' (default), 'category', 'createTime', 'key', 'lastUpdateTime', 'name', 'version' or 'tenantId'|Property to sort on, to be used together with the 'order'. -|The general <> can be used for this URL. - -|=============== - - -.Get a list of models - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates request was successful and the models are returned -|400|Indicates a parameter was passed in the wrong format. The status-message contains additional information. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "data":[ - { - "name":"Model name", - "key":"Model key", - "category":"Model category", - "version":2, - "metaInfo":"Model metainfo", - "deploymentId":"7", - "id":"10", - "url":"http://localhost:8182/repository/models/10", - "createTime":"2013-06-12T14:31:08.612+0000", - "lastUpdateTime":"2013-06-12T14:31:08.612+0000", - "deploymentUrl":"http://localhost:8182/repository/deployments/7", - "tenantId":null - }, - - ... - - ], - "total":2, - "start":0, - "sort":"id", - "order":"asc", - "size":2 -} ----- - - -==== Get a model - - ----- -GET repository/models/{modelId} ----- - -.Get a model - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|modelId|Yes|String|The id of the model to get. - -|=============== - - -.Get a model - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the model was found and returned. -|404|Indicates the requested model was not found. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "id":"5", - "url":"http://localhost:8182/repository/models/5", - "name":"Model name", - "key":"Model key", - "category":"Model category", - "version":2, - "metaInfo":"Model metainfo", - "deploymentId":"2", - "deploymentUrl":"http://localhost:8182/repository/deployments/2", - "createTime":"2013-06-12T12:31:19.861+0000", - "lastUpdateTime":"2013-06-12T12:31:19.861+0000", - "tenantId":null -} ----- - - - -==== Update a model - ----- -PUT repository/models/{modelId} ----- - -*Request body:* - -[source,json,linenums] ----- -{ - "name":"Model name", - "key":"Model key", - "category":"Model category", - "version":2, - "metaInfo":"Model metainfo", - "deploymentId":"2", - "tenantId":"updatedTenant" -} ----- - -All request values are optional. For example, you can only include the 'name' attribute in the request body JSON-object, only updating the name of the model, leaving all other fields unaffected. When an attribute is explicitly included and is set to null, the model-value will be updated to null. Example: +{"metaInfo" : null}+ will clear the metaInfo of the model). - -.Update a model - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the model was found and updated. -|404|Indicates the requested model was not found. - -|=============== - -*Success response body:* - -[source,json,linenums] ----- -{ - "id":"5", - "url":"http://localhost:8182/repository/models/5", - "name":"Model name", - "key":"Model key", - "category":"Model category", - "version":2, - "metaInfo":"Model metainfo", - "deploymentId":"2", - "deploymentUrl":"http://localhost:8182/repository/deployments/2", - "createTime":"2013-06-12T12:31:19.861+0000", - "lastUpdateTime":"2013-06-12T12:31:19.861+0000", - "tenantId":""updatedTenant" -} ----- - - -==== Create a model - ----- -POST repository/models ----- - -*Request body:* - -[source,json,linenums] ----- -{ - "name":"Model name", - "key":"Model key", - "category":"Model category", - "version":1, - "metaInfo":"Model metainfo", - "deploymentId":"2", - "tenantId":"tenant" -} ----- - - -All request values are optional. For example, you can only include the 'name' attribute in the request body JSON-object, only setting the name of the model, leaving all other fields null. - -.Create a model - Response codes -[options="header"] -|=============== -|Response code|Description -|201|Indicates the model was created. - -|=============== - -*Success response body:* - -[source,json,linenums] ----- -{ - "id":"5", - "url":"http://localhost:8182/repository/models/5", - "name":"Model name", - "key":"Model key", - "category":"Model category", - "version":1, - "metaInfo":"Model metainfo", - "deploymentId":"2", - "deploymentUrl":"http://localhost:8182/repository/deployments/2", - "createTime":"2013-06-12T12:31:19.861+0000", - "lastUpdateTime":"2013-06-12T12:31:19.861+0000", - "tenantId":"tenant" -} ----- - - -==== Delete a model - ----- -DELETE repository/models/{modelId} ----- - - -.Delete a model - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|modelId|Yes|String|The id of the model to delete. - -|=============== - - -.Delete a model - Response codes -[options="header"] -|=============== -|Response code|Description -|204|Indicates the model was found and has been deleted. Response-body is intentionally empty. -|404|Indicates the requested model was not found. - -|=============== - - -==== Get the editor source for a model - - ----- -GET repository/models/{modelId}/source ----- - - -.Get the editor source for a model - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|modelId|Yes|String|The id of the model. - -|=============== - - -.Get the editor source for a model - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the model was found and source is returned. -|404|Indicates the requested model was not found. - -|=============== - - - -*Success response body:* - -Response body contains the model's raw editor source. The response's content-type is set to +application/octet-stream+, regardless of the content of the source. - - -==== Set the editor source for a model - ----- -PUT repository/models/{modelId}/source ----- - -.Set the editor source for a model - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|modelId|Yes|String|The id of the model. - -|=============== - - -*Request body:* - -The request should be of type +multipart/form-data+. There should be a single file-part included with the binary value of the source. - -.Set the editor source for a model - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the model was found and the source has been updated. -|404|Indicates the requested model was not found. - -|=============== - -*Success response body:* - -Response body contains the model's raw editor source. The response's content-type is set to +application/octet-stream+, regardless of the content of the source. - - -==== Get the extra editor source for a model - ----- -GET repository/models/{modelId}/source-extra ----- - -.Get the extra editor source for a model - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|modelId|Yes|String|The id of the model. - -|=============== - - -.Get the extra editor source for a model - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the model was found and source is returned. -|404|Indicates the requested model was not found. - -|=============== - - -*Success response body:* - -Response body contains the model's raw extra editor source. The response's content-type is set to +application/octet-stream+, regardless of the content of the extra source. - - -==== Set the extra editor source for a model - - ----- -PUT repository/models/{modelId}/source-extra ----- - -.Set the extra editor source for a model - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|modelId|Yes|String|The id of the model. - -|=============== - -*Request body:* - -The request should be of type +multipart/form-data+. There should be a single file-part included with the binary value of the extra source. - -.Set the extra editor source for a model - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the model was found and the extra source has been updated. -|404|Indicates the requested model was not found. - -|=============== - - -*Success response body:* - -Response body contains the model's raw editor source. The response's content-type is set to +application/octet-stream+, regardless of the content of the source. - - -=== Process Instances - -==== Get a process instance - ----- -GET runtime/process-instances/{processInstanceId} ----- - -.Get a process instance - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|processInstanceId|Yes|String|The id of the process instance to get. - -|=============== - - -.Get a process instance - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the process instance was found and returned. -|404|Indicates the requested process instance was not found. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "id":"7", - "url":"http://localhost:8182/runtime/process-instances/7", - "businessKey":"myBusinessKey", - "suspended":false, - "processDefinitionUrl":"http://localhost:8182/repository/process-definitions/processOne%3A1%3A4", - "activityId":"processTask", - "tenantId": null -} ----- - - -==== Delete a process instance - ----- -DELETE runtime/process-instances/{processInstanceId} ----- - -.Delete a process instance - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|processInstanceId|Yes|String|The id of the process instance to delete. - -|=============== - - -.Delete a process instance - Response codes -[options="header"] -|=============== -|Response code|Description -|204|Indicates the process instance was found and deleted. Response body is left empty intentionally. -|404|Indicates the requested process instance was not found. - -|=============== - - -==== Activate or suspend a process instance - - ----- -PUT runtime/process-instances/{processInstanceId} ----- - - -.Activate or suspend a process instance - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|processInstanceId|Yes|String|The id of the process instance to activate/suspend. - -|=============== - - -*Request response body (suspend):* - -[source,json,linenums] ----- -{ - "action":"suspend" -} ----- - -*Request response body (activate):* - -[source,json,linenums] ----- -{ - "action":"activate" -} ----- - -.Activate or suspend a process instance - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the process instance was found and action was executed. -|400|Indicates an invalid action was supplied. -|404|Indicates the requested process instance was not found. -|409|Indicates the requested process instance action cannot be executed since the process-instance is already activated/suspended. - -|=============== - - - -==== Start a process instance - - ----- -POST runtime/process-instances ----- - -*Request body (start by process definition id):* - -[source,json,linenums] ----- -{ - "processDefinitionId":"oneTaskProcess:1:158", - "businessKey":"myBusinessKey", - "returnVariables":true, - "variables": [ - { - "name":"myVar", - "value":"This is a variable" - } - ] -} ----- - -*Request body (start by process definition key):* - -[source,json,linenums] ----- -{ - "processDefinitionKey":"oneTaskProcess", - "businessKey":"myBusinessKey", - "returnVariables":false, - "tenantId": "tenant1", - "variables": [ - { - "name":"myVar", - "value":"This is a variable" - } - ] -} ----- - -*Request body (start by message):* - -[source,json,linenums] ----- -{ - "message":"newOrderMessage", - "businessKey":"myBusinessKey", - "tenantId": "tenant1", - "variables": [ - { - "name":"myVar", - "value":"This is a variable" - } - ] -} ----- - -Note that also a _transientVariables_ property is accepted as part of this json, that follows the same structure as the _variables_ property. - -The _returnVariables_ property can be used to get the existing variables in the process instance context back in the response. By default the variables are not returned. - -Only one of +processDefinitionId+, +processDefinitionKey+ or +message+ can be used in the request body. Parameters +businessKey+, +variables+ and +tenantId+ are optional. If +tenantId+ is omitted, the default tenant will be used. More information about the variable format can be found in <>. Note that the variable-scope that is supplied is ignored, process-variables are always +local+. - - -.Start a process instance - Response codes -[options="header"] -|=============== -|Response code|Description -|201|Indicates the process instance was created. -|400|Indicates either the process-definition was not found (based on id or key), no process is started by sending the given message or an invalid variable has been passed. Status description contains additional information about the error. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "id":"7", - "url":"http://localhost:8182/runtime/process-instances/7", - "businessKey":"myBusinessKey", - "suspended":false, - "processDefinitionUrl":"http://localhost:8182/repository/process-definitions/processOne%3A1%3A4", - "activityId":"processTask", - "tenantId" : null -} ----- - - -[[restProcessInstancesGet]] - - -==== List of process instances - ----- -GET runtime/process-instances ----- - -.List of process instances - URL query parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|id|No|String|Only return process instance with the given id. -|processDefinitionKey|No|String|Only return process instances with the given process definition key. -|processDefinitionId|No|String|Only return process instances with the given process definition id. -|businessKey|No|String|Only return process instances with the given businessKey. -|involvedUser|No|String|Only return process instances in which the given user is involved. -|suspended|No|Boolean|If +true+, only return process instance which are suspended. If +false+, only return process instances which are not suspended (active). -|superProcessInstanceId|No|String|Only return process instances which have the given super process-instance id (for processes that have a call-activities). -|subProcessInstanceId|No|String|Only return process instances which have the given sub process-instance id (for processes started as a call-activity). -|excludeSubprocesses|No|Boolean|Return only process instances which aren't sub processes. -|includeProcessVariables|No|Boolean|Indication to include process variables in the result. -|tenantId|No|String|Only return process instances with the given tenantId. -|tenantIdLike|No|String|Only return process instances with a tenantId like the given value. -|withoutTenantId|No|Boolean|If +true+, only returns process instances without a tenantId set. If +false+, the +withoutTenantId+ parameter is ignored. -|sort|No|String|Sort field, should be either one of +id+ (default), +processDefinitionId+, +tenantId+ or +processDefinitionKey+. -|The general <> can be used for this URL. - -|=============== - - -.List of process instances - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates request was successful and the process-instances are returned -|400|Indicates a parameter was passed in the wrong format . The status-message contains additional information. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "data":[ - { - "id":"7", - "url":"http://localhost:8182/runtime/process-instances/7", - "businessKey":"myBusinessKey", - "suspended":false, - "processDefinitionUrl":"http://localhost:8182/repository/process-definitions/processOne%3A1%3A4", - "activityId":"processTask", - "tenantId" : null - } - - - ], - "total":2, - "start":0, - "sort":"id", - "order":"asc", - "size":2 -} ----- - - -==== Query process instances - ----- -POST query/process-instances ----- - -*Request body:* - -[source,json,linenums] ----- -{ - "processDefinitionKey":"oneTaskProcess", - "variables": - [ - { - "name" : "myVariable", - "value" : 1234, - "operation" : "equals", - "type" : "long" - } - ] -} ----- - -The request body can contain all possible filters that can be used in the <> URL query. On top of these, it's possible to provide an array of variables -to include in the query, with their format <>. - - -The general <> can be used for this URL. - - -.Query process instances - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates request was successful and the process-instances are returned -|400|Indicates a parameter was passed in the wrong format . The status-message contains additional information. - -|=============== - -*Success response body:* - -[source,json,linenums] ----- -{ - "data":[ - { - "id":"7", - "url":"http://localhost:8182/runtime/process-instances/7", - "businessKey":"myBusinessKey", - "suspended":false, - "processDefinitionUrl":"http://localhost:8182/repository/process-definitions/processOne%3A1%3A4", - "activityId":"processTask", - "tenantId" : null - } - - - ], - "total":2, - "start":0, - "sort":"id", - "order":"asc", - "size":2 -} ----- - - -==== Get diagram for a process instance - ----- -GET runtime/process-instances/{processInstanceId}/diagram ----- - -.Get diagram for a process instance - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|processInstanceId|Yes|String|The id of the process instance to get the diagram for. - -|=============== - - -.Get diagram for a process instance - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the process instance was found and the diagram was returned. -|400|Indicates the requested process instance was not found but the process doesn't contain any graphical information (BPMN:DI) and no diagram can be created. -|404|Indicates the requested process instance was not found. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "id":"7", - "url":"http://localhost:8182/runtime/process-instances/7", - "businessKey":"myBusinessKey", - "suspended":false, - "processDefinitionUrl":"http://localhost:8182/repository/process-definitions/processOne%3A1%3A4", - "activityId":"processTask" -} ----- - - -==== Get involved people for process instance - ----- -GET runtime/process-instances/{processInstanceId}/identitylinks ----- - - -.Get involved people for process instance - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|processInstanceId|Yes|String|The id of the process instance to the links for. - -|=============== - - -.Get involved people for process instance - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the process instance was found and links are returned. -|404|Indicates the requested process instance was not found. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -[ - { - "url":"http://localhost:8182/runtime/process-instances/5/identitylinks/users/john/customType", - "user":"john", - "group":null, - "type":"customType" - }, - { - "url":"http://localhost:8182/runtime/process-instances/5/identitylinks/users/paul/candidate", - "user":"paul", - "group":null, - "type":"candidate" - } -] ----- - - -Note that the +groupId+ will always be null, as it's only possible to involve users with a process-instance. - - -==== Add an involved user to a process instance - - ----- -POST runtime/process-instances/{processInstanceId}/identitylinks ----- - -.Add an involved user to a process instance - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|processInstanceId|Yes|String|The id of the process instance to the links for. - -|=============== - - -*Request body:* - -[source,json,linenums] ----- -{ - "userId":"kermit", - "type":"participant" -} ----- - - -Both +userId+ and +type+ are required. - - -.Add an involved user to a process instance - Response codes -[options="header"] -|=============== -|Response code|Description -|201|Indicates the process instance was found and the link is created. -|400|Indicates the requested body did not contain a userId or a type. -|404|Indicates the requested process instance was not found. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "url":"http://localhost:8182/runtime/process-instances/5/identitylinks/users/john/customType", - "user":"john", - "group":null, - "type":"customType" -} ----- - - -Note that the +groupId+ will always be null, as it's only possible to involve users with a process-instance. - - -==== Remove an involved user to from process instance - ----- -DELETE runtime/process-instances/{processInstanceId}/identitylinks/users/{userId}/{type} ----- - - -.Remove an involved user to from process instance - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|processInstanceId|Yes|String|The id of the process instance. -|userId|Yes|String|The id of the user to delete link for. -|type|Yes|String|Type of link to delete. - -|=============== - - -.Remove an involved user to from process instance - Response codes -[options="header"] -|=============== -|Response code|Description -|204|Indicates the process instance was found and the link has been deleted. Response body is left empty intentionally. -|404|Indicates the requested process instance was not found or the link to delete doesn't exist. The response status contains additional information about the error. - -|=============== - -*Success response body:* - -[source,json,linenums] ----- -{ - "url":"http://localhost:8182/runtime/process-instances/5/identitylinks/users/john/customType", - "user":"john", - "group":null, - "type":"customType" -} ----- - - -Note that the +groupId+ will always be null, as it's only possible to involve users with a process-instance. - - -==== List of variables for a process instance - ----- -GET runtime/process-instances/{processInstanceId}/variables ----- - -.List of variables for a process instance - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|processInstanceId|Yes|String|The id of the process instance to the variables for. - -|=============== - - - -.List of variables for a process instance - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the process instance was found and variables are returned. -|404|Indicates the requested process instance was not found. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -[ - { - "name":"intProcVar", - "type":"integer", - "value":123, - "scope":"local" - }, - { - "name":"byteArrayProcVar", - "type":"binary", - "value":null, - "valueUrl":"http://localhost:8182/runtime/process-instances/5/variables/byteArrayProcVar/data", - "scope":"local" - } -] ----- - - -In case the variable is a binary variable or serializable, the +valueUrl+ points to an URL to fetch the raw value. If it's a plain variable, the value is present in the response. -Note that only +local+ scoped variables are returned, as there is no +global+ scope for process-instance variables. - - - -==== Get a variable for a process instance - - ----- -GET runtime/process-instances/{processInstanceId}/variables/{variableName} ----- - - -.Get a variable for a process instance - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|processInstanceId|Yes|String|The id of the process instance to the variables for. -|variableName|Yes|String|Name of the variable to get. - -|=============== - - -.Get a variable for a process instance - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates both the process instance and variable were found and variable is returned. -|400|Indicates the request body is incomplete or contains illegal values. The status description contains additional information about the error. -|404|Indicates the requested process instance was not found or the process instance does not have a variable with the given name. Status description contains additional information about the error. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- - { - "name":"intProcVar", - "type":"integer", - "value":123, - "scope":"local" - } ----- - - -In case the variable is a binary variable or serializable, the +valueUrl+ points to an URL to fetch the raw value. If it's a plain variable, the value is present in the response. Note that only +local+ scoped variables are returned, as there is no +global+ scope for process-instance variables. - - -==== Create (or update) variables on a process instance - ----- -POST runtime/process-instances/{processInstanceId}/variables ----- - ----- -PUT runtime/process-instances/{processInstanceId}/variables ----- - - -When using +POST+, all variables that are passed are created. In case one of the variables already exists on the process instance, the request results in an error (409 - CONFLICT). When +PUT+ is used, nonexistent variables are created on the process-instance and existing ones are overridden without any error. - -.Create (or update) variables on a process instance - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|processInstanceId|Yes|String|The id of the process instance to the variables for. - -|=============== - - -*Request body:* - ----- -[ - { - "name":"intProcVar", - "type":"integer", - "value":123 - }, - - ... -] ----- - - -Any number of variables can be passed into the request body array. More information about the variable format can be found in <>. Note that scope is ignored, only +local+ variables can be set in a process instance. - -.Create (or update) variables on a process instance - Response codes -[options="header"] -|=============== -|Response code|Description -|201|Indicates the process instance was found and variable is created. -|400|Indicates the request body is incomplete or contains illegal values. The status description contains additional information about the error. -|404|Indicates the requested process instance was not found. -|409|Indicates the process instance was found but already contains a variable with the given name (only thrown when POST method is used). Use the update-method instead. - -|=============== - - -*Success response body:* - ----- -[ - { - "name":"intProcVar", - "type":"integer", - "value":123, - "scope":"local" - }, - - ... - -] ----- - - -==== Update a single variable on a process instance - ----- -PUT runtime/process-instances/{processInstanceId}/variables/{variableName} ----- - -.Update a single variable on a process instance - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|processInstanceId|Yes|String|The id of the process instance to the variables for. -|variableName|Yes|String|Name of the variable to get. - -|=============== - -*Request body:* - -[source,json,linenums] ----- - { - "name":"intProcVar" - "type":"integer" - "value":123 - } ----- - - -More information about the variable format can be found in <>. Note that scope is ignored, only +local+ variables can be set in a process instance. - -.Update a single variable on a process instance - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates both the process instance and variable were found and variable is updated. -|404|Indicates the requested process instance was not found or the process instance does not have a variable with the given name. Status description contains additional information about the error. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "name":"intProcVar", - "type":"integer", - "value":123, - "scope":"local" -} ----- - - -In case the variable is a binary variable or serializable, the +valueUrl+ points to an URL to fetch the raw value. If it's a plain variable, the value is present in the response. Note that only +local+ scoped variables are returned, as there is no +global+ scope for process-instance variables. - -==== Create a new binary variable on a process-instance - ----- -POST runtime/process-instances/{processInstanceId}/variables ----- - - -.Create a new binary variable on a process-instance - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|processInstanceId|Yes|String|The id of the process instance to create the new variable for. - -|=============== - - - -*Request body:* - -The request should be of type +multipart/form-data+. There should be a single file-part included with the binary value of the variable. On top of that, the following additional form-fields can be present: - -* ++name++: Required name of the variable. -* ++type++: Type of variable that is created. If omitted, +binary+ is assumed and the binary data in the request will be stored as an array of bytes. - - -*Success response body:* - -[source,json,linenums] ----- -{ - "name" : "binaryVariable", - "scope" : "local", - "type" : "binary", - "value" : null, - "valueUrl" : "http://.../runtime/process-instances/123/variables/binaryVariable/data" -} ----- - - -.Create a new binary variable on a process-instance - Response codes -[options="header"] -|=============== -|Response code|Description -|201|Indicates the variable was created and the result is returned. -|400|Indicates the name of the variable to create was missing. Status message provides additional information. -|404|Indicates the requested process instance was not found. -|409|Indicates the process instance already has a variable with the given name. Use the PUT method to update the task variable instead. -|415|Indicates the serializable data contains an object for which no class is present in the JVM running the Flowable engine and therefore cannot be deserialized. - -|=============== - - - -==== Update an existing binary variable on a process-instance - ----- -PUT runtime/process-instances/{processInstanceId}/variables ----- - -.Update an existing binary variable on a process-instance - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|processInstanceId|Yes|String|The id of the process instance to create the new variable for. - -|=============== - - -*Request body:* -The request should be of type +multipart/form-data+. There should be a single file-part included with the binary value of the variable. On top of that, the following additional form-fields can be present: - -* ++name++: Required name of the variable. -* ++type++: Type of variable that is created. If omitted, +binary+ is assumed and the binary data in the request will be stored as an array of bytes. - -*Success response body:* - -[source,json,linenums] ----- -{ - "name" : "binaryVariable", - "scope" : "local", - "type" : "binary", - "value" : null, - "valueUrl" : "http://.../runtime/process-instances/123/variables/binaryVariable/data" -} ----- - - -.Update an existing binary variable on a process-instance - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the variable was updated and the result is returned. -|400|Indicates the name of the variable to update was missing. Status message provides additional information. -|404|Indicates the requested process instance was not found or the process instance does not have a variable with the given name. -|415|Indicates the serializable data contains an object for which no class is present in the JVM running the Flowable engine and therefore cannot be deserialized. - -|=============== - - - -=== Executions - - -==== Get an execution - ----- -GET runtime/executions/{executionId} ----- - - -.Get an execution - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|executionId|Yes|String|The id of the execution to get. - -|=============== - - -.Get an execution - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the execution was found and returned. -|404|Indicates the execution was not found. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "id":"5", - "url":"http://localhost:8182/runtime/executions/5", - "parentId":null, - "parentUrl":null, - "processInstanceId":"5", - "processInstanceUrl":"http://localhost:8182/runtime/process-instances/5", - "suspended":false, - "activityId":null, - "tenantId": null -} ----- - - -==== Execute an action on an execution - - ----- -PUT runtime/executions/{executionId} ----- - - -.Execute an action on an execution - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|executionId|Yes|String|The id of the execution to execute action on. - -|=============== - - -*Request body (signal an execution):* - -[source,json,linenums] ----- -{ - "action":"signal" -} ----- - -Both a _variables_ and _transientVariables_ property is accepted with following structure: - -[source,json,linenums] ----- -{ - "action":"signal", - "variables" : [ - { - "name": "myVar", - "value": "someValue" - } - ] -} ----- - - -*Request body (signal event received for execution):* - -[source,json,linenums] ----- -{ - "action":"signalEventReceived", - "signalName":"mySignal" - "variables": [ ] -} ----- - -Notifies the execution that a signal event has been received, requires a +signalName+ parameter. Optional +variables+ can be passed that are set on the execution before the action is executed. - -*Request body (signal event received for execution):* - -[source,json,linenums] ----- -{ - "action":"messageEventReceived", - "messageName":"myMessage" - "variables": [ ] -} ----- - - -Notifies the execution that a message event has been received, requires a +messageName+ parameter. Optional +variables+ can be passed that are set on the execution before the action is executed. - -.Execute an action on an execution - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the execution was found and the action is performed. -|204|Indicates the execution was found, the action was performed and the action caused the execution to end. -|400|Indicates an illegal action was requested, required parameters are missing in the request body or illegal variables are passed in. Status description contains additional information about the error. -|404|Indicates the execution was not found. - -|=============== - -*Success response body (in case execution is not ended due to action):* - -[source,json,linenums] ----- -{ - "id":"5", - "url":"http://localhost:8182/runtime/executions/5", - "parentId":null, - "parentUrl":null, - "processInstanceId":"5", - "processInstanceUrl":"http://localhost:8182/runtime/process-instances/5", - "suspended":false, - "activityId":null, - "tenantId" : null -} ----- - - -==== Get active activities in an execution - ----- -GET runtime/executions/{executionId}/activities ----- - -Returns all activities which are active in the execution and in all child-executions (and their children, recursively), if any. - -.Get active activities in an execution - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|executionId|Yes|String|The id of the execution to get activities for. - -|=============== - - -.Get active activities in an execution - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the execution was found and activities are returned. -|404|Indicates the execution was not found. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -[ - "userTaskForManager", - "receiveTask" -] ----- - - -[[restExecutionsGet]] - - -==== List of executions - - ----- -GET runtime/executions ----- - -.List of executions - URL query parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|id|No|String|Only return executions with the given id. -|activityId|No|String|Only return executions with the given activity id. -|processDefinitionKey|No|String|Only return executions with the given process definition key. -|processDefinitionId|No|String|Only return executions with the given process definition id. -|processInstanceId|No|String|Only return executions which are part of the process instance with the given id. -|messageEventSubscriptionName|No|String|Only return executions which are subscribed to a message with the given name. -|signalEventSubscriptionName|No|String|Only return executions which are subscribed to a signal with the given name. -|parentId|No|String|Only return executions which are a direct child of the given execution. -|tenantId|No|String|Only return executions with the given tenantId. -|tenantIdLike|No|String|Only return executions with a tenantId like the given value. -|withoutTenantId|No|Boolean|If +true+, only returns executions without a tenantId set. If +false+, the +withoutTenantId+ parameter is ignored. -|sort|No|String|Sort field, should be either one of +processInstanceId+ (default), +processDefinitionId+, +processDefinitionKey+ or +tenantId+. -|The general <> can be used for this URL. - -|=============== - - -.List of executions - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates request was successful and the executions are returned -|400|Indicates a parameter was passed in the wrong format . The status-message contains additional information. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "data":[ - { - "id":"5", - "url":"http://localhost:8182/runtime/executions/5", - "parentId":null, - "parentUrl":null, - "processInstanceId":"5", - "processInstanceUrl":"http://localhost:8182/runtime/process-instances/5", - "suspended":false, - "activityId":null, - "tenantId":null - }, - { - "id":"7", - "url":"http://localhost:8182/runtime/executions/7", - "parentId":"5", - "parentUrl":"http://localhost:8182/runtime/executions/5", - "processInstanceId":"5", - "processInstanceUrl":"http://localhost:8182/runtime/process-instances/5", - "suspended":false, - "activityId":"processTask", - "tenantId":null - } - ], - "total":2, - "start":0, - "sort":"processInstanceId", - "order":"asc", - "size":2 -} ----- - - - -==== Query executions - - ----- -POST query/executions ----- - -*Request body:* - -[source,json,linenums] ----- -{ - "processDefinitionKey":"oneTaskProcess", - "variables": - [ - { - "name" : "myVariable", - "value" : 1234, - "operation" : "equals", - "type" : "long" - } - ], - "processInstanceVariables": - [ - { - "name" : "processVariable", - "value" : "some string", - "operation" : "equals", - "type" : "string" - } - ] -} ----- - - -The request body can contain all possible filters that can be used in the <> URL query. On top of these, it's possible to provide an array of +variables+ and +processInstanceVariables+ -to include in the query, with their format <>. - -The general <> can be used for this URL. - -.Query executions - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates request was successful and the executions are returned -|400|Indicates a parameter was passed in the wrong format . The status-message contains additional information. - -|=============== - -*Success response body:* - -[source,json,linenums] ----- -{ - "data":[ - { - "id":"5", - "url":"http://localhost:8182/runtime/executions/5", - "parentId":null, - "parentUrl":null, - "processInstanceId":"5", - "processInstanceUrl":"http://localhost:8182/runtime/process-instances/5", - "suspended":false, - "activityId":null, - "tenantId":null - }, - { - "id":"7", - "url":"http://localhost:8182/runtime/executions/7", - "parentId":"5", - "parentUrl":"http://localhost:8182/runtime/executions/5", - "processInstanceId":"5", - "processInstanceUrl":"http://localhost:8182/runtime/process-instances/5", - "suspended":false, - "activityId":"processTask", - "tenantId":null - } - ], - "total":2, - "start":0, - "sort":"processInstanceId", - "order":"asc", - "size":2 -} ----- - - - -==== List of variables for an execution - ----- -GET runtime/executions/{executionId}/variables?scope={scope} ----- - - -.List of variables for an execution - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|executionId|Yes|String|The id of the execution to the variables for. -|scope|No|String|Either +local+ or +global+. If omitted, both local and global scoped variables are returned. - -|=============== - - -.List of variables for an execution - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the execution was found and variables are returned. -|404|Indicates the requested execution was not found. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -[ - { - "name":"intProcVar", - "type":"integer", - "value":123, - "scope":"global" - }, - { - "name":"byteArrayProcVar", - "type":"binary", - "value":null, - "valueUrl":"http://localhost:8182/runtime/process-instances/5/variables/byteArrayProcVar/data", - "scope":"local" - } - - -] ----- - - -In case the variable is a binary variable or serializable, the +valueUrl+ points to an URL to fetch the raw value. If it's a plain variable, the value is present in the response. - - -==== Get a variable for an execution - ----- -GET runtime/executions/{executionId}/variables/{variableName}?scope={scope} ----- - - -.Get a variable for an execution - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|executionId|Yes|String|The id of the execution to the variables for. -|variableName|Yes|String|Name of the variable to get. -|scope|No|String|Either +local+ or +global+. If omitted, local variable is returned (if exists). If not, a global variable is returned (if exists). - -|=============== - - -.Get a variable for an execution - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates both the execution and variable were found and variable is returned. -|400|Indicates the request body is incomplete or contains illegal values. The status description contains additional information about the error. -|404|Indicates the requested execution was not found or the execution does not have a variable with the given name in the requested scope (in case scope-query parameter was omitted, variable doesn't exist in local and global scope). Status description contains additional information about the error. - -|=============== - - - -*Success response body:* - -[source,json,linenums] ----- - { - "name":"intProcVar", - "type":"integer", - "value":123, - "scope":"local" - } ----- - - -In case the variable is a binary variable or serializable, the +valueUrl+ points to an URL to fetch the raw value. If it's a plain variable, the value is present in the response. - - -==== Create (or update) variables on an execution - ----- -POST runtime/executions/{executionId}/variables ----- - ----- -PUT runtime/executions/{executionId}/variables ----- - -When using +POST+, all variables that are passed are created. In case one of the variables already exists on the execution in the requested scope, the request results in an error (409 - CONFLICT). When +PUT+ is used, nonexistent variables are created on the execution and existing ones are overridden without any error. - -.Create (or update) variables on an execution - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|executionId|Yes|String|The id of the execution to the variables for. - -|=============== - - - -*Request body:* - -[source,json,linenums] ----- -[ - { - "name":"intProcVar" - "type":"integer" - "value":123, - "scope":"local" - } - - - -] ----- - -*Note that you can only provide variables that have the same scope. If the request-body array contains variables from mixed scopes, the request results in an error (400 - BAD REQUEST).*Any number of variables can be passed into the request body array. More information about the variable format can be found in <>. Note that scope is ignored, only +local+ variables can be set in a process instance. - -.Create (or update) variables on an execution - Response codes -[options="header"] -|=============== -|Response code|Description -|201|Indicates the execution was found and variable is created. -|400|Indicates the request body is incomplete or contains illegal values. The status description contains additional information about the error. -|404|Indicates the requested execution was not found. -|409|Indicates the execution was found but already contains a variable with the given name (only thrown when POST method is used). Use the update-method instead. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -[ - { - "name":"intProcVar", - "type":"integer", - "value":123, - "scope":"local" - } - - - -] ----- - - - -==== Update a variable on an execution - - ----- -PUT runtime/executions/{executionId}/variables/{variableName} ----- - - -.Update a variable on an execution - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|executionId|Yes|String|The id of the execution to update the variables for. -|variableName|Yes|String|Name of the variable to update. - -|=============== - - -*Request body:* - -[source,json,linenums] ----- - { - "name":"intProcVar" - "type":"integer" - "value":123, - "scope":"global" - } ----- - -More information about the variable format can be found in <>. - -.Update a variable on an execution - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates both the process instance and variable were found and variable is updated. -|404|Indicates the requested process instance was not found or the process instance does not have a variable with the given name. Status description contains additional information about the error. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- - { - "name":"intProcVar", - "type":"integer", - "value":123, - "scope":"global" - } ----- - - -In case the variable is a binary variable or serializable, the +valueUrl+ points to an URL to fetch the raw value. If it's a plain variable, the value is present in the response. - - -==== Create a new binary variable on an execution - ----- -POST runtime/executions/{executionId}/variables ----- - - -.Create a new binary variable on an execution - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|executionId|Yes|String|The id of the execution to create the new variable for. - -|=============== - - -*Request body:* - -The request should be of type +multipart/form-data+. There should be a single file-part included with the binary value of the variable. On top of that, the following additional form-fields can be present: - -* ++name++: Required name of the variable. -* ++type++: Type of variable that is created. If omitted, +binary+ is assumed and the binary data in the request will be stored as an array of bytes. -* ++scope++: Scope of variable that is created. If omitted, +local+ is assumed. - -*Success response body:* - -[source,json,linenums] ----- -{ - "name" : "binaryVariable", - "scope" : "local", - "type" : "binary", - "value" : null, - "valueUrl" : "http://.../runtime/executions/123/variables/binaryVariable/data" -} ----- - - -.Create a new binary variable on an execution - Response codes -[options="header"] -|=============== -|Response code|Description -|201|Indicates the variable was created and the result is returned. -|400|Indicates the name of the variable to create was missing. Status message provides additional information. -|404|Indicates the requested execution was not found. -|409|Indicates the execution already has a variable with the given name. Use the PUT method to update the task variable instead. -|415|Indicates the serializable data contains an object for which no class is present in the JVM running the Flowable engine and therefore cannot be deserialized. - -|=============== - - - -==== Update an existing binary variable on a process-instance - ----- -PUT runtime/executions/{executionId}/variables/{variableName} ----- - -.Update an existing binary variable on a process-instance - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|executionId|Yes|String|The id of the execution to create the new variable for. -|variableName|Yes|String|The name of the variable to update. - -|=============== - - -*Request body:* -The request should be of type +multipart/form-data+. There should be a single file-part included with the binary value of the variable. On top of that, the following additional form-fields can be present: - -* ++name++: Required name of the variable. -* ++type++: Type of variable that is created. If omitted, +binary+ is assumed and the binary data in the request will be stored as an array of bytes. -* ++scope++: Scope of variable that is created. If omitted, +local+ is assumed. - - -*Success response body:* - -[source,json,linenums] ----- -{ - "name" : "binaryVariable", - "scope" : "local", - "type" : "binary", - "value" : null, - "valueUrl" : "http://.../runtime/executions/123/variables/binaryVariable/data" -} ----- - - -.Update an existing binary variable on a process-instance - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the variable was updated and the result is returned. -|400|Indicates the name of the variable to update was missing. Status message provides additional information. -|404|Indicates the requested execution was not found or the execution does not have a variable with the given name. -|415|Indicates the serializable data contains an object for which no class is present in the JVM running the Flowable engine and therefore cannot be deserialized. - -|=============== - - - -=== Tasks - - -==== Get a task - ----- -GET runtime/tasks/{taskId} ----- - -.Get a task - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task to get. - -|=============== - - - -.Get a task - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the task was found and returned. -|404|Indicates the requested task was not found. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "assignee" : "kermit", - "createTime" : "2013-04-17T10:17:43.902+0000", - "delegationState" : "pending", - "description" : "Task description", - "dueDate" : "2013-04-17T10:17:43.902+0000", - "execution" : "http://localhost:8182/runtime/executions/5", - "id" : "8", - "name" : "My task", - "owner" : "owner", - "parentTask" : "http://localhost:8182/runtime/tasks/9", - "priority" : 50, - "processDefinition" : "http://localhost:8182/repository/process-definitions/oneTaskProcess%3A1%3A4", - "processInstance" : "http://localhost:8182/runtime/process-instances/5", - "suspended" : false, - "taskDefinitionKey" : "theTask", - "url" : "http://localhost:8182/runtime/tasks/8", - "tenantId" : null -} ----- - - -* ++delegationState++: Delegation-state of the task, can be +null+, +"pending"+ or +"resolved".+ - - -[[restTasksGet]] - - -==== List of tasks - ----- -GET runtime/tasks ----- - - -.List of tasks - URL query parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|name|No|String|Only return tasks with the given name. -|nameLike|No|String|Only return tasks with a name like the given name. -|description|No|String|Only return tasks with the given description. -|priority|No|Integer|Only return tasks with the given priority. -|minimumPriority|No|Integer|Only return tasks with a priority greater than the given value. -|maximumPriority|No|Integer|Only return tasks with a priority lower than the given value. -|assignee|No|String|Only return tasks assigned to the given user. -|assigneeLike|No|String|Only return tasks assigned with an assignee like the given value. -|owner|No|String|Only return tasks owned by the given user. -|ownerLike|No|String|Only return tasks assigned with an owner like the given value. -|unassigned|No|Boolean|Only return tasks that are not assigned to anyone. If +false+ is passed, the value is ignored. -|delegationState|No|String|Only return tasks that have the given delegation state. Possible values are +pending+ and +resolved+. -|candidateUser|No|String|Only return tasks that can be claimed by the given user. This includes both tasks where the user is an explicit candidate for and task that are claimable by a group that the user is a member of. -|candidateGroup|No|String|Only return tasks that can be claimed by a user in the given group. -|candidateGroups|No|String|Only return tasks that can be claimed by a user in the given groups. Values split by comma. -|involvedUser|No|String|Only return tasks in which the given user is involved. -|taskDefinitionKey|No|String|Only return tasks with the given task definition id. -|taskDefinitionKeyLike|No|String|Only return tasks with a given task definition id like the given value. -|processInstanceId|No|String|Only return tasks which are part of the process instance with the given id. -|processInstanceBusinessKey|No|String|Only return tasks which are part of the process instance with the given business key. -|processInstanceBusinessKeyLike|No|String|Only return tasks which are part of the process instance which has a business key like the given value. -|processDefinitionId|No|String|Only return tasks which are part of a process instance which has a process definition with the given id. -|processDefinitionKey|No|String|Only return tasks which are part of a process instance which has a process definition with the given key. -|processDefinitionKeyLike|No|String|Only return tasks which are part of a process instance which has a process definition with a key like the given value. -|processDefinitionName|No|String|Only return tasks which are part of a process instance which has a process definition with the given name. -|processDefinitionNameLike|No|String|Only return tasks which are part of a process instance which has a process definition with a name like the given value. -|executionId|No|String|Only return tasks which are part of the execution with the given id. -|createdOn|No|ISO Date|Only return tasks which are created on the given date. -|createdBefore|No|ISO Date|Only return tasks which are created before the given date. -|createdAfter|No|ISO Date|Only return tasks which are created after the given date. -|dueOn|No|ISO Date|Only return tasks which are due on the given date. -|dueBefore|No|ISO Date|Only return tasks which are due before the given date. -|dueAfter|No|ISO Date|Only return tasks which are due after the given date. -|withoutDueDate|No|boolean|Only return tasks which don't have a due date. The property is ignored if the value is +false+. -|excludeSubTasks|No|Boolean|Only return tasks that are not a subtask of another task. -|active|No|Boolean|If +true+, only return tasks that are not suspended (either part of a process that is not suspended or not part of a process at all). If false, only tasks that are part of suspended process instances are returned. -|includeTaskLocalVariables|No|Boolean|Indication to include task local variables in the result. -|includeProcessVariables|No|Boolean|Indication to include process variables in the result. -|tenantId|No|String|Only return tasks with the given tenantId. -|tenantIdLike|No|String|Only return tasks with a tenantId like the given value. -|withoutTenantId|No|Boolean|If +true+, only returns tasks without a tenantId set. If +false+, the +withoutTenantId+ parameter is ignored. -|candidateOrAssigned|No|String|Select tasks that has been claimed or assigned to user or waiting to claim by user (candidate user or groups). -|category|No|string|Select tasks with the given category. Note that this is the task category, not the category of the process definition (namespace within the BPMN Xml). -|The general <> can be used for this URL. - -|=============== - - -.List of tasks - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates request was successful and the tasks are returned -|400|Indicates a parameter was passed in the wrong format or that 'delegationState' has an invalid value (other than 'pending' and 'resolved'). The status-message contains additional information. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "data": [ - { - "assignee" : "kermit", - "createTime" : "2013-04-17T10:17:43.902+0000", - "delegationState" : "pending", - "description" : "Task description", - "dueDate" : "2013-04-17T10:17:43.902+0000", - "execution" : "http://localhost:8182/runtime/executions/5", - "id" : "8", - "name" : "My task", - "owner" : "owner", - "parentTask" : "http://localhost:8182/runtime/tasks/9", - "priority" : 50, - "processDefinition" : "http://localhost:8182/repository/process-definitions/oneTaskProcess%3A1%3A4", - "processInstance" : "http://localhost:8182/runtime/process-instances/5", - "suspended" : false, - "taskDefinitionKey" : "theTask", - "url" : "http://localhost:8182/runtime/tasks/8", - "tenantId" : null - } - ], - "total": 1, - "start": 0, - "sort": "name", - "order": "asc", - "size": 1 -} ----- - - - -==== Query for tasks - ----- -POST query/tasks ----- - - -*Request body:* - -[source,json,linenums] ----- -{ - "name" : "My task", - "description" : "The task description", - - ... - - "taskVariables" : [ - { - "name" : "myVariable", - "value" : 1234, - "operation" : "equals", - "type" : "long" - } - ], - - "processInstanceVariables" : [ - { - ... - } - ] - ] -} ----- - - - -All supported JSON parameter fields allowed are exactly the same as the parameters found for <> (except for candidateGroupIn which is only available in this POST task query REST service), but passed in as JSON-body arguments rather than URL-parameters to allow for more advanced querying and preventing errors with request-uri's that are too long. On top of that, the query allows for filtering based on task and process variables. The +taskVariables+ and +processInstanceVariables+ are both JSON-arrays containing objects with the format <> - - -.Query for tasks - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates request was successful and the tasks are returned -|400|Indicates a parameter was passed in the wrong format or that 'delegationState' has an invalid value (other than 'pending' and 'resolved'). The status-message contains additional information. - -|=============== - - - -*Success response body:* - -[source,json,linenums] ----- -{ - "data": [ - { - "assignee" : "kermit", - "createTime" : "2013-04-17T10:17:43.902+0000", - "delegationState" : "pending", - "description" : "Task description", - "dueDate" : "2013-04-17T10:17:43.902+0000", - "execution" : "http://localhost:8182/runtime/executions/5", - "id" : "8", - "name" : "My task", - "owner" : "owner", - "parentTask" : "http://localhost:8182/runtime/tasks/9", - "priority" : 50, - "processDefinition" : "http://localhost:8182/repository/process-definitions/oneTaskProcess%3A1%3A4", - "processInstance" : "http://localhost:8182/runtime/process-instances/5", - "suspended" : false, - "taskDefinitionKey" : "theTask", - "url" : "http://localhost:8182/runtime/tasks/8", - "tenantId" : null - } - ], - "total": 1, - "start": 0, - "sort": "name", - "order": "asc", - "size": 1 -} ----- - - -==== Update a task - - ----- -PUT runtime/tasks/{taskId} ----- - - -*Body JSON:* - -[source,json,linenums] ----- -{ - "assignee" : "assignee", - "delegationState" : "resolved", - "description" : "New task description", - "dueDate" : "2013-04-17T13:06:02.438+02:00", - "name" : "New task name", - "owner" : "owner", - "parentTaskId" : "3", - "priority" : 20 -} ----- - -All request values are optional. For example, you can only include the 'assignee' attribute in the request body JSON-object, only updating the assignee of the task, leaving all other fields unaffected. When an attribute is explicitly included and is set to null, the task-value will be updated to null. Example: +{"dueDate" : null}+ will clear the duedate of the task). - - -.Update a task - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the task was updated. -|404|Indicates the requested task was not found. -|409|Indicates the requested task was updated simultaneously. - -|=============== - - -*Success response body:* see response for +runtime/tasks/{taskId}+. - - -==== Task actions - ----- -POST runtime/tasks/{taskId} ----- - -*Complete a task - Body JSON:* - -[source,json,linenums] ----- -{ - "action" : "complete", - "variables" : [] -} ----- - - -Completes the task. Optional variable array can be passed in using the +variables+ property. More information about the variable format can be found in <>. Note that the variable-scope is applied. If scope isn't indicated, variables are set to the parent-scope and if indicated, variables are set to the scope that is provided. - -Note that also a _transientVariables_ property is accepted as part of this json, that follows the same structure as the _variables_ property. - -*Claim a task - Body JSON:* - -[source,json,linenums] ----- -{ - "action" : "claim", - "assignee" : "userWhoClaims" -} ----- - -Claims the task by the given assignee. If the assignee is +null+, the task is assigned to no-one, claimable again. - -*Delegate a task - Body JSON:* - -[source,json,linenums] ----- -{ - "action" : "delegate", - "assignee" : "userToDelegateTo" -} ----- - - -Delegates the task to the given assignee. The assignee is required. - -*Resolve a task - Body JSON:* - -[source,json,linenums] ----- - -{ - "action" : "resolve" -} ----- - - -Resolves the task delegation. The task is assigned back to the task owner (if any). - - -.Task actions - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the action was executed. -|400|When the body contains an invalid value or when the assignee is missing when the action requires it. -|404|Indicates the requested task was not found. -|409|Indicates the action cannot be performed due to a conflict. Either the task was updates simultaneously or the task was claimed by another user, in case of the '++claim++' action. - -|=============== - - -*Success response body:* see response for +runtime/tasks/{taskId}+. - - -==== Delete a task - - ----- -DELETE runtime/tasks/{taskId}?cascadeHistory={cascadeHistory}&deleteReason={deleteReason} ----- - - -.>Delete a task - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task to delete. -|cascadeHistory|False|Boolean|Whether or not to delete the HistoricTask instance when deleting the task (if applicable). If not provided, this value defaults to false. -|deleteReason|False|String|Reason why the task is deleted. This value is ignored when +cascadeHistory+ is true. - -|=============== - - -.>Delete a task - Response codes -[options="header"] -|=============== -|Response code|Description -|204|Indicates the task was found and has been deleted. Response-body is intentionally empty. -|403|Indicates the requested task cannot be deleted because it's part of a workflow. -|404|Indicates the requested task was not found. - -|=============== - - - -==== Get all variables for a task - ----- -GET runtime/tasks/{taskId}/variables?scope={scope} ----- - - -.Get all variables for a task - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task to get variables for. -|scope|False|String|Scope of variables to be returned. When '++local++', only task-local variables are returned. When '++global++', only variables from the task's parent execution-hierarchy are returned. When the parameter is omitted, both local and global variables are returned. - -|=============== - - -.Get all variables for a task - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the task was found and the requested variables are returned. -|404|Indicates the requested task was not found. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -[ - { - "name" : "doubleTaskVar", - "scope" : "local", - "type" : "double", - "value" : 99.99 - }, - { - "name" : "stringProcVar", - "scope" : "global", - "type" : "string", - "value" : "This is a ProcVariable" - } - - - -] ----- - -The variables are returned as a JSON array. Full response description can be found in the general <>. - - -==== Get a variable from a task - ----- -GET runtime/tasks/{taskId}/variables/{variableName}?scope={scope} ----- - - -.Get a variable from a task - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task to get a variable for. -|variableName|Yes|String|The name of the variable to get. -|scope|False|String|Scope of variable to be returned. When '++local++', only task-local variable value is returned. When '++global++', only variable value from the task's parent execution-hierarchy are returned. When the parameter is omitted, a local variable will be returned if it exists, otherwise a global variable. - -|=============== - - -.Get a variable from a task - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the task was found and the requested variables are returned. -|404|Indicates the requested task was not found or the task doesn't have a variable with the given name (in the given scope). Status message provides additional information. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "name" : "myTaskVariable", - "scope" : "local", - "type" : "string", - "value" : "Hello my friend" -} ----- - - -Full response body description can be found in the general <>. - - -==== Get the binary data for a variable - ----- -GET runtime/tasks/{taskId}/variables/{variableName}/data?scope={scope} ----- - - -.Get the binary data for a variable - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task to get a variable data for. -|variableName|Yes|String|The name of the variable to get data for. Only variables of type +binary+ and +serializable+ can be used. If any other type of variable is used, a +404+ is returned. -|scope|False|String|Scope of variable to be returned. When '++local++', only task-local variable value is returned. When '++global++', only variable value from the task's parent execution-hierarchy are returned. When the parameter is omitted, a local variable will be returned if it exists, otherwise a global variable. - -|=============== - - - -.Get the binary data for a variable - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the task was found and the requested variables are returned. -|404|Indicates the requested task was not found or the task doesn't have a variable with the given name (in the given scope) or the variable doesn't have a binary stream available. Status message provides additional information. - -|=============== - - - -*Success response body:* - -The response body contains the binary value of the variable. When the variable is of type +binary+, the content-type of the response is set to +application/octet-stream+, regardless of the content of the variable or the request accept-type header. In case of +serializable+, +application/x-java-serialized-object+ is used as content-type. - - - -==== Create new variables on a task - - ----- -POST runtime/tasks/{taskId}/variables ----- - - -.Create new variables on a task - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task to create the new variable for. - -|=============== - - -*Request body for creating simple (non-binary) variables:* - -[source,json,linenums] ----- -[ - { - "name" : "myTaskVariable", - "scope" : "local", - "type" : "string", - "value" : "Hello my friend" - }, - { - - } -] ----- - - -The request body should be an array containing one or more JSON-objects representing the variables that should be created. - -* ++name++: Required name of the variable -* ++scope++: Scope of variable that is created. If omitted, +local+ is assumed. -* ++type++: Type of variable that is created. If omitted, reverts to raw JSON-value type (string, boolean, integer or double). -* ++value++: Variable value. - -More information about the variable format can be found in <>. - - - -*Success response body:* - -[source,json,linenums] ----- -[ - { - "name" : "myTaskVariable", - "scope" : "local", - "type" : "string", - "value" : "Hello my friend" - }, - { - - } -] ----- - - -.Create new variables on a task - Response codes -[options="header"] -|=============== -|Response code|Description -|201|Indicates the variables were created and the result is returned. -|400|Indicates the name of a variable to create was missing or that an attempt is done to create a variable on a standalone task (without a process associated) with scope +global+ or an empty array of variables was included in the request or request did not contain an array of variables. Status message provides additional information. -|404|Indicates the requested task was not found. -|409|Indicates the task already has a variable with the given name. Use the PUT method to update the task variable instead. - -|=============== - - -==== Create a new binary variable on a task - ----- -POST runtime/tasks/{taskId}/variables ----- - - -.Create a new binary variable on a task - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task to create the new variable for. - -|=============== - - -*Request body:* - -The request should be of type +multipart/form-data+. There should be a single file-part included with the binary value of the variable. On top of that, the following additional form-fields can be present: - -* ++name++: Required name of the variable. -* ++scope++: Scope of variable that is created. If omitted, +local+ is assumed. -* ++type++: Type of variable that is created. If omitted, +binary+ is assumed and the binary data in the request will be stored as an array of bytes. - - -*Success response body:* - -[source,json,linenums] ----- -{ - "name" : "binaryVariable", - "scope" : "local", - "type" : "binary", - "value" : null, - "valueUrl" : "http://.../runtime/tasks/123/variables/binaryVariable/data" -} ----- - -.Create a new binary variable on a task - Response codes -[options="header"] -|=============== -|Response code|Description -|201|Indicates the variable was created and the result is returned. -|400|Indicates the name of the variable to create was missing or that an attempt is done to create a variable on a standalone task (without a process associated) with scope +global+. Status message provides additional information. -|404|Indicates the requested task was not found. -|409|Indicates the task already has a variable with the given name. Use the PUT method to update the task variable instead. -|415|Indicates the serializable data contains an object for which no class is present in the JVM running the Flowable engine and therefore cannot be deserialized. - -|=============== - - - -==== Update an existing variable on a task - - ----- -PUT runtime/tasks/{taskId}/variables/{variableName} ----- - - -.Update an existing variable on a task - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task to update the variable for. -|variableName|Yes|String|The name of the variable to update. - -|=============== - - -*Request body for updating simple (non-binary) variables:* - -[source,json,linenums] ----- -{ - "name" : "myTaskVariable", - "scope" : "local", - "type" : "string", - "value" : "Hello my friend" -} ----- - - -* ++name++: Required name of the variable -* ++scope++: Scope of variable that is updated. If omitted, +local+ is assumed. -* ++type++: Type of variable that is updated. If omitted, reverts to raw JSON-value type (string, boolean, integer or double). -* ++value++: Variable value. - - -More information about the variable format can be found in <>. - - -*Success response body:* - -[source,json,linenums] ----- -{ - "name" : "myTaskVariable", - "scope" : "local", - "type" : "string", - "value" : "Hello my friend" -} ----- - - -.Update an existing variable on a task - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the variables was updated and the result is returned. -|400|Indicates the name of a variable to update was missing or that an attempt is done to update a variable on a standalone task (without a process associated) with scope +global+. Status message provides additional information. -|404|Indicates the requested task was not found or the task doesn't have a variable with the given name in the given scope. Status message contains additional information about the error. - -|=============== - - - -==== Updating a binary variable on a task - ----- -PUT runtime/tasks/{taskId}/variables/{variableName} ----- - -.Updating a binary variable on a task - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task to update the variable for. -|variableName|Yes|String|The name of the variable to update. - -|=============== - - - -*Request body:* - -The request should be of type +multipart/form-data+. There should be a single file-part included with the binary value of the variable. On top of that, the following additional form-fields can be present: - -* ++name++: Required name of the variable. -* ++scope++: Scope of variable that is updated. If omitted, +local+ is assumed. -* ++type++: Type of variable that is updated. If omitted, +binary+ is assumed and the binary data in the request will be stored as an array of bytes. - - -*Success response body:* - -[source,json,linenums] ----- -{ - "name" : "binaryVariable", - "scope" : "local", - "type" : "binary", - "value" : null, - "valueUrl" : "http://.../runtime/tasks/123/variables/binaryVariable/data" -} ----- - - -.Updating a binary variable on a task - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the variable was updated and the result is returned. -|400|Indicates the name of the variable to update was missing or that an attempt is done to update a variable on a standalone task (without a process associated) with scope +global+. Status message provides additional information. -|404|Indicates the requested task was not found or the variable to update doesn't exist for the given task in the given scope. -|415|Indicates the serializable data contains an object for which no class is present in the JVM running the Flowable engine and therefore cannot be deserialized. - -|=============== - - - -==== Delete a variable on a task - ----- -DELETE runtime/tasks/{taskId}/variables/{variableName}?scope={scope} ----- - - -.Delete a variable on a task - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task the variable to delete belongs to. -|variableName|Yes|String|The name of the variable to delete. -|scope|No|String|Scope of variable to delete in. Can be either +local+ or +global+. If omitted, +local+ is assumed. - -|=============== - - -.Delete a variable on a task - Response codes -[options="header"] -|=============== -|Response code|Description -|204|Indicates the task variable was found and has been deleted. Response-body is intentionally empty. -|404|Indicates the requested task was not found or the task doesn't have a variable with the given name. Status message contains additional information about the error. - -|=============== - - - -==== Delete all local variables on a task - ----- -DELETE runtime/tasks/{taskId}/variables ----- - -.Delete all local variables on a task - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task the variable to delete belongs to. - -|=============== - - -.Delete all local variables on a task - Response codes -[options="header"] -|=============== -|Response code|Description -|204|Indicates all local task variables have been deleted. Response-body is intentionally empty. -|404|Indicates the requested task was not found. - -|=============== - - - -==== Get all identity links for a task - - ----- -GET runtime/tasks/{taskId}/identitylinks ----- - - -.Get all identity links for a task - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task to get the identity links for. - -|=============== - - -.Get all identity links for a task - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the task was found and the requested identity links are returned. -|404|Indicates the requested task was not found. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -[ - { - "userId" : "kermit", - "groupId" : null, - "type" : "candidate", - "url" : "http://localhost:8081/flowable-rest/service/runtime/tasks/100/identitylinks/users/kermit/candidate" - }, - { - "userId" : null, - "groupId" : "sales", - "type" : "candidate", - "url" : "http://localhost:8081/flowable-rest/service/runtime/tasks/100/identitylinks/groups/sales/candidate" - }, - - ... -] ----- - - - -==== Get all identitylinks for a task for either groups or users - ----- -GET runtime/tasks/{taskId}/identitylinks/users -GET runtime/tasks/{taskId}/identitylinks/groups ----- - - -Returns only identity links targeting either users or groups. Response body and status-codes are exactly the same as when getting the full list of identity links for a task. - - -==== Get a single identity link on a task - - - ----- -GET runtime/tasks/{taskId}/identitylinks/{family}/{identityId}/{type} ----- - - -.Get all identitylinks for a task for either groups or users - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task . -|family|Yes|String|Either +groups+ or +users+, depending on what kind of identity is targeted. -|identityId|Yes|String|The id of the identity. -|type|Yes|String|The type of identity link. - -|=============== - - -.Get all identitylinks for a task for either groups or users - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the task and identity link was found and returned. -|404|Indicates the requested task was not found or the task doesn't have the requested identityLink. The status contains additional information about this error. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "userId" : null, - "groupId" : "sales", - "type" : "candidate", - "url" : "http://localhost:8081/flowable-rest/service/runtime/tasks/100/identitylinks/groups/sales/candidate" -} ----- - - -==== Create an identity link on a task - - ----- -POST runtime/tasks/{taskId}/identitylinks ----- - - -.Create an identity link on a task - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task . - -|=============== - - - -*Request body (user):* - -[source,json,linenums] ----- -{ - "userId" : "kermit", - "type" : "candidate", -} ----- - - -*Request body (group):* - -[source,json,linenums] ----- -{ - "groupId" : "sales", - "type" : "candidate", -} ----- - -.Create an identity link on a task - Response codes -[options="header"] -|=============== -|Response code|Description -|201|Indicates the task was found and the identity link was created. -|404|Indicates the requested task was not found or the task doesn't have the requested identityLink. The status contains additional information about this error. - -|=============== - - - -*Success response body:* - -[source,json,linenums] ----- -{ - "userId" : null, - "groupId" : "sales", - "type" : "candidate", - "url" : "http://localhost:8081/flowable-rest/service/runtime/tasks/100/identitylinks/groups/sales/candidate" -} ----- - - -==== Delete an identity link on a task - ----- -DELETE runtime/tasks/{taskId}/identitylinks/{family}/{identityId}/{type} ----- - -.Delete an identity link on a task - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task. -|family|Yes|String|Either +groups+ or +users+, depending on what kind of identity is targeted. -|identityId|Yes|String|The id of the identity. -|type|Yes|String|The type of identity link. - -|=============== - - -.Delete an identity link on a task - Response codes -[options="header"] -|=============== -|Response code|Description -|204|Indicates the task and identity link were found and the link has been deleted. Response-body is intentionally empty. -|404|Indicates the requested task was not found or the task doesn't have the requested identityLink. The status contains additional information about this error. - -|=============== - - - - -==== Create a new comment on a task - - ----- -POST runtime/tasks/{taskId}/comments ----- - -.Create a new comment on a task - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task to create the comment for. - -|=============== - - -*Request body:* - -[source,json,linenums] ----- -{ - "message" : "This is a comment on the task.", - "saveProcessInstanceId" : true -} ----- - - -Parameter +saveProcessInstanceId+ is optional, if +true+ save process instance id of task with comment. - -*Success response body:* - -[source,json,linenums] ----- -{ - "id" : "123", - "taskUrl" : "http://localhost:8081/flowable-rest/service/runtime/tasks/101/comments/123", - "processInstanceUrl" : "http://localhost:8081/flowable-rest/service/history/historic-process-instances/100/comments/123", - "message" : "This is a comment on the task.", - "author" : "kermit", - "time" : "2014-07-13T13:13:52.232+08:00" - "taskId" : "101", - "processInstanceId" : "100" -} ----- - - -.Create a new comment on a task - Response codes -[options="header"] -|=============== -|Response code|Description -|201|Indicates the comment was created and the result is returned. -|400|Indicates the comment is missing from the request. -|404|Indicates the requested task was not found. - -|=============== - - - -==== Get all comments on a task - ----- -GET runtime/tasks/{taskId}/comments ----- - -.Get all comments on a task - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task to get the comments for. - -|=============== - -*Success response body:* - -[source,json,linenums] ----- -[ - { - "id" : "123", - "taskUrl" : "http://localhost:8081/flowable-rest/service/runtime/tasks/101/comments/123", - "processInstanceUrl" : "http://localhost:8081/flowable-rest/service/history/historic-process-instances/100/comments/123", - "message" : "This is a comment on the task.", - "author" : "kermit" - "time" : "2014-07-13T13:13:52.232+08:00" - "taskId" : "101", - "processInstanceId" : "100" - }, - { - "id" : "456", - "taskUrl" : "http://localhost:8081/flowable-rest/service/runtime/tasks/101/comments/456", - "processInstanceUrl" : "http://localhost:8081/flowable-rest/service/history/historic-process-instances/100/comments/456", - "message" : "This is another comment on the task.", - "author" : "gonzo", - "time" : "2014-07-13T13:13:52.232+08:00" - "taskId" : "101", - "processInstanceId" : "100" - } -] ----- - - -.Get all comments on a task - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the task was found and the comments are returned. -|404|Indicates the requested task was not found. - -|=============== - - - -==== Get a comment on a task - ----- -GET runtime/tasks/{taskId}/comments/{commentId} ----- - - -.Get a comment on a task - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task to get the comment for. -|commentId|Yes|String|The id of the comment. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "id" : "123", - "taskUrl" : "http://localhost:8081/flowable-rest/service/runtime/tasks/101/comments/123", - "processInstanceUrl" : "http://localhost:8081/flowable-rest/service/history/historic-process-instances/100/comments/123", - "message" : "This is a comment on the task.", - "author" : "kermit", - "time" : "2014-07-13T13:13:52.232+08:00" - "taskId" : "101", - "processInstanceId" : "100" -} ----- - -.Get a comment on a task - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the task and comment were found and the comment is returned. -|404|Indicates the requested task was not found or the tasks doesn't have a comment with the given ID. - -|=============== - - -==== Delete a comment on a task - ----- -DELETE runtime/tasks/{taskId}/comments/{commentId} ----- - -.Delete a comment on a task - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task to delete the comment for. -|commentId|Yes|String|The id of the comment. - -|=============== - - -.Delete a comment on a task - Response codes -[options="header"] -|=============== -|Response code|Description -|204|Indicates the task and comment were found and the comment is deleted. Response body is left empty intentionally. -|404|Indicates the requested task was not found or the tasks doesn't have a comment with the given ID. - -|=============== - - -==== Get all events for a task - ----- -GET runtime/tasks/{taskId}/events ----- - -.Get all events for a task - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task to get the events for. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -[ - { - "action" : "AddUserLink", - "id" : "4", - "message" : [ "gonzo", "contributor" ], - "taskUrl" : "http://localhost:8182/runtime/tasks/2", - "time" : "2013-05-17T11:50:50.000+0000", - "url" : "http://localhost:8182/runtime/tasks/2/events/4", - "userId" : null - } - -] ----- - - -.Get all events for a task - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the task was found and the events are returned. -|404|Indicates the requested task was not found. - -|=============== - - - -==== Get an event on a task - ----- -GET runtime/tasks/{taskId}/events/{eventId} ----- - -.Get an event on a task - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task to get the event for. -|eventId|Yes|String|The id of the event. - -|=============== - - - -*Success response body:* - -[source,json,linenums] ----- -{ - "action" : "AddUserLink", - "id" : "4", - "message" : [ "gonzo", "contributor" ], - "taskUrl" : "http://localhost:8182/runtime/tasks/2", - "time" : "2013-05-17T11:50:50.000+0000", - "url" : "http://localhost:8182/runtime/tasks/2/events/4", - "userId" : null -} ----- - - -.Get an event on a task - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the task and event were found and the event is returned. -|404|Indicates the requested task was not found or the tasks doesn't have an event with the given ID. - -|=============== - - - -==== Create a new attachment on a task, containing a link to an external resource - ----- -POST runtime/tasks/{taskId}/attachments ----- - -.Create a new attachment on a task, containing a link to an external resource - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task to create the attachment for. - -|=============== - - -*Request body:* - -[source,json,linenums] ----- -{ - "name":"Simple attachment", - "description":"Simple attachment description", - "type":"simpleType", - "externalUrl":"http://flowable.org" -} ----- - - -Only the attachment name is required to create a new attachment. - - - -*Success response body:* - -[source,json,linenums] ----- -{ - "id":"3", - "url":"http://localhost:8182/runtime/tasks/2/attachments/3", - "name":"Simple attachment", - "description":"Simple attachment description", - "type":"simpleType", - "taskUrl":"http://localhost:8182/runtime/tasks/2", - "processInstanceUrl":null, - "externalUrl":"http://flowable.org", - "contentUrl":null -} ----- - - -.Create a new attachment on a task, containing a link to an external resource - Response codes -[options="header"] -|=============== -|Response code|Description -|201|Indicates the attachment was created and the result is returned. -|400|Indicates the attachment name is missing from the request. -|404|Indicates the requested task was not found. - -|=============== - - - -==== Create a new attachment on a task, with an attached file - ----- -POST runtime/tasks/{taskId}/attachments ----- - -.Create a new attachment on a task, with an attached file - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task to create the attachment for. - -|=============== - - -*Request body:* - -The request should be of type +multipart/form-data+. There should be a single file-part included with the binary value of the variable. On top of that, the following additional form-fields can be present: - -* ++name++: Required name of the variable. -* ++description++: Description of the attachment, optional. -* ++type++: Type of attachment, optional. Supports any arbitrary string or a valid HTTP content-type. - -*Success response body:* - -[source,json,linenums] ----- -{ - "id":"5", - "url":"http://localhost:8182/runtime/tasks/2/attachments/5", - "name":"Binary attachment", - "description":"Binary attachment description", - "type":"binaryType", - "taskUrl":"http://localhost:8182/runtime/tasks/2", - "processInstanceUrl":null, - "externalUrl":null, - "contentUrl":"http://localhost:8182/runtime/tasks/2/attachments/5/content" -} ----- - - -.Create a new attachment on a task, with an attached file - Response codes -[options="header"] -|=============== -|Response code|Description -|201|Indicates the attachment was created and the result is returned. -|400|Indicates the attachment name is missing from the request or no file was present in the request. The error-message contains additional information. -|404|Indicates the requested task was not found. - -|=============== - - -==== Get all attachments on a task - ----- -GET runtime/tasks/{taskId}/attachments ----- - - -.Get all attachments on a task - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task to get the attachments for. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -[ - { - "id":"3", - "url":"http://localhost:8182/runtime/tasks/2/attachments/3", - "name":"Simple attachment", - "description":"Simple attachment description", - "type":"simpleType", - "taskUrl":"http://localhost:8182/runtime/tasks/2", - "processInstanceUrl":null, - "externalUrl":"http://flowable.org", - "contentUrl":null - }, - { - "id":"5", - "url":"http://localhost:8182/runtime/tasks/2/attachments/5", - "name":"Binary attachment", - "description":"Binary attachment description", - "type":"binaryType", - "taskUrl":"http://localhost:8182/runtime/tasks/2", - "processInstanceUrl":null, - "externalUrl":null, - "contentUrl":"http://localhost:8182/runtime/tasks/2/attachments/5/content" - } -] ----- - - -.Get all attachments on a task - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the task was found and the attachments are returned. -|404|Indicates the requested task was not found. - -|=============== - - - - -==== Get an attachment on a task - ----- -GET runtime/tasks/{taskId}/attachments/{attachmentId} ----- - -.Get an attachment on a task - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task to get the attachment for. -|attachmentId|Yes|String|The id of the attachment. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "id":"5", - "url":"http://localhost:8182/runtime/tasks/2/attachments/5", - "name":"Binary attachment", - "description":"Binary attachment description", - "type":"binaryType", - "taskUrl":"http://localhost:8182/runtime/tasks/2", - "processInstanceUrl":null, - "externalUrl":null, - "contentUrl":"http://localhost:8182/runtime/tasks/2/attachments/5/content" -} ----- - - -* ++externalUrl - contentUrl:++In case the attachment is a link to an external resource, the +externalUrl+ contains the URL to the external content. If the attachment content is present in the Flowable engine, the +contentUrl+ will contain an URL where the binary content can be streamed from. -* ++type:++Can be any arbitrary value. When a valid formatted media-type (e.g. application/xml, text/plain) is included, the binary content HTTP response content-type will be set the given value. - -.Get an attachment on a task - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the task and attachment were found and the attachment is returned. -|404|Indicates the requested task was not found or the tasks doesn't have a attachment with the given ID. - -|=============== - - - -==== Get the content for an attachment - - ----- -GET runtime/tasks/{taskId}/attachment/{attachmentId}/content ----- - -.Get the content for an attachment - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task to get a variable data for. -|attachmentId|Yes|String|The id of the attachment, a +404+ is returned when the attachment points to an external URL rather than content attached in Flowable. - -|=============== - - -.Get the content for an attachment - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the task and attachment was found and the requested content is returned. -|404|Indicates the requested task was not found or the task doesn't have an attachment with the given id or the attachment doesn't have a binary stream available. Status message provides additional information. - -|=============== - - -*Success response body:* - -The response body contains the binary content. By default, the content-type of the response is set to +application/octet-stream+ unless the attachment type contains a valid Content-type. - - -==== Delete an attachment on a task - - ----- -DELETE runtime/tasks/{taskId}/attachments/{attachmentId} ----- - -.Delete an attachment on a task - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes|String|The id of the task to delete the attachment for. -|attachmentId|Yes|String|The id of the attachment. - -|=============== - - -.Delete an attachment on a task - Response codes -[options="header"] -|=============== -|Response code|Description -|204|Indicates the task and attachment were found and the attachment is deleted. Response body is left empty intentionally. -|404|Indicates the requested task was not found or the tasks doesn't have a attachment with the given ID. - -|=============== - - -=== History - -==== Get a historic process instance - - ----- -GET history/historic-process-instances/{processInstanceId} ----- - -.Get a historic process instance - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates that the historic process instances could be found. -|404|Indicates that the historic process instances could not be found. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "data": [ - { - "id" : "5", - "businessKey" : "myKey", - "processDefinitionId" : "oneTaskProcess%3A1%3A4", - "processDefinitionUrl" : "http://localhost:8182/repository/process-definitions/oneTaskProcess%3A1%3A4", - "startTime" : "2013-04-17T10:17:43.902+0000", - "endTime" : "2013-04-18T14:06:32.715+0000", - "durationInMillis" : 86400056, - "startUserId" : "kermit", - "startActivityId" : "startEvent", - "endActivityId" : "endEvent", - "deleteReason" : null, - "superProcessInstanceId" : "3", - "url" : "http://localhost:8182/history/historic-process-instances/5", - "variables": null, - "tenantId":null - } - ], - "total": 1, - "start": 0, - "sort": "name", - "order": "asc", - "size": 1 -} ----- - - -[[restHistoricProcessInstancesGet]] - - -==== List of historic process instances - ----- -GET history/historic-process-instances ----- - -.List of historic process instances - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|processInstanceId|No|String|An id of the historic process instance. -|processDefinitionKey|No|String|The process definition key of the historic process instance. -|processDefinitionId|No|String|The process definition id of the historic process instance. -|businessKey|No|String|The business key of the historic process instance. -|involvedUser|No|String|An involved user of the historic process instance. -|finished|No|Boolean|Indication if the historic process instance is finished. -|superProcessInstanceId|No|String|An optional parent process id of the historic process instance. -|excludeSubprocesses|No|Boolean|Return only historic process instances which aren't sub processes. -|finishedAfter|No|Date|Return only historic process instances that were finished after this date. -|finishedBefore|No|Date|Return only historic process instances that were finished before this date. -|startedAfter|No|Date|Return only historic process instances that were started after this date. -|startedBefore|No|Date|Return only historic process instances that were started before this date. -|startedBy|No|String|Return only historic process instances that were started by this user. -|includeProcessVariables|No|Boolean|An indication if the historic process instance variables should be returned as well. -|tenantId|No|String|Only return instances with the given tenantId. -|tenantIdLike|No|String|Only return instances with a tenantId like the given value. -|withoutTenantId|No|Boolean|If +true+, only returns instances without a tenantId set. If +false+, the +withoutTenantId+ parameter is ignored. -|The general <> can be used for this URL. - -|=============== - - -.List of historic process instances - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates that historic process instances could be queried. -|400|Indicates an parameter was passed in the wrong format. The status-message contains additional information. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "data": [ - { - "id" : "5", - "businessKey" : "myKey", - "processDefinitionId" : "oneTaskProcess%3A1%3A4", - "processDefinitionUrl" : "http://localhost:8182/repository/process-definitions/oneTaskProcess%3A1%3A4", - "startTime" : "2013-04-17T10:17:43.902+0000", - "endTime" : "2013-04-18T14:06:32.715+0000", - "durationInMillis" : 86400056, - "startUserId" : "kermit", - "startActivityId" : "startEvent", - "endActivityId" : "endEvent", - "deleteReason" : null, - "superProcessInstanceId" : "3", - "url" : "http://localhost:8182/history/historic-process-instances/5", - "variables": [ - { - "name": "test", - "variableScope": "local", - "value": "myTest" - } - ], - "tenantId":null - } - ], - "total": 1, - "start": 0, - "sort": "name", - "order": "asc", - "size": 1 -} ----- - - -==== Query for historic process instances - ----- -POST query/historic-process-instances ----- - -*Request body:* - -[source,json,linenums] ----- -{ - "processDefinitionId" : "oneTaskProcess%3A1%3A4", - - - "variables" : [ - { - "name" : "myVariable", - "value" : 1234, - "operation" : "equals", - "type" : "long" - } - ] -} ----- - -All supported JSON parameter fields allowed are exactly the same as the parameters found for <>, but passed in as JSON-body arguments rather than URL-parameters to allow for more advanced querying and preventing errors with request-uri's that are too long. On top of that, the query allows for filtering based on process variables. The +variables+ property is a JSON-array containing objects with the format <> - - -.Query for historic process instances - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates request was successful and the tasks are returned -|400|Indicates an parameter was passed in the wrong format. The status-message contains additional information. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "data": [ - { - "id" : "5", - "businessKey" : "myKey", - "processDefinitionId" : "oneTaskProcess%3A1%3A4", - "processDefinitionUrl" : "http://localhost:8182/repository/process-definitions/oneTaskProcess%3A1%3A4", - "startTime" : "2013-04-17T10:17:43.902+0000", - "endTime" : "2013-04-18T14:06:32.715+0000", - "durationInMillis" : 86400056, - "startUserId" : "kermit", - "startActivityId" : "startEvent", - "endActivityId" : "endEvent", - "deleteReason" : null, - "superProcessInstanceId" : "3", - "url" : "http://localhost:8182/history/historic-process-instances/5", - "variables": [ - { - "name": "test", - "variableScope": "local", - "value": "myTest" - } - ], - "tenantId":null - } - ], - "total": 1, - "start": 0, - "sort": "name", - "order": "asc", - "size": 1 -} ----- - - -==== Delete a historic process instance - ----- -DELETE history/historic-process-instances/{processInstanceId} ----- - - -.Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates that the historic process instance was deleted. -|404|Indicates that the historic process instance could not be found. - -|=============== - - -==== Get the identity links of a historic process instance - - ----- -GET history/historic-process-instance/{processInstanceId}/identitylinks ----- - - -.Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates request was successful and the identity links are returned -|404|Indicates the process instance could not be found. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -[ - { - "type" : "participant", - "userId" : "kermit", - "groupId" : null, - "taskId" : null, - "taskUrl" : null, - "processInstanceId" : "5", - "processInstanceUrl" : "http://localhost:8182/history/historic-process-instances/5" - } -] ----- - - - -==== Get the binary data for a historic process instance variable - ----- -GET history/historic-process-instances/{processInstanceId}/variables/{variableName}/data ----- - - -.Get the binary data for a historic process instance variable - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the process instance was found and the requested variable data is returned. -|404|Indicates the requested process instance was not found or the process instance doesn't have a variable with the given name or the variable doesn't have a binary stream available. Status message provides additional information. - -|=============== - - -*Success response body:* - -The response body contains the binary value of the variable. When the variable is of type +binary+, the content-type of the response is set to +application/octet-stream+, regardless of the content of the variable or the request accept-type header. In case of +serializable+, +application/x-java-serialized-object+ is used as content-type. - - -==== Create a new comment on a historic process instance - ----- -POST history/historic-process-instances/{processInstanceId}/comments ----- - - -.Create a new comment on a historic process instance - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|processInstanceId|Yes|String|The id of the process instance to create the comment for. - -|=============== - - -*Request body:* - -[source,json,linenums] ----- -{ - "message" : "This is a comment.", - "saveProcessInstanceId" : true -} ----- - -Parameter +saveProcessInstanceId+ is optional, if +true+ save process instance id of task with comment. - -*Success response body:* - -[source,json,linenums] ----- -{ - "id" : "123", - "taskUrl" : "http://localhost:8081/flowable-rest/service/runtime/tasks/101/comments/123", - "processInstanceUrl" : "http://localhost:8081/flowable-rest/service/history/historic-process-instances/100/comments/123", - "message" : "This is a comment on the task.", - "author" : "kermit", - "time" : "2014-07-13T13:13:52.232+08:00", - "taskId" : "101", - "processInstanceId" : "100" -} ----- - - -.Create a new comment on a historic process instance - Response codes -[options="header"] -|=============== -|Response code|Description -|201|Indicates the comment was created and the result is returned. -|400|Indicates the comment is missing from the request. -|404|Indicates the requested historic process instance was not found. - -|=============== - - - -==== Get all comments on a historic process instance - - ----- -GET history/historic-process-instances/{processInstanceId}/comments ----- - - -.Get all comments on a process instance - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|processInstanceId|Yes|String|The id of the process instance to get the comments for. - -|=============== - -*Success response body:* - -[source,json,linenums] ----- -[ - { - "id" : "123", - "processInstanceUrl" : "http://localhost:8081/flowable-rest/service/history/historic-process-instances/100/comments/123", - "message" : "This is a comment on the task.", - "author" : "kermit", - "time" : "2014-07-13T13:13:52.232+08:00", - "processInstanceId" : "100" - }, - { - "id" : "456", - "processInstanceUrl" : "http://localhost:8081/flowable-rest/service/history/historic-process-instances/100/comments/456", - "message" : "This is another comment.", - "author" : "gonzo", - "time" : "2014-07-14T15:16:52.232+08:00", - "processInstanceId" : "100" - } -] ----- - - -.Get all comments on a process instance - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the process instance was found and the comments are returned. -|404|Indicates the requested task was not found. - -|=============== - - -==== Get a comment on a historic process instance - ----- -GET history/historic-process-instances/{processInstanceId}/comments/{commentId} ----- - - -.Get a comment on a historic process instance - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|processInstanceId|Yes|String|The id of the historic process instance to get the comment for. -|commentId|Yes|String|The id of the comment. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "id" : "123", - "processInstanceUrl" : "http://localhost:8081/flowable-rest/service/history/historic-process-instances/100/comments/456", - "message" : "This is another comment.", - "author" : "gonzo", - "time" : "2014-07-14T15:16:52.232+08:00", - "processInstanceId" : "100" -} ----- - - -.Get a comment on a historic process instance - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the historic process instance and comment were found and the comment is returned. -|404|Indicates the requested historic process instance was not found or the historic process instance doesn't have a comment with the given ID. - -|=============== - - - -==== Delete a comment on a historic process instance - ----- -DELETE history/historic-process-instances/{processInstanceId}/comments/{commentId} ----- - -.Delete a comment on a historic process instance - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|processInstanceId|Yes|String|The id of the historic process instance to delete the comment for. -|commentId|Yes|String|The id of the comment. - -|=============== - - -.Delete a comment on a historic process instance - Response codes -[options="header"] -|=============== -|Response code|Description -|204|Indicates the historic process instance and comment were found and the comment is deleted. Response body is left empty intentionally. -|404|Indicates the requested task was not found or the historic process instance doesn't have a comment with the given ID. - -|=============== - - -==== Get a single historic task instance - ----- -GET history/historic-task-instances/{taskId} ----- - -.Get a single historic task instance - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates that the historic task instances could be found. -|404|Indicates that the historic task instances could not be found. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "id" : "5", - "processDefinitionId" : "oneTaskProcess%3A1%3A4", - "processDefinitionUrl" : "http://localhost:8182/repository/process-definitions/oneTaskProcess%3A1%3A4", - "processInstanceId" : "3", - "processInstanceUrl" : "http://localhost:8182/history/historic-process-instances/3", - "executionId" : "4", - "name" : "My task name", - "description" : "My task description", - "deleteReason" : null, - "owner" : "kermit", - "assignee" : "fozzie", - "startTime" : "2013-04-17T10:17:43.902+0000", - "endTime" : "2013-04-18T14:06:32.715+0000", - "durationInMillis" : 86400056, - "workTimeInMillis" : 234890, - "claimTime" : "2013-04-18T11:01:54.715+0000", - "taskDefinitionKey" : "taskKey", - "formKey" : null, - "priority" : 50, - "dueDate" : "2013-04-20T12:11:13.134+0000", - "parentTaskId" : null, - "url" : "http://localhost:8182/history/historic-task-instances/5", - "variables": null, - "tenantId":null -} ----- - - -[[restHistoricTaskInstancesGet]] - - -==== Get historic task instances - ----- -GET history/historic-task-instances ----- - - -.Get historic task instances - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|No|String|An id of the historic task instance. -|processInstanceId|No|String|The process instance id of the historic task instance. -|processDefinitionKey|No|String|The process definition key of the historic task instance. -|processDefinitionKeyLike|No|String|The process definition key of the historic task instance, which matches the given value. -|processDefinitionId|No|String|The process definition id of the historic task instance. -|processDefinitionName|No|String|The process definition name of the historic task instance. -|processDefinitionNameLike|No|String|The process definition name of the historic task instance, which matches the given value. -|processBusinessKey|No|String|The process instance business key of the historic task instance. -|processBusinessKeyLike|No|String|The process instance business key of the historic task instance that matches the given value. -|executionId|No|String|The execution id of the historic task instance. -|taskDefinitionKey|No|String|The task definition key for tasks part of a process -|taskName|No|String|The task name of the historic task instance. -|taskNameLike|No|String|The task name with 'like' operator for the historic task instance. -|taskDescription|No|String|The task description of the historic task instance. -|taskDescriptionLike|No|String|The task description with 'like' operator for the historic task instance. -|taskDefinitionKey|No|String|The task identifier from the process definition for the historic task instance. -|taskCategory|No|String|Select tasks with the given category. Note that this is the task category, not the category of the process definition (namespace within the BPMN Xml). -|taskDeleteReason|No|String|The task delete reason of the historic task instance. -|taskDeleteReasonLike|No|String|The task delete reason with 'like' operator for the historic task instance. -|taskAssignee|No|String|The assignee of the historic task instance. -|taskAssigneeLike|No|String|The assignee with 'like' operator for the historic task instance. -|taskOwner|No|String|The owner of the historic task instance. -|taskOwnerLike|No|String|The owner with 'like' operator for the historic task instance. -|taskInvolvedUser|No|String|An involved user of the historic task instance. -|taskPriority|No|String|The priority of the historic task instance. -|finished|No|Boolean|Indication if the historic task instance is finished. -|processFinished|No|Boolean|Indication if the process instance of the historic task instance is finished. -|parentTaskId|No|String|An optional parent task id of the historic task instance. -|dueDate|No|Date|Return only historic task instances that have a due date equal this date. -|dueDateAfter|No|Date|Return only historic task instances that have a due date after this date. -|dueDateBefore|No|Date|Return only historic task instances that have a due date before this date. -|withoutDueDate|No|Boolean|Return only historic task instances that have no due-date. When +false+ is provided as value, this parameter is ignored. -|taskCompletedOn|No|Date|Return only historic task instances that have been completed on this date. -|taskCompletedAfter|No|Date|Return only historic task instances that have been completed after this date. -|taskCompletedBefore|No|Date|Return only historic task instances that have been completed before this date. -|taskCreatedOn|No|Date|Return only historic task instances that were created on this date. -|taskCreatedBefore|No|Date|Return only historic task instances that were created before this date. -|taskCreatedAfter|No|Date|Return only historic task instances that were created after this date. -|includeTaskLocalVariables|No|Boolean|An indication if the historic task instance local variables should be returned as well. -|includeProcessVariables|No|Boolean|An indication if the historic task instance global variables should be returned as well. -|tenantId|No|String|Only return historic task instances with the given tenantId. -|tenantIdLike|No|String|Only return historic task instances with a tenantId like the given value. -|withoutTenantId|No|Boolean|If +true+, only returns historic task instances without a tenantId set. If +false+, the +withoutTenantId+ parameter is ignored. -|The general <> can be used for this URL. - -|=============== - - -.Get historic task instances - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates that historic process instances could be queried. -|400|Indicates an parameter was passed in the wrong format. The status-message contains additional information. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "data": [ - { - "id" : "5", - "processDefinitionId" : "oneTaskProcess%3A1%3A4", - "processDefinitionUrl" : "http://localhost:8182/repository/process-definitions/oneTaskProcess%3A1%3A4", - "processInstanceId" : "3", - "processInstanceUrl" : "http://localhost:8182/history/historic-process-instances/3", - "executionId" : "4", - "name" : "My task name", - "description" : "My task description", - "deleteReason" : null, - "owner" : "kermit", - "assignee" : "fozzie", - "startTime" : "2013-04-17T10:17:43.902+0000", - "endTime" : "2013-04-18T14:06:32.715+0000", - "durationInMillis" : 86400056, - "workTimeInMillis" : 234890, - "claimTime" : "2013-04-18T11:01:54.715+0000", - "taskDefinitionKey" : "taskKey", - "formKey" : null, - "priority" : 50, - "dueDate" : "2013-04-20T12:11:13.134+0000", - "parentTaskId" : null, - "url" : "http://localhost:8182/history/historic-task-instances/5", - "taskVariables": [ - { - "name": "test", - "variableScope": "local", - "value": "myTest" - } - ], - "processVariables": [ - { - "name": "processTest", - "variableScope": "global", - "value": "myProcessTest" - } - ], - "tenantId":null - } - ], - "total": 1, - "start": 0, - "sort": "name", - "order": "asc", - "size": 1 -} ----- - - -==== Query for historic task instances - ----- -POST query/historic-task-instances ----- - - -*Query for historic task instances - Request body:* - -[source,json,linenums] ----- -{ - "processDefinitionId" : "oneTaskProcess%3A1%3A4", - ... - - "variables" : [ - { - "name" : "myVariable", - "value" : 1234, - "operation" : "equals", - "type" : "long" - } - ] -} ----- - - -All supported JSON parameter fields allowed are exactly the same as the parameters found for <>, but passed in as JSON-body arguments rather than URL-parameters to allow for more advanced querying and preventing errors with request-uri's that are too long. On top of that, the query allows for filtering based on process variables. The +taskVariables+ and +processVariables+ properties are JSON-arrays containing objects with the format <> - -.Query for historic task instances - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates request was successful and the tasks are returned -|400|Indicates an parameter was passed in the wrong format. The status-message contains additional information. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "data": [ - { - "id" : "5", - "processDefinitionId" : "oneTaskProcess%3A1%3A4", - "processDefinitionUrl" : "http://localhost:8182/repository/process-definitions/oneTaskProcess%3A1%3A4", - "processInstanceId" : "3", - "processInstanceUrl" : "http://localhost:8182/history/historic-process-instances/3", - "executionId" : "4", - "name" : "My task name", - "description" : "My task description", - "deleteReason" : null, - "owner" : "kermit", - "assignee" : "fozzie", - "startTime" : "2013-04-17T10:17:43.902+0000", - "endTime" : "2013-04-18T14:06:32.715+0000", - "durationInMillis" : 86400056, - "workTimeInMillis" : 234890, - "claimTime" : "2013-04-18T11:01:54.715+0000", - "taskDefinitionKey" : "taskKey", - "formKey" : null, - "priority" : 50, - "dueDate" : "2013-04-20T12:11:13.134+0000", - "parentTaskId" : null, - "url" : "http://localhost:8182/history/historic-task-instances/5", - "taskVariables": [ - { - "name": "test", - "variableScope": "local", - "value": "myTest" - } - ], - "processVariables": [ - { - "name": "processTest", - "variableScope": "global", - "value": "myProcessTest" - } - ], - "tenantId":null - } - ], - "total": 1, - "start": 0, - "sort": "name", - "order": "asc", - "size": 1 -} ----- - - -==== Delete a historic task instance - ----- -DELETE history/historic-task-instances/{taskId} ----- - -.Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates that the historic task instance was deleted. -|404|Indicates that the historic task instance could not be found. - -|=============== - - - -==== Get the identity links of a historic task instance - ----- -GET history/historic-task-instance/{taskId}/identitylinks ----- - -.Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates request was successful and the identity links are returned -|404|Indicates the task instance could not be found. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -[ - { - "type" : "assignee", - "userId" : "kermit", - "groupId" : null, - "taskId" : "6", - "taskUrl" : "http://localhost:8182/history/historic-task-instances/5", - "processInstanceId" : null, - "processInstanceUrl" : null - } -] ----- - - -==== Get the binary data for a historic task instance variable - ----- -GET history/historic-task-instances/{taskId}/variables/{variableName}/data ----- - -.Get the binary data for a historic task instance variable - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the task instance was found and the requested variable data is returned. -|404|Indicates the requested task instance was not found or the process instance doesn't have a variable with the given name or the variable doesn't have a binary stream available. Status message provides additional information. - -|=============== - - -*Success response body:* - -The response body contains the binary value of the variable. When the variable is of type +binary+, the content-type of the response is set to +application/octet-stream+, regardless of the content of the variable or the request accept-type header. In case of +serializable+, +application/x-java-serialized-object+ is used as content-type. - - -[[restHistoricActivityInstancesGet]] - - -==== Get historic activity instances - ----- -GET history/historic-activity-instances ----- - -.Get historic activity instances - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|activityId|No|String|An id of the activity instance. -|activityInstanceId|No|String|An id of the historic activity instance. -|activityName|No|String|The name of the historic activity instance. -|activityType|No|String|The element type of the historic activity instance. -|executionId|No|String|The execution id of the historic activity instance. -|finished|No|Boolean|Indication if the historic activity instance is finished. -|taskAssignee|No|String|The assignee of the historic activity instance. -|processInstanceId|No|String|The process instance id of the historic activity instance. -|processDefinitionId|No|String|The process definition id of the historic activity instance. -|tenantId|No|String|Only return instances with the given tenantId. -|tenantIdLike|No|String|Only return instances with a tenantId like the given value. -|withoutTenantId|No|Boolean|If +true+, only returns instances without a tenantId set. If +false+, the +withoutTenantId+ parameter is ignored. -|The general <> can be used for this URL. - -|=============== - - - -.Get historic activity instances - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates that historic activity instances could be queried. -|400|Indicates an parameter was passed in the wrong format. The status-message contains additional information. - -|=============== - - - -*Success response body:* - -[source,json,linenums] ----- -{ - "data": [ - { - "id" : "5", - "activityId" : "4", - "activityName" : "My user task", - "activityType" : "userTask", - "processDefinitionId" : "oneTaskProcess%3A1%3A4", - "processDefinitionUrl" : "http://localhost:8182/repository/process-definitions/oneTaskProcess%3A1%3A4", - "processInstanceId" : "3", - "processInstanceUrl" : "http://localhost:8182/history/historic-process-instances/3", - "executionId" : "4", - "taskId" : "4", - "calledProcessInstanceId" : null, - "assignee" : "fozzie", - "startTime" : "2013-04-17T10:17:43.902+0000", - "endTime" : "2013-04-18T14:06:32.715+0000", - "durationInMillis" : 86400056, - "tenantId":null - } - ], - "total": 1, - "start": 0, - "sort": "name", - "order": "asc", - "size": 1 -} ----- - - -==== Query for historic activity instances - ----- -POST query/historic-activity-instances ----- - - -*Request body:* - -[source,json,linenums] ----- -{ - "processDefinitionId" : "oneTaskProcess%3A1%3A4" -} ----- - - -All supported JSON parameter fields allowed are exactly the same as the parameters found for <>, but passed in as JSON-body arguments rather than URL-parameters to allow for more advanced querying and preventing errors with request-uri's that are too long. - - -.Query for historic activity instances - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates request was successful and the activities are returned -|400|Indicates an parameter was passed in the wrong format. The status-message contains additional information. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "data": [ - { - "id" : "5", - "activityId" : "4", - "activityName" : "My user task", - "activityType" : "userTask", - "processDefinitionId" : "oneTaskProcess%3A1%3A4", - "processDefinitionUrl" : "http://localhost:8182/repository/process-definitions/oneTaskProcess%3A1%3A4", - "processInstanceId" : "3", - "processInstanceUrl" : "http://localhost:8182/history/historic-process-instances/3", - "executionId" : "4", - "taskId" : "4", - "calledProcessInstanceId" : null, - "assignee" : "fozzie", - "startTime" : "2013-04-17T10:17:43.902+0000", - "endTime" : "2013-04-18T14:06:32.715+0000", - "durationInMillis" : 86400056, - "tenantId":null - } - ], - "total": 1, - "start": 0, - "sort": "name", - "order": "asc", - "size": 1 -} ----- - - -[[restHistoricVariableInstancesGet]] - - -==== List of historic variable instances - ----- -GET history/historic-variable-instances ----- - -.List of historic variable instances - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|processInstanceId|No|String|The process instance id of the historic variable instance. -|taskId|No|String|The task id of the historic variable instance. -|excludeTaskVariables|No|Boolean|Indication to exclude the task variables from the result. -|variableName|No|String|The variable name of the historic variable instance. -|variableNameLike|No|String|The variable name using the 'like' operator for the historic variable instance. -|The general <> can be used for this URL. - -|=============== - - -.List of historic variable instances - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates that historic variable instances could be queried. -|400|Indicates an parameter was passed in the wrong format. The status-message contains additional information. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "data": [ - { - "id" : "14", - "processInstanceId" : "5", - "processInstanceUrl" : "http://localhost:8182/history/historic-process-instances/5", - "taskId" : "6", - "variable" : { - "name" : "myVariable", - "variableScope", "global", - "value" : "test" - } - } - ], - "total": 1, - "start": 0, - "sort": "name", - "order": "asc", - "size": 1 -} ----- - - - -==== Query for historic variable instances - ----- -POST query/historic-variable-instances ----- - - -*Request body:* - -[source,json,linenums] ----- -{ - "processDefinitionId" : "oneTaskProcess%3A1%3A4", - ... - - "variables" : [ - { - "name" : "myVariable", - "value" : 1234, - "operation" : "equals", - "type" : "long" - } - ] -} ----- - - -All supported JSON parameter fields allowed are exactly the same as the parameters found for <>, but passed in as JSON-body arguments rather than URL-parameters to allow for more advanced querying and preventing errors with request-uri's that are too long. On top of that, the query allows for filtering based on process variables. The +variables+ property is a JSON-array containing objects with the format <> - -.Query for historic variable instances - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates request was successful and the tasks are returned -|400|Indicates an parameter was passed in the wrong format. The status-message contains additional information. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "data": [ - { - "id" : "14", - "processInstanceId" : "5", - "processInstanceUrl" : "http://localhost:8182/history/historic-process-instances/5", - "taskId" : "6", - "variable" : { - "name" : "myVariable", - "variableScope", "global", - "value" : "test" - } - } - ], - "total": 1, - "start": 0, - "sort": "name", - "order": "asc", - "size": 1 -} ----- - - -====Get the binary data for a historic task instance variable - - ----- -GET history/historic-variable-instances/{varInstanceId}/data ----- - -.Get the binary data for a historic task instance variable - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the variable instance was found and the requested variable data is returned. -|404|Indicates the requested variable instance was not found or the variable instance doesn't have a variable with the given name or the variable doesn't have a binary stream available. Status message provides additional information. - -|=============== - - -*Success response body:* - -The response body contains the binary value of the variable. When the variable is of type +binary+, the content-type of the response is set to +application/octet-stream+, regardless of the content of the variable or the request accept-type header. In case of +serializable+, +application/x-java-serialized-object+ is used as content-type. - - -[[restHistoricDetailGet]] - - -==== Get historic detail - ----- -GET history/historic-detail ----- - -.Get historic detail - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|id|No|String|The id of the historic detail. -|processInstanceId|No|String|The process instance id of the historic detail. -|executionId|No|String|The execution id of the historic detail. -|activityInstanceId|No|String|The activity instance id of the historic detail. -|taskId|No|String|The task id of the historic detail. -|selectOnlyFormProperties|No|Boolean|Indication to only return form properties in the result. -|selectOnlyVariableUpdates|No|Boolean|Indication to only return variable updates in the result. -|The general <> can be used for this URL. - -|=============== - - -.Get historic detail - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates that historic detail could be queried. -|400|Indicates an parameter was passed in the wrong format. The status-message contains additional information. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "data": [ - { - "id" : "26", - "processInstanceId" : "5", - "processInstanceUrl" : "http://localhost:8182/history/historic-process-instances/5", - "executionId" : "6", - "activityInstanceId", "10", - "taskId" : "6", - "taskUrl" : "http://localhost:8182/history/historic-task-instances/6", - "time" : "2013-04-17T10:17:43.902+0000", - "detailType" : "variableUpdate", - "revision" : 2, - "variable" : { - "name" : "myVariable", - "variableScope", "global", - "value" : "test" - }, - "propertyId": null, - "propertyValue": null - } - ], - "total": 1, - "start": 0, - "sort": "name", - "order": "asc", - "size": 1 -} ----- - - -==== Query for historic details - ----- -POST query/historic-detail ----- - -*Request body:* - ----- -{ - "processInstanceId" : "5", -} ----- - - -All supported JSON parameter fields allowed are exactly the same as the parameters found for <>, but passed in as JSON-body arguments rather than URL-parameters to allow for more advanced querying and preventing errors with request-uri's that are too long. - -.Query for historic details - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates request was successful and the historic details are returned -|400|Indicates an parameter was passed in the wrong format. The status-message contains additional information. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "data": [ - { - "id" : "26", - "processInstanceId" : "5", - "processInstanceUrl" : "http://localhost:8182/history/historic-process-instances/5", - "executionId" : "6", - "activityInstanceId", "10", - "taskId" : "6", - "taskUrl" : "http://localhost:8182/history/historic-task-instances/6", - "time" : "2013-04-17T10:17:43.902+0000", - "detailType" : "variableUpdate", - "revision" : 2, - "variable" : { - "name" : "myVariable", - "variableScope", "global", - "value" : "test" - }, - "propertyId" : null, - "propertyValue" : null - } - ], - "total": 1, - "start": 0, - "sort": "name", - "order": "asc", - "size": 1 -} ----- - - -==== Get the binary data for a historic detail variable - ----- -GET history/historic-detail/{detailId}/data ----- - - -.Get the binary data for a historic detail variable - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the historic detail instance was found and the requested variable data is returned. -|404|Indicates the requested historic detail instance was not found or the historic detail instance doesn't have a variable with the given name or the variable doesn't have a binary stream available. Status message provides additional information. - -|=============== - - -*Success response body:* - -The response body contains the binary value of the variable. When the variable is of type +binary+, the content-type of the response is set to +application/octet-stream+, regardless of the content of the variable or the request accept-type header. In case of +serializable+, +application/x-java-serialized-object+ is used as content-type. - -=== Forms - -==== Get form data - ----- -GET form/form-data ----- - -.Get form data - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|taskId|Yes (if no processDefinitionId)|String|The task id corresponding to the form data that needs to be retrieved. -|processDefinitionId|Yes (if no taskId)|String|The process definition id corresponding to the start event form data that needs to be retrieved. - -|=============== - - -.Get form data - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates that form data could be queried. -|404|Indicates that form data could not be found. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "data": [ - { - "formKey" : null, - "deploymentId" : "2", - "processDefinitionId" : "3", - "processDefinitionUrl" : "http://localhost:8182/repository/process-definition/3", - "taskId" : "6", - "taskUrl" : "http://localhost:8182/runtime/task/6", - "formProperties" : [ - { - "id" : "room", - "name" : "Room", - "type" : "string", - "value" : null, - "readable" : true, - "writable" : true, - "required" : true, - "datePattern" : null, - "enumValues" : [ - { - "id" : "normal", - "name" : "Normal bed" - }, - { - "id" : "kingsize", - "name" : "Kingsize bed" - }, - ] - } - ] - } - ], - "total": 1, - "start": 0, - "sort": "name", - "order": "asc", - "size": 1 -} ----- - - -==== Submit task form data - ----- -POST form/form-data ----- - -*Request body for task form:* - -[source,json,linenums] ----- -{ - "taskId" : "5", - "properties" : [ - { - "id" : "room", - "value" : "normal" - } - ] -} ----- - - -*Request body for start event form:* - -[source,json,linenums] ----- -{ - "processDefinitionId" : "5", - "businessKey" : "myKey", - "properties" : [ - { - "id" : "room", - "value" : "normal" - } - ] -} ----- - - -.Submit task form data - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates request was successful and the form data was submitted -|400|Indicates an parameter was passed in the wrong format. The status-message contains additional information. - -|=============== - - -*Success response body for start event form data (no response for task form data):* - -[source,json,linenums] ----- -{ - "id" : "5", - "url" : "http://localhost:8182/history/historic-process-instances/5", - "businessKey" : "myKey", - "suspended": false, - "processDefinitionId" : "3", - "processDefinitionUrl" : "http://localhost:8182/repository/process-definition/3", - "activityId" : "myTask" -} ----- - - -=== Database tables - -==== List of tables - ----- -GET management/tables ----- - -.List of tables - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the request was successful. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -[ - { - "name":"ACT_RU_VARIABLE", - "url":"http://localhost:8182/management/tables/ACT_RU_VARIABLE", - "count":4528 - }, - { - "name":"ACT_RU_EVENT_SUBSCR", - "url":"http://localhost:8182/management/tables/ACT_RU_EVENT_SUBSCR", - "count":3 - } - -] ----- - - -==== Get a single table - ----- -GET management/tables/{tableName} ----- - - -.Get a single table - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|tableName|Yes|String|The name of the table to get. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "name":"ACT_RE_PROCDEF", - "url":"http://localhost:8182/management/tables/ACT_RE_PROCDEF", - "count":60 -} ----- - - -.Get a single table - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the table exists and the table count is returned. -|404|Indicates the requested table does not exist. - -|=============== - - - - -==== Get column info for a single table - ----- -GET management/tables/{tableName}/columns ----- - -.Get column info for a single table - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|tableName|Yes|String|The name of the table to get. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- - -{ - "tableName":"ACT_RU_VARIABLE", - "columnNames":[ - "ID_", - "REV_", - "TYPE_", - "NAME_" - - - ], - "columnTypes":[ - "VARCHAR", - "INTEGER", - "VARCHAR", - "VARCHAR" - - - ] -} ----- - - -.Get column info for a single table - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the table exists and the table column info is returned. -|404|Indicates the requested table does not exist. - -|=============== - - - -==== Get row data for a single table - ----- -GET management/tables/{tableName}/data ----- - -.Get row data for a single table - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|tableName|Yes|String|The name of the table to get. - -|=============== - - -.Get row data for a single table - URL query parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|start|No|Integer|Index of the first row to fetch. Defaults to 0. -|size|No|Integer|Number of rows to fetch, starting from +start+. Defaults to 10. -|orderAscendingColumn|No|String|Name of the column to sort the resulting rows on, ascending. -|orderDescendingColumn|No|String|Name of the column to sort the resulting rows on, descending. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "total":3, - "start":0, - "sort":null, - "order":null, - "size":3, - - "data":[ - { - "TASK_ID_":"2", - "NAME_":"var1", - "REV_":1, - "TEXT_":"123", - "LONG_":123, - "ID_":"3", - "TYPE_":"integer" - } - - - - ] - -} ----- - -.Get row data for a single table - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the table exists and the table row data is returned. -|404|Indicates the requested table does not exist. - -|=============== - - -=== Engine - -==== Get engine properties - ----- -GET management/properties ----- - - -Returns a read-only view of the properties used internally in the engine. - -*Success response body:* - -[source,json,linenums] ----- -{ - "next.dbid":"101", - "schema.history":"create(5.15)", - "schema.version":"5.15" -} ----- - - -.Get engine properties - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the properties are returned. - -|=============== - - - -==== Get engine info - ----- -GET management/engine ----- - - -Returns a read-only view of the engine that is used in this REST-service. - - -*Success response body:* - -[source,json,linenums] ----- -{ - "name":"default", - "version":"5.15", - "resourceUrl":"file://flowable/flowable.cfg.xml", - "exception":null -} ----- - - -.Get engine info - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the engine info is returned. - -|=============== - - - -=== Runtime - -==== Signal event received - ----- -POST runtime/signals ----- - - -Notifies the engine that a signal event has been received, not explicitly related to a specific execution. - -*Body JSON:* - -[source,json,linenums] ----- -{ - "signalName": "My Signal", - "tenantId" : "execute", - "async": true, - "variables": [ - {"name": "testVar", "value": "This is a string"} - - ] -} ----- - - -.Signal event received - JSON Body parameters -[options="header"] -|=============== -|Parameter|Description|Required -|signalName|Name of the signal|Yes -|tenantId|ID of the tenant that the signal event should be processed in|No -|async|If +true+, handling of the signal will happen asynchronously. Return code will be +202 - Accepted+ to indicate the request is accepted but not yet executed. If +false+, - handling the signal will be done immediately and result (++200 - OK++) will only return after this completed successfully. Defaults to ++false++ if omitted.|No -|variables|Array of variables (in the general variables format) to use as payload to pass along with the signal. Cannot be used in case +async+ is set to +true+, this will result in an error.|No - -|=============== - - -*Success response body:* - -.Signal event received - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicated signal has been processed and no errors occurred. -|202|Indicated signal processing is queued as a job, ready to be executed. -|400|Signal not processed. The signal name is missing or variables are used together with async, which is not allowed. Response body contains additional information about the error. - -|=============== - - - -=== Jobs - -==== Get a single job - ----- -GET management/jobs/{jobId} ----- - -.Get a single job - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|jobId|Yes|String|The id of the job to get. - -|=============== - - - -*Success response body:* - -[source,json,linenums] ----- -{ - "id":"8", - "url":"http://localhost:8182/management/jobs/8", - "processInstanceId":"5", - "processInstanceUrl":"http://localhost:8182/runtime/process-instances/5", - "processDefinitionId":"timerProcess:1:4", - "processDefinitionUrl":"http://localhost:8182/repository/process-definitions/timerProcess%3A1%3A4", - "executionId":"7", - "executionUrl":"http://localhost:8182/runtime/executions/7", - "retries":3, - "exceptionMessage":null, - "dueDate":"2013-06-04T22:05:05.474+0000", - "tenantId":null -} ----- - -.Get a single job - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the job exists and is returned. -|404|Indicates the requested job does not exist. - -|=============== - - - -==== Delete a job - ----- -DELETE management/jobs/{jobId} ----- - - -.Delete a job - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|jobId|Yes|String|The id of the job to delete. - -|=============== - - -.Delete a job - Response codes -[options="header"] -|=============== -|Response code|Description -|204|Indicates the job was found and has been deleted. Response-body is intentionally empty. -|404|Indicates the requested job was not found. - -|=============== - - - -==== Execute a single job - ----- -POST management/jobs/{jobId} ----- - - -*Body JSON:* - -[source,json,linenums] ----- -{ - "action" : "execute" -} ----- - - -.Execute a single job - JSON Body parameters -[options="header"] -|=============== -|Parameter|Description|Required -|action|Action to perform. Only +execute+ is supported.|Yes - -|=============== - - -.Execute a single job - Response codes -[options="header"] -|=============== -|Response code|Description -|204|Indicates the job was executed. Response-body is intentionally empty. -|404|Indicates the requested job was not found. -|500|Indicates the an exception occurred while executing the job. The status-description contains additional detail about the error. The full error-stacktrace can be fetched later on if needed. - -|=============== - - - -==== Get the exception stacktrace for a job - ----- -GET management/jobs/{jobId}/exception-stacktrace ----- - - -.Get the exception stacktrace for a job - URL parameters -[options="header"] -|=============== -|Parameter|Description|Required -|jobId|Id of the job to get the stacktrace for.|Yes - -|=============== - - -.Get the exception stacktrace for a job - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the requested job was not found and the stacktrace has been returned. The response contains the raw stacktrace and always has a Content-type of +text/plain+. -|404|Indicates the requested job was not found or the job doesn't have an exception stacktrace. Status-description contains additional information about the error. - -|=============== - - - -==== Get a list of jobs - - ----- -GET management/jobs ----- - - -.Get a list of jobs - URL query parameters -[options="header"] -|=============== -|Parameter|Description|Type -|id|Only return job with the given id|String -|processInstanceId|Only return jobs part of a process with the given id|String -|executionId|Only return jobs part of an execution with the given id|String -|processDefinitionId|Only return jobs with the given process definition id|String -|withRetriesLeft|If +true+, only return jobs with retries left. If false, this parameter is ignored.|Boolean -|executable|If +true+, only return jobs which are executable. If false, this parameter is ignored.|Boolean -|timersOnly|If +true+, only return jobs which are timers. If false, this parameter is ignored. Cannot be used together with +$$'messagesOnly'$$+.|Boolean -|messagesOnly|If +true+, only return jobs which are messages. If false, this parameter is ignored. Cannot be used together with +$$'timersOnly'$$+|Boolean -|withException|If +true+, only return jobs for which an exception occurred while executing it. If false, this parameter is ignored.|Boolean -|dueBefore|Only return jobs which are due to be executed before the given date. Jobs without duedate are never returned using this parameter.|Date -|dueAfter|Only return jobs which are due to be executed after the given date. Jobs without duedate are never returned using this parameter.|Date -|exceptionMessage|Only return jobs with the given exception message|String -|tenantId|No|String|Only return jobs with the given tenantId. -|tenantIdLike|No|String|Only return jobs with a tenantId like the given value. -|withoutTenantId|No|Boolean|If +true+, only returns jobs without a tenantId set. If +false+, the +withoutTenantId+ parameter is ignored. -|sort|Field to sort results on, should be one of +id+, +dueDate+, +executionId+, +processInstanceId+, +retries+ or +tenantId+.|String -|The general <> can be used for this URL. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "data":[ - { - "id":"13", - "url":"http://localhost:8182/management/jobs/13", - "processInstanceId":"5", - "processInstanceUrl":"http://localhost:8182/runtime/process-instances/5", - "processDefinitionId":"timerProcess:1:4", - "processDefinitionUrl":"http://localhost:8182/repository/process-definitions/timerProcess%3A1%3A4", - "executionId":"12", - "executionUrl":"http://localhost:8182/runtime/executions/12", - "retries":0, - "exceptionMessage":"Can't find scripting engine for 'unexistinglanguage'", - "dueDate":"2013-06-07T10:00:24.653+0000", - "tenantId":null - } - - - - ], - "total":2, - "start":0, - "sort":"id", - "order":"asc", - "size":2 -} ----- - - -.Get a list of jobs - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the requested jobs were returned. -|400|Indicates an illegal value has been used in a url query parameter or the both +$$'messagesOnly'$$+ and +$$'timersOnly'$$+ are used as parameters. Status description contains additional details about the error. - -|=============== - - - -==== Get a single deadletter job - ----- -GET management/deadletter-jobs/{jobId} ----- - -.Get a single dead letter job - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|jobId|Yes|String|The id of the dead letter job to get. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "id":"8", - "url":"http://localhost:8182/management/jobs/8", - "processInstanceId":"5", - "processInstanceUrl":"http://localhost:8182/runtime/process-instances/5", - "processDefinitionId":"timerProcess:1:4", - "processDefinitionUrl":"http://localhost:8182/repository/process-definitions/timerProcess%3A1%3A4", - "executionId":"7", - "executionUrl":"http://localhost:8182/runtime/executions/7", - "retries":0, - "exceptionMessage":"Can't find scripting engine for 'unexistinglanguage'", - "dueDate":"2013-06-04T22:05:05.474+0000", - "tenantId":null -} ----- - -.Get a single dead letter job - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the dead letter job exists and is returned. -|404|Indicates the requested dead letter job does not exist. - -|=============== - - - -==== Delete a dead letter job - ----- -DELETE management/deadletter-jobs/{jobId} ----- - - -.Delete a dead letter job - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|jobId|Yes|String|The id of the dead letter job to delete. - -|=============== - - -.Delete a dead letter job - Response codes -[options="header"] -|=============== -|Response code|Description -|204|Indicates the dead letter job was found and has been deleted. Response-body is intentionally empty. -|404|Indicates the requested dead letter job was not found. - -|=============== - - - -==== Resume and execute a dead letter job - ----- -POST management/deadletter-jobs/{jobId} ----- - - -*Body JSON:* - -[source,json,linenums] ----- -{ - "action" : "move" -} ----- - - -.Resume and execute a dead letter job - JSON Body parameters -[options="header"] -|=============== -|Parameter|Description|Required -|action|Action to perform. Only +execute+ is supported.|Yes - -|=============== - - -.Resume and execute a dead letter job - Response codes -[options="header"] -|=============== -|Response code|Description -|204|Indicates the dead letter job was executed. Response-body is intentionally empty. -|404|Indicates the requested dead letter job was not found. -|500|Indicates the an exception occurred while executing the dead letter job. The status-description contains additional detail about the error. The full error-stacktrace can be fetched later on if needed. - -|=============== - - - -==== Get the exception stacktrace for a deadletter job - ----- -GET management/deadletter-jobs/{jobId}/exception-stacktrace ----- - - -.Get the exception stacktrace for a dead letter job - URL parameters -[options="header"] -|=============== -|Parameter|Description|Required -|jobId|Id of the dead letter job to get the stacktrace for.|Yes - -|=============== - - -.Get the exception stacktrace for a dead letter job - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the requested dead letter job was not found and the stacktrace has been returned. The response contains the raw stacktrace and always has a Content-type of +text/plain+. -|404|Indicates the requested dead letter job was not found or the job doesn't have an exception stacktrace. Status-description contains additional information about the error. - -|=============== - - - -==== Get a list of dead letterjobs - - ----- -GET management/deadletter-jobs ----- - - -.Get a list of dead letter jobs - URL query parameters -[options="header"] -|=============== -|Parameter|Description|Type -|id|Only return job with the given id|String -|processInstanceId|Only return jobs part of a process with the given id|String -|executionId|Only return jobs part of an execution with the given id|String -|processDefinitionId|Only return jobs with the given process definition id|String -|executable|If +true+, only return jobs which are executable. If +false+, this parameter is ignored.|Boolean -|timersOnly|If +true+, only return jobs which are timers. If +false+, this parameter is ignored. Cannot be used together with +$$'messagesOnly'$$+.|Boolean -|messagesOnly|If +true+, only return jobs which are messages. If +false+, this parameter is ignored. Cannot be used together with +$$'timersOnly'$$+|Boolean -|withException|If +true+, only return jobs for which an exception occurred while executing it. If +false+, this parameter is ignored.|Boolean -|dueBefore|Only return jobs which are due to be executed before the given date. Jobs without duedate are never returned using this parameter.|Date -|dueAfter|Only return jobs which are due to be executed after the given date. Jobs without duedate are never returned using this parameter.|Date -|withException|If +true+, for which an exception occurred while executing it. If +false+, this parameter is ignored.|Boolean -|tenantId|String|Only return jobs with exception. -|tenantIdLike|String|Only return jobs with a tenantId like the given value. -|withoutTenantId|Boolean|If +true+, only returns jobs without a tenantId set. If +false+, this parameter is ignored. -|locked|Boolean|If +true+, only returns jobs which are locked. If +false+, this parameter is ignored. -|unlocked|Boolean|If +true+, only returns jobs which are unlocked. If +false+, this parameter is ignored. -|sort|Field to sort results on, should be one of +id+, +dueDate+, +executionId+, +processInstanceId+, +retries+ or +tenantId+.|String -|The general <> can be used for this URL. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "data":[ - { - "id":"13", - "url":"http://localhost:8182/management/jobs/13", - "processInstanceId":"5", - "processInstanceUrl":"http://localhost:8182/runtime/process-instances/5", - "processDefinitionId":"timerProcess:1:4", - "processDefinitionUrl":"http://localhost:8182/repository/process-definitions/timerProcess%3A1%3A4", - "executionId":"12", - "executionUrl":"http://localhost:8182/runtime/executions/12", - "retries":0, - "withException":"Can't find scripting engine for 'unexistinglanguage'", - "dueDate":"2013-06-07T10:00:24.653+0000", - "createTime":"2013-06-06T08:08:24.007+0000" - "tenantId":null - } - ], - "total":2, - "start":0, - "sort":"id", - "order":"asc", - "size":2 -} ----- - - -.Get a list of dead letter jobs - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the requested jobs were returned. -|400|Indicates an illegal value has been used in a url query parameter or the both +$$'messagesOnly'$$+ and +$$'timersOnly'$$+ are used as parameters. Status description contains additional details about the error. - -|=============== - - - -=== Users - -==== Get a single user - ----- -GET identity/users/{userId} ----- - - -.Get a single user - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|userId|Yes|String|The id of the user to get. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "id":"testuser", - "firstName":"Fred", - "lastName":"McDonald", - "url":"http://localhost:8182/identity/users/testuser", - "email":"no-reply@flowable.org" -} ----- - - -.Get a single user - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the user exists and is returned. -|404|Indicates the requested user does not exist. - -|=============== - - - -==== Get a list of users - - ----- -GET identity/users ----- - -.Get a list of users - URL query parameters -[options="header"] -|=============== -|Parameter|Description|Type -|id|Only return user with the given id|String -|firstName|Only return users with the given firstname|String -|lastName|Only return users with the given lastname|String -|email|Only return users with the given email|String -|firstNameLike|Only return users with a firstname like the given value. Use +%+ as wildcard-character.|String -|lastNameLike|Only return users with a lastname like the given value. Use +%+ as wildcard-character.|String -|emailLike|Only return users with an email like the given value. Use +%+ as wildcard-character.|String -|memberOfGroup|Only return users which are a member of the given group.|String -|potentialStarter|Only return users which are potential starters for a process-definition with the given id.|String -|sort|Field to sort results on, should be one of +id+, +firstName+, +lastname+ or +email+.|String -|The general <> can be used for this URL. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "data":[ - { - "id":"anotherUser", - "firstName":"Tijs", - "lastName":"Barrez", - "url":"http://localhost:8182/identity/users/anotherUser", - "email":"no-reply@flowable.org" - }, - { - "id":"kermit", - "firstName":"Kermit", - "lastName":"the Frog", - "url":"http://localhost:8182/identity/users/kermit", - "email":null - }, - { - "id":"testuser", - "firstName":"Fred", - "lastName":"McDonald", - "url":"http://localhost:8182/identity/users/testuser", - "email":"no-reply@flowable.org" - } - ], - "total":3, - "start":0, - "sort":"id", - "order":"asc", - "size":3 -} ----- - - -.Get a list of users - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the requested users were returned. - -|=============== - - - -==== Update a user - ----- -PUT identity/users/{userId} ----- - -*Body JSON:* - -[source,json,linenums] ----- -{ - "firstName":"Tijs", - "lastName":"Barrez", - "email":"no-reply@flowable.org", - "password":"pass123" -} ----- - -All request values are optional. For example, you can only include the 'firstName' attribute in the request body JSON-object, only updating the firstName of the user, leaving all other fields unaffected. When an attribute is explicitly included and is set to null, the user-value will be updated to null. Example: +{"firstName" : null}+ will clear the firstName of the user). - - -.Update a user - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the user was updated. -|404|Indicates the requested user was not found. -|409|Indicates the requested user was updated simultaneously. - -|=============== - - -*Success response body:* see response for +identity/users/{userId}+. - - -==== Create a user - ----- -POST identity/users ----- - -*Body JSON:* - ----- -{ - "id":"tijs", - "firstName":"Tijs", - "lastName":"Barrez", - "email":"no-reply@flowable.org", - "password":"pass123" -} ----- - -.Create a user - Response codes -[options="header"] -|=============== -|Response code|Description -|201|Indicates the user was created. -|400|Indicates the id of the user was missing. - -|=============== - - -*Success response body:* see response for +identity/users/{userId}+. - -==== Delete a user - ----- -DELETE identity/users/{userId} ----- - -.Delete a user - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|userId|Yes|String|The id of the user to delete. - -|=============== - - - -.Delete a user - Response codes -[options="header"] -|=============== -|Response code|Description -|204|Indicates the user was found and has been deleted. Response-body is intentionally empty. -|404|Indicates the requested user was not found. - -|=============== - - -==== Get a user's picture - ----- -GET identity/users/{userId}/picture ----- - - -.Get a user's picture - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|userId|Yes|String|The id of the user to get the picture for. - -|=============== - - -*Response Body:* - -The response body contains the raw picture data, representing the user's picture. The Content-type of the response corresponds to the mimeType that was set when creating the picture. - -.Get a user's picture - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the user was found and has a picture, which is returned in the body. -|404|Indicates the requested user was not found or the user does not have a profile picture. Status-description contains additional information about the error. - -|=============== - - - -==== Updating a user's picture - ----- -GET identity/users/{userId}/picture ----- - -.Updating a user's picture - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|userId|Yes|String|The id of the user to get the picture for. - -|=============== - - -*Request body:* - -The request should be of type +multipart/form-data+. There should be a single file-part included with the binary value of the picture. On top of that, the following additional form-fields can be present: - -* ++mimeType++: Optional mime-type for the uploaded picture. If omitted, the default of +image/jpeg+ is used as a mime-type for the picture. - - -.Updating a user's picture - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the user was found and the picture has been updated. The response-body is left empty intentionally. -|404|Indicates the requested user was not found. - -|=============== - - - -==== List a user's info - ----- -PUT identity/users/{userId}/info ----- - - -.List a user's info - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|userId|Yes|String|The id of the user to get the info for. - -|=============== - - - -*Response Body:* - -[source,json,linenums] ----- -[ - { - "key":"key1", - "url":"http://localhost:8182/identity/users/testuser/info/key1" - }, - { - "key":"key2", - "url":"http://localhost:8182/identity/users/testuser/info/key2" - } -] ----- - - -.List a user's info - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the user was found and list of info (key and url) is returned. -|404|Indicates the requested user was not found. - -|=============== - - - - -==== Get a user's info - ----- -GET identity/users/{userId}/info/{key} ----- - - -.Get a user's info - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|userId|Yes|String|The id of the user to get the info for. -|key|Yes|String|The key of the user info to get. - -|=============== - - -*Response Body:* - -[source,json,linenums] ----- -{ - "key":"key1", - "value":"Value 1", - "url":"http://localhost:8182/identity/users/testuser/info/key1" -} ----- - - -.Get a user's info - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the user was found and the user has info for the given key.. -|404|Indicates the requested user was not found or the user doesn't have info for the given key. Status description contains additional information about the error. - -|=============== - - - -==== Update a user's info - ----- -PUT identity/users/{userId}/info/{key} ----- - -.Update a user's info - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|userId|Yes|String|The id of the user to update the info for. -|key|Yes|String|The key of the user info to update. - -|=============== - - -*Request Body:* - -[source,json,linenums] ----- -{ - "value":"The updated value" -} ----- - -*Response Body:* - -[source,json,linenums] ----- -{ - "key":"key1", - "value":"The updated value", - "url":"http://localhost:8182/identity/users/testuser/info/key1" -} ----- - -.Update a user's info - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the user was found and the info has been updated. -|400|Indicates the value was missing from the request body. -|404|Indicates the requested user was not found or the user doesn't have info for the given key. Status description contains additional information about the error. - -|=============== - - - -==== Create a new user's info entry - ----- -POST identity/users/{userId}/info ----- - - -.Create a new user's info entry - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|userId|Yes|String|The id of the user to create the info for. - -|=============== - - -*Request Body:* - -[source,json,linenums] ----- -{ - "key":"key1", - "value":"The value" -} ----- - - -*Response Body:* - -[source,json,linenums] ----- -{ - "key":"key1", - "value":"The value", - "url":"http://localhost:8182/identity/users/testuser/info/key1" -} ----- - - -.Create a new user's info entry - Response codes -[options="header"] -|=============== -|Response code|Description -|201|Indicates the user was found and the info has been created. -|400|Indicates the key or value was missing from the request body. Status description contains additional information about the error. -|404|Indicates the requested user was not found. -|409|Indicates there is already an info-entry with the given key for the user, update the resource instance (++PUT++). - -|=============== - - - -==== Delete a user's info - ----- -DELETE identity/users/{userId}/info/{key} ----- - - -.Delete a user's info - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|userId|Yes|String|The id of the user to delete the info for. -|key|Yes|String|The key of the user info to delete. - -|=============== - - - -.Delete a user's info - Response codes -[options="header"] -|=============== -|Response code|Description -|204|Indicates the user was found and the info for the given key has been deleted. Response body is left empty intentionally. -|404|Indicates the requested user was not found or the user doesn't have info for the given key. Status description contains additional information about the error. - -|=============== - - - -=== Groups - - - -==== Get a single group - - - ----- -GET identity/groups/{groupId} ----- - - -.Get a single group - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|groupId|Yes|String|The id of the group to get. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "id":"testgroup", - "url":"http://localhost:8182/identity/groups/testgroup", - "name":"Test group", - "type":"Test type" -} ----- - - -.Get a single group - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the group exists and is returned. -|404|Indicates the requested group does not exist. - -|=============== - - - -==== Get a list of groups - - ----- -GET identity/groups ----- - - -.Get a list of groups - URL query parameters -[options="header"] -|=============== -|Parameter|Description|Type -|id|Only return group with the given id|String -|name|Only return groups with the given name|String -|type|Only return groups with the given type|String -|nameLike|Only return groups with a name like the given value. Use +%+ as wildcard-character.|String -|member|Only return groups which have a member with the given username.|String -|potentialStarter|Only return groups which members are potential starters for a process-definition with the given id.|String -|sort|Field to sort results on, should be one of +id+, +name+ or +type+.|String -|The general <> can be used for this URL. - -|=============== - - -*Success response body:* - -[source,json,linenums] ----- -{ - "data":[ - { - "id":"testgroup", - "url":"http://localhost:8182/identity/groups/testgroup", - "name":"Test group", - "type":"Test type" - } - ], - "total":3, - "start":0, - "sort":"id", - "order":"asc", - "size":3 -} ----- - - -.Get a list of groups - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the requested groups were returned. - -|=============== - - - - -==== Update a group - ----- -PUT identity/groups/{groupId} ----- - -*Body JSON:* - -[source,json,linenums] ----- -{ - "name":"Test group", - "type":"Test type" -} ----- - - -All request values are optional. For example, you can only include the 'name' attribute in the request body JSON-object, only updating the name of the group, leaving all other fields unaffected. When an attribute is explicitly included and is set to null, the group-value will be updated to null. - - -.Update a group - Response codes -[options="header"] -|=============== -|Response code|Description -|200|Indicates the group was updated. -|404|Indicates the requested group was not found. -|409|Indicates the requested group was updated simultaneously. - -|=============== - - -*Success response body:* see response for +identity/groups/{groupId}+. - -==== Create a group - ----- -POST identity/groups ----- - -*Body JSON:* - -[source,json,linenums] ----- -{ - "id":"testgroup", - "name":"Test group", - "type":"Test type" -} ----- - - -.Create a group - Response codes -[options="header"] -|=============== -|Response code|Description -|201|Indicates the group was created. -|400|Indicates the id of the group was missing. - -|=============== - -*Success response body:* see response for +identity/groups/{groupId}+. - - -==== Delete a group - ----- -DELETE identity/groups/{groupId} ----- - - -.Delete a group - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|groupId|Yes|String|The id of the group to delete. - -|=============== - - -.Delete a group - Response codes -[options="header"] -|=============== -|Response code|Description -|204|Indicates the group was found and has been deleted. Response-body is intentionally empty. -|404|Indicates the requested group was not found. - -|=============== - - - -==== Get members in a group - -There is no GET allowed on +identity/groups/members+. Use the +identity/users?memberOfGroup=sales+ URL to get all users that are part of a particular group. - - - -==== Add a member to a group - - - ----- -POST identity/groups/{groupId}/members ----- - - -.Add a member to a group - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|groupId|Yes|String|The id of the group to add a member to. - -|=============== - - - -*Body JSON:* - -[source,json,linenums] ----- -{ - "userId":"kermit" -} ----- - - -.Add a member to a group - Response codes -[options="header"] -|=============== -|Response code|Description -|201|Indicates the group was found and the member has been added. -|404|Indicates the userId was not included in the request body. -|404|Indicates the requested group was not found. -|409|Indicates the requested user is already a member of the group. - -|=============== - - -*Response Body:* - -[source,json,linenums] ----- -{ - "userId":"kermit", - "groupId":"sales", - "url":"http://localhost:8182/identity/groups/sales/members/kermit" -} ----- - - -==== Delete a member from a group - - ----- -DELETE identity/groups/{groupId}/members/{userId} ----- - -.Delete a member from a group - URL parameters -[options="header"] -|=============== -|Parameter|Required|Value|Description -|groupId|Yes|String|The id of the group to remove a member from. -|userId|Yes|String|The id of the user to remove. - -|=============== - - - -.Delete a member from a group - Response codes -[options="header"] -|=============== -|Response code|Description -|204|Indicates the group was found and the member has been deleted. The response body is left empty intentionally. -|404|Indicates the requested group was not found or that the user is not a member of the group. The status description contains additional information about the error. - -|=============== - - -*Response Body:* - -[source,json,linenums] ----- -{ - "userId":"kermit", - "groupId":"sales", - "url":"http://localhost:8182/identity/groups/sales/members/kermit" -} ----- diff --git a/docs/userguide/src/zh_CN/bpmn/ch16-Cdi.adoc b/docs/userguide/src/zh_CN/bpmn/ch16-Cdi.adoc deleted file mode 100644 index a4331a4f27b..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch16-Cdi.adoc +++ /dev/null @@ -1,327 +0,0 @@ -[[cdiintegration]] - -== 集成CDI - -flowable-cdi模块结合了Flowable的可配置性及CDI(上下文和依赖注入, Contexts and Dependency Injection, J2EE)的可扩展性。flowable-cdi最突出的特点是: - -* 支持@BusinessProcessScoped bean(生命周期绑定至流程实例的CDI bean), -* 从流程中解析CDI bean(包括EJB)的自定义El解析器, -* 使用注解对流程实例进行声明式控制, -* Flowable关联至CDI事件总线, -* 可以与Java EE,Java SE,以及Spring一起工作, -* 支持单元测试。 - -[source,xml,linenums] ----- - - org.flowable - flowable-cdi - 6.x - ----- - -[[_setting_up_flowable_cdi]] -=== 安装flowable-cdi - -Flowable CDI可以安装在不同环境中。在这个章节我们主要介绍配置选项。 - -[[_looking_up_a_process_engine]] -==== 查找流程引擎 - -CDI扩展需要访问流程引擎,在运行时会查找++org.flowable.cdi.spi.ProcessEngineLookup++接口的实现。CDI模块提供了默认的名为++org.flowable.cdi.impl.LocalProcessEngineLookup++的实现,使用++ProcessEngines++-Utility类查找流程引擎,默认配置下用 +$$ProcessEngines#NAME_DEFAULT$$+ 查找流程引擎。如果需要使用自定义的名字,需要扩展这个类。请注意:需要将++flowable.cfg.xml++配置文件放在classpath中。 - -Flowable cdi使用java.util.ServiceLoader SPI解析++org.flowable.cdi.spi.ProcessEngineLookup++实例。为了提供接口的自定义实现,需要在部署中添加名为++META-INF/services/org.flowable.cdi.spi.ProcessEngineLookup++的纯文本文件,并在其中设置实现的全限定类名。 - -[NOTE] -==== -如果不提供自定义的++org.flowable.cdi.spi.ProcessEngineLookup++实现,则Flowable会使用默认的++LocalProcessEngineLookup++实现。在这种情况下,只需要在classpath中提供flowable.cfg.xml(参见下一章节)即可。 -==== - -[[_configuring_the_process_engine]] -==== 配置流程引擎 - -配置方式取决于所选用的流程引擎查找策略(上一章节)。这章介绍与LocalProcessEngineLookup一起使用的可用配置选项,并需要在classpath中提供一个Spring flowable.cfg.xml文件。 - -根据底层事务管理策略的不同,Flowable提供了不同的ProcessEngineConfiguration实现。flowable-cdi模块不关注事务,也就意味着可以使用任何事务管理策略(甚至是Spring抽象事务)。按照约定,CDI模块提供两个自定义的ProcessEngineConfiguration实现: - -* ++org.flowable.cdi.CdiJtaProcessEngineConfiguration++: Flowable JtaProcessEngineConfiguration的子类,可用于Flowable使用JTA管理事务的情况 - -* ++org.flowable.cdi.CdiStandaloneProcessEngineConfiguration++: StandaloneProcessEngineConfiguration的子类,可用于Flowable使用简单JDBC事务的情况。 - -下面是一个JBoss 7的flowable.cfg.xml文件示例: - -[source,xml,linenums] ----- - - - - - - - - - - - - - - - - - - - - - ----- - -这是Glassfish 3.1.1中的配置(假设已正确配置了名为jdbc/flowable的数据源): - - -[source,xml,linenums] ----- - - - - - - - - - - - - - - - - - - - ----- - -请注意上面的配置需要"spring-context"模块: - -[source,xml,linenums] ----- - - org.springframework - spring-context - 4.2.5.RELEASE - ----- - -Java SE环境中的配置与<>章节中的示例一样,只是用"CdiStandaloneProcessEngineConfiguration"代替"StandaloneProcessEngineConfiguration"。 - -[[_deploying_processes]] -==== 部署流程 - -可以使用标准的Flowable API(++RepositoryService++)部署流程。另外,flowable-cdi也提供了自动部署流程的功能,部署classpath中的++processes.xml++文件提供的流程列表。这是一个processes.xml文件的例子: - -[source,xml,linenums] ----- - - - - - - ----- - -[[_contextual_process_execution_with_cdi]] -=== 使用CDI的基于上下文的流程执行 - -本章节将介绍Flowable CDI扩展使用的基于上下文的流程执行模型(contextual process execution model)。BPMN业务流程通常是一个长期运行的交互动作,包含用户与系统的任务。在运行时,流程分割为独立工作单元的集合,由用户与/或应用逻辑操作。在flowable-cdi中,流程实例可以关联至一个CDI作用域,代表了一个工作单元。在工作单元很复杂的时候特别有用,比如用户任务由多个不同表单的复杂顺序组成,并需要在交互过程中保持"非流程作用域(non-process-scoped)"状态的场景。 - -[[_associating_a_conversation_with_a_process_instance]] -==== 将一个会话关联至一个流程实例 - -解析@BusinessProcessScoped bean或注入流程变量,都依赖活动的CDI作用域与流程实例的关联。flowable-cdi提供了++org.flowable.cdi.BusinessProcess++ bean用于控制该关联,并提供: - -* __startProcessBy(...)__方法,镜像了Flowable ++RuntimeService++服务暴露的对应方法,用于启动并关联一个业务流程, -* ++resumeProcessById(String processInstanceId)++,用于将给定id关联至流程实例, -* ++resumeTaskById(String taskId)++,用于将给定id关联至任务(以及扩展至相关的流程实例)。 - -当完成了一个工作单元(例如一个用户任务)时,可以调用++completeTask()++方法,解除流程实例与会话/请求的关联。这将通知Flowable完成当前任务,并继续运行流程实例。 - -请注意++BusinessProcess++ bean是一个++@Named++ bean,意味着可以使用表达式(比如在JSF页面中)调用它。下面的JSF2代码片段启动了一个新的会话,并将其关联至一个用户任务实例,其id作为请求参数传递(例如++pageName.jsf?taskId=XX++): - -[source,xml,linenums] ----- - - - - ----- - -[[_declaratively_controlling_the_process]] -==== 声明式控制流程 - -Flowable可以使用注解,声明式地启动流程实例以及完成任务。++@org.flowable.cdi.annotation.StartProcess++注解可以通过"key"或"name"启动一个流程实例。请注意流程实例在注解的方法返回__之后__启动。例如: - -[source,java,linenums] ----- -@StartProcess("authorizeBusinessTripRequest") -public String submitRequest(BusinessTripRequest request) { - // 进行一些操作 - return "success"; -} ----- - -按照Flowable的配置,被注解的方法代码以及流程实例的启动将处于同一个事务中。++@org.flowable.cdi.annotation.CompleteTask++的使用方式相同: - -[source,java,linenums] ----- -@CompleteTask(endConversation=false) -public String authorizeBusinessTrip() { - // 进行一些操作 - return "success"; -} ----- - -++@CompleteTask++注解可以结束当前会话。默认行为是在调用Flowable返回后结束回话。但可以像上面的例子一样,禁用结束会话。 - -[[_referencing_beans_from_the_process]] -==== 从流程中引用Bean - -flowable-cdi使用自定义解析器,将CDI bean暴露给Flowable El。因此可以像这样在流程中引用bean: - -[source,xml,linenums] ----- - ----- - -其中"authorizingManager"可以是生产者方法提供的bean: - -[source,java,linenums] ----- -@Inject @ProcessVariable Object businessTripRequesterUsername; - -@Produces -@Named -public Employee authorizingManager() { - TypedQuery query = entityManager.createQuery("SELECT e FROM Employee e WHERE e.account.username='" - + businessTripRequesterUsername + "'", Employee.class); - Employee employee = query.getSingleResult(); - return employee.getManager(); -} - ----- - -可以使用++flowable:expression="myEjb.method()"++扩展,在服务任务中调用一个EJB中的业务方法。请注意这需要在++MyEjb++类上使用++@Named++注解。 - -[[_working_with_businessprocessscoped_beans]] -==== 使用@BusinessProcessScoped bean - -可以使用flowable-cdi将一个bean的生命周期绑定在一个流程实例上。为此提供名为BusinessProcessContext的自定义的上下文实现。BusinessProcessScoped bean实例将作为流程变量存储在当前流程实例中。BusinessProcessScoped bean需要是可持久化(PassivationCapable,例如Serializable)的。下面是一个流程作用域bean的例子: - -[source,java,linenums] ----- -@Named -@BusinessProcessScoped -public class BusinessTripRequest implements Serializable { - private static final long serialVersionUID = 1L; - private String startDate; - private String endDate; - // ... -} ----- - -有时也需要在没有关联至流程实例的情况下(例如在流程启动前)使用流程作用域bean。如果当前没有激活的流程实例,则BusinessProcessScoped bean的实例将临时存储在本地作用域(也就是会话或请求中,取决于上下文)。如果该作用域之后关联至一个业务流程实例,则会将bean实例刷入该流程实例。 - -[[_injecting_process_variables]] -==== 注入流程变量 - -flowable-cdi支持以下方式注入流程变量 - -* 使用++@Inject [additional qualifiers] Type fieldName++类型安全地注入++@BusinessProcessScoped++ bean -* 使用++@ProcessVariable(name?)++限定名不安全地注入其它流程变量: - -[source,java,linenums] ----- -@Inject @ProcessVariable Object accountNumber; -@Inject @ProcessVariable("accountNumber") Object account ----- - -要在EL中引用流程变量,有类似的选择: - -* 可以直接引用++@Named @BusinessProcessScoped++ bean, -* 可以通过++ProcessVariables++ bean引用其它流程变量: - ----- -#{processVariables['accountNumber']} ----- - -[[_receiving_process_events]] -==== 接收流程事件 - -Flowable可以关联至CDI事件总线。这样就可以使用标准CDI事件机制获取流程事件。要为Flowable启用CDI事件支持,需要在配置中启用相应的处理监听器: - -[source,xml,linenums] ----- - - - - - ----- - -这样Flowable就被配置为使用CDI事件总线发布事件。下面介绍如何在CDI bean中接收流程事件。事件通知是类型安全的。流程事件的类型是++org.flowable.cdi.BusinessProcessEvent++。 -下面是一个简单的事件观察者方法的例子: - -[source,java,linenums] ----- -public void onProcessEvent(@Observes BusinessProcessEvent businessProcessEvent) { - // 处理事件 -} ----- - -所有事件都会通知观察者。如果需要限制观察者接收的事件,可以添加限定注解: - -* ++@BusinessProcess++: 限制事件为特定的流程定义。例如:++@Observes @BusinessProcess("billingProcess") BusinessProcessEvent evt++ -* ++@StartActivity++: 使用特定的活动限制事件。例如:++@Observes @StartActivity("shipGoods") BusinessProcessEvent evt++将在进入id为"shipGoods"的活动时调用。 -* ++@EndActivity++: 使用特定的活动限制事件。例如:++@Observes @EndActivity("shipGoods") BusinessProcessEvent evt++将在离开id为"shipGoods"的活动时调用。 -* ++@TakeTransition++: 使用特定的路径限制事件。 -* ++@CreateTask++: 使用特定任务的创建限制事件。 -* ++@DeleteTask++: 使用特定任务的删除限制事件。 -* ++@AssignTask++: 使用特定任务的指派限制事件。 -* ++@CompleteTask++: 使用特定任务的完成限制事件。 - -上面的限定名可以自由组合。例如,要接收离开"shipmentProcess"中的"shipGoods"活动时生成的所有事件,可以撰写下面的观察者方法: - -[source,java,linenums] ----- -public void beforeShippingGoods(@Observes @BusinessProcess("shippingProcess") @EndActivity("shipGoods") BusinessProcessEvent evt) { - // 处理事件 -} ----- - -在默认配置下,事件监听器将在上下文相同的事务中同步调用。CDI事务性观察者(CDI transactional observer,只能与JavaEE/EJB一起使用)可以在将事件交给观察者方法时进行控制。使用事务性观察者,可以保证比如只在触发事件的事务成功时才通知观察者: - -[source,java,linenums] ----- -public void onShipmentSuceeded(@Observes(during=TransactionPhase.AFTER_SUCCESS) @BusinessProcess("shippingProcess") @EndActivity("shipGoods") BusinessProcessEvent evt) { - // 给客户发送邮件。 -} ----- - -[[_additional_features]] -==== 其他功能 - -* 可以注入流程引擎与服务:++@Inject ProcessEngine, RepositoryService, TaskService++, ... -* 可以注入当前的流程实例与任务:++@Inject ProcessInstance, Task++, -* 可以注入当前的businessKey:++@Inject @BusinessKey String businessKey++, -* 可以注入当前的流程实例id:+@Inject @ProcessInstanceId String pid++ - -[[_known_limitations]] -=== 已知限制 - -尽管flowable-cdi遵循SPI,并设计为“可插拔扩展”,但只在Weld下进行了测试。 diff --git a/docs/userguide/src/zh_CN/bpmn/ch16-Ldap.adoc b/docs/userguide/src/zh_CN/bpmn/ch16-Ldap.adoc deleted file mode 100755 index 831ed1fbe9a..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch16-Ldap.adoc +++ /dev/null @@ -1,154 +0,0 @@ -[[chapter_ldap]] - -== 集成LDAP - -很多公司使用LDAP(Lightweight Directory Access Protocol,轻量级目录访问协议)系统管理用户与组。Flowable提供了一个开箱即用的解决方案,简单配置即可将Flowable与LDAP系统连接起来。 - -早期版本就可以集成LDAP。之后大幅简化了配置,但“老”的LDAP配置方式仍然可用。实际上,简化配置只是对“老”框架进行的包装。 - -[[ldap_usage]] - -=== 使用 - -在pom.xml中添加下列依赖,为项目中添加LDAP集成代码: - -[source,xml,linenums] ----- - - org.flowable - flowable-ldap-configurator - latest.version - ----- - - -[[ldap_usecases]] - - -=== 用途 - -目前LDAP集成有两大作用: - -* 通过IdentityService进行认证。用于由IdentityService处理所有认证业务的场景。 -* 获取一个组中的用户。比如,用于查询某用户作为候选组的任务。 - -[[ldap_configuration]] - -=== 配置 - - -在流程引擎配置的++idmProcessEngineConfigurator++小节添加++org.flowable.ldap.LDAPConfigurator++的实现,进行Flowable与LDAP系统的集成配置。这是个高度可扩展的类:如果默认实现不能满足使用场景,可以轻松地覆盖方法,许多依赖的bean也是可插拔的。 - -这是一个示例配置(在代码方式创建引擎时完全类似)。目前不需要太关注这些参数,我们会在下一章节详细介绍。 - -[source,xml,linenums] ----- - - ... - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ----- - -[[ldap_properties]] - - -=== 参数 - -++org.flowable.ldap.LDAPConfiguration++使用下列参数: - - -.LDAP配置参数 -[options="header"] -|=============== -|参数名|描述|类型|默认值 -|server|LDAP系统的服务器。例如__ldap://localhost:33389__|String| -|port|LDAP系统的端口|int| -|user|LDAP系统的用户id|String| -|password|LDAP系统的密码|String| -|initialContextFactory|连接LDAP所用的InitialContextFactory|String|com.sun.jndi.ldap.LdapCtxFactory -|securityAuthentication|连接LDAP系统所用的__java.naming.security.authentication__|String|simple -|customConnectionParameters|用于设置没有配置setter的LDAP连接参数。例如 http://docs.oracle.com/javase/tutorial/jndi/ldap/jndi.html 中的自定义参数,用于配置连接池、安全等。连接LDAP系统时会使用这些参数。|Map| -|baseDn|查询用户及组的基础__标识名__(__distinguished name, DN__)|String| -|userBaseDn|查询用户的基础__标识名__。不设置则使用baseDn(见上)|String| -|groupBaseDn|查询组的基础__标识名__。不设置则使用baseDn(见上)|String| -|searchTimeLimit|查询LDAP的超时时间,以毫秒计|long|一小时 -|queryUserByUserId|通过ID查询用户所用的语句。 - 比如:`(&(objectClass=inetOrgPerson)(uid={0}))` - 返回LDAP中所有__inetOrgPerson__类、__uid__属性值匹配的对象。 - 上例中,使用{@link java.text.MessageFormat}即__{0}__注入用户ID。 - 如果不能通过简单的语句进行查询,可以改用 `org.flowable.ldap.LDAPQueryBuilder` ,进行定制化查询。|string| -|queryUserByFullNameLike|通过全名查询用户所用的语句。 - 比如:`(&(objectClass=inetOrgPerson)(\|({0}=**{1}**)({2}={3})))` - 返回LDAP中所有__inetOrgPerson__类、姓或名匹配的对象。 - 注入到表达式中的值:{0} : 名字属性名 {1} : 查询文本 {2} : 姓属性名 {3} : 查询文本 - 如果不能通过简单的语句进行查询,可以改用 `org.flowable.ldap.LDAPQueryBuilder`,进行定制化查询。|string| -|queryAllUsers|不使用过滤条件,查询所有用户所用的语句。 - 比如:`(objectClass=inetOrgPerson)` - 返回LDAP中所有__groupOfUniqueNames__类的对象。|string| -|queryGroupsForUser|查询给定用户所在组所用的语句。 - 比如:`(&(objectClass=groupOfUniqueNames)(uniqueMember={0}))` - 返回LDAP中所有__groupOfUniqueNames__类、DN为__uniqueMember__的对象。 - 上例中,使用{@link java.text.MessageFormat}即__{0}__注入用户ID。 - 如果不能通过简单的语句进行查询,可以改用 `org.flowable.ldap.LDAPQueryBuilder` ,进行定制化查询。|string| -|queryAllGroups|查询所有组所用的语句。 - 比如:`(objectClass=groupOfUniqueNames)` - 返回LDAP中所有__groupOfUniqueNames__的对象。|string| -|userIdAttribute|代表用户ID的LDAP属性名。用于查询并将LDAP用户对象映射至Flowable用户对象。|string| -|userFirstNameAttribute|代表用户名字的LDAP属性名。用于查询并将LDAP用户对象映射至Flowable用户对象。|string| -|userLastNameAttribute|代表用户姓的LDAP属性名。用于查询并将LDAP用户对象映射至Flowable用户对象。|string| -|groupIdAttribute|代表用户组ID的LDAP属性名。用于查询并将LDAP用户组对象映射至Flowable用户组对象。|string| -|groupNameAttribute|代表用户组名称的LDAP属性名。用于查询并将LDAP用户组对象映射至Flowable用户组对象。|String| -|groupTypeAttribute|代表用户组类型的LDAP属性名。用于查询并将LDAP用户组对象映射至Flowable用户组对象|String| - -|=============== - -下面的参数用于修改默认行为及缓存组: - -.高级参数 -[options="header"] -|=============== -|参数名|描述|类型|默认值 -|ldapUserManagerFactory|如果默认实现不符合要求,可以设置一个自定义的LDAPUserManagerFactory实现。|LDAPUserManagerFactory的实例| -|ldapGroupManagerFactory|如果默认实现不符合要求,可以设置一个自定义的LDAPGroupManagerFactory实现。|LDAPGroupManagerFactory的实例| -|ldapMemberShipManagerFactory|如果默认实现不符合要求,可以设置一个自定义的LDAPMembershipManagerFactory实现。请注意很少出现这种情况,一般都使用LDAP系统管理成员信息。|LDAPMembershipManagerFactory的实例| -|ldapQueryBuilder|如果默认实现不符合要求,可以设置一个自定义的查询构建器。使用LDAPUserManager或LDAPGroupManage进行LDAP查询时,会使用LDAPQueryBuilder的实例。默认会使用在本实例中设置的参数,例如queryGroupsForUser与queryUserById|org.flowable.ldap.LDAPQueryBuilder的实例| -|groupCacheSize|设置用户组缓存的尺寸。 -这是用户所在组的LRU缓存。避免每次需要查询用户所在组时都访问LDAP系统。 -若值小于0,则不会启用缓存。默认值为-1,所以不会进行缓存。|int|-1 -|groupCacheExpirationTime|设置用户组缓存的过期时间,以毫秒计。如果设置了用户组缓存,在查询了用户所在组后,会缓存用户组关系,持续本参数设置的时间。也就是说,如果在00:00进行了用户所在组查询,过期时间为30分钟,则在00:00 - 00:30间会使用该惠存,00:30之后进行的查询不会使用该缓存,而是会重新查询LDAP系统。|long|一个小时 - -|=============== - -使用活动目录(Active Directory)时请注意:用户报告在使用活动目录时,需要将__InitialDirContext__设置为Context.REFERRAL。可以通过customConnectionParameters map设置这个参数。 diff --git a/docs/userguide/src/zh_CN/bpmn/ch17-Advanced.adoc b/docs/userguide/src/zh_CN/bpmn/ch17-Advanced.adoc deleted file mode 100755 index baf2d7535eb..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch17-Advanced.adoc +++ /dev/null @@ -1,866 +0,0 @@ -[[_advanced]] -== 高级 - -本章介绍的Flowable的高级使用技巧,超出了一般的执行BPMN 2.0流程的范畴。因此,要理解这里讨论的主题,需要对Flowable足够熟练与精通。 - -[[_async_executor]] -=== 异步执行器 - -Flowable V5版本中,在之前的作业执行器(job executor)之外,还提供了异步执行器(async executor)。异步执行器已被许多Flowable的用户及我们自己的跑分证明,性能比老的作业执行器好。 - -从Flowable V6起,将只提供异步执行器。在V6中,对异步执行器进行了完全的重构,以提升性能及易用性。当然仍然与已有的API兼容。 - -[[async_executor_design]] - -==== 异步执行器的设计 - -Flowable有两种作业类型:定时器(例如边界事件或用户任务中的定时器)以及异步操作(带有__flowable:async="true"__属性的服务任务)。 - -**定时器**很容易理解:保存在ACT_RU_TIMER_JOB表中,并带有给定的到期日期。异步执行器中有一个线程,周期性地检查是否有需要触发的定时器(也就是说,到期日期在当前时间“之前”)。当需要触发定时器时,从JOB表中移除该定时器,并创建一个异步作业(async job)。 - -**异步作业**在执行流程实例(即调用API)时插入数据库。如果当前Flowable引擎启用了异步执行器,则该异步作业将被__锁定(locked)__。即在ACT_RU_JOB表中插入一个作业条目,并设置其__lock owner(锁持有人)__与__lock expiration time(锁到期时间)__。在API调用成功后触发的事务监听器(transaction commit listener),将会触发同一引擎中的异步执行器,让其执行该作业(因此可以保证数据库中已经保存了数据)。为此,异步执行器使用(可配置的)线程池,从其中取出线程用于执行作业,并使流程可以异步进行。如果Flowable引擎未启用异步执行器,则异步作业仍会插入ACT_RU_JOB表,但不会被锁定。 - -与检查定时器的线程类似,异步执行器中也有一个用于“获取”新的异步作业的线程。这里的异步作业,指的是表中存储但未被锁定的作业。这个线程会将这些作业锁定给当前Flowable引擎,并发送至异步执行器。 - -用于执行作业的线程池从一个内存队列中获取作业。当队列满了时(可配置),作业将会被解锁,并重新存回数据库。这样,其他的异步执行器就可以重新操作它们。 - -如果在执行作业期间发生了异常,这个异步作业将会转化为一个定时器作业,并带有一个到期日期。之后,它将会像普通定时器作业一样被获取,并重新变回异步作业,以实现重试。当一个作业已经重试了(可配置)几次,仍然失败,则作业被视为“死亡(dead)”,并被移至ACT_RU_DEADLETTER_JOB表。“死信(deadletter)”的概念在各种其他系统中也广泛使用。管理员需要检查失败作业的异常信息,并进行相应操作。 - -流程定义与流程实例都可以被暂停。这些定义或实例所关联的暂停作业,将被移至ACT_RU_SUSPENDED_JOB表,以确保用于获取作业的查询语句中的where条件尽量少。 - -综上所述:对于熟悉作业/异步执行器的旧实现的人来说,主要目标是让查询尽可能简单。在过去(V6以前),所有作业类型/状态使用一张表。为了满足所有使用场景,导致“where”条件十分庞大。现在已经解决了这个问题,我们的跑分也证明这个新设计带来了更好的性能,也更有弹性。 - -[[_async_executor_configuration]] -==== 配置异步执行器 - -异步执行器是一个高度可配置的组件。建议先查看异步执行器的默认配置,检查它们是否符合你的流程的要求。 - -另外,也可以扩展默认的实现,或者替换为你自己实现的__org.flowable.engine.impl.asyncexecutor.AsyncExecutor__接口。 - -可以在流程引擎配置中使用setter设置下列参数: - -.异步执行器配置选项 -[options="header"] -|=============== -|名称|默认值|描述 - -|asyncExecutorThreadPoolQueueSize|100|在获取待执行的作业之后,线程池中某个线程实际执行作业之前,放置这些作业的队列的长度。 -|asyncExecutorCorePoolSize|8|用于执行作业的线程池中,最小的活动(kept alive)线程数量。 -|asyncExecutorMaxPoolSize|8|用于执行作业的线程池中,创建线程的最大数量。 -|asyncExecutorThreadKeepAliveTime|5000|在销毁执行作业所用的线程前,需要保持活动的时间(以毫秒计)。设置为>0的值会消耗资源,但在有大量执行作业的时候,可以避免总是创建新线程。如果设置为0,则线程会在执行完作业后立刻被销毁。 -|asyncExecutorNumberOfRetries|3|作业被移入“死信”表之前的最大重试次数。 -|asyncExecutorMaxTimerJobsPerAcquisition|1|在一次获取定时器作业的查询中,获取作业的数量。默认值为1,因为这样可以降低潜在的乐观锁异常情况。较大的数值性能较好,但在不同的引擎间发生乐观锁异常的几率也会变大。 -|asyncExecutorMaxAsyncJobsDuePerAcquisition|1|在一次获取异步作业的查询中,获取作业的数量。默认值为1,因为这样可以降低潜在的乐观锁异常情况。较大的数值性能较好,但在不同的引擎间发生乐观锁异常的几率也会变大。 -|asyncExecutorDefaultTimerJobAcquireWaitTime|10000|获取定时器作业的线程在两次获取作业的查询之间等待的时间(以毫秒记)。只在上一次查询未找到新的定时器作业,或者获取的作业数量少于__asyncExecutorMaxTimerJobsPerAcquisition__中设置的值时才会等待。 -|asyncExecutorDefaultAsyncJobAcquireWaitTime|10000|获取异步作业的线程在两次获取作业的查询之间等待的时间(以毫秒记)。只在上一次查询未找到新的异步作业,或者获取的作业数量少于__asyncExecutorMaxAsyncJobsDuePerAcquisition__中设置的值时才会等待。 -|asyncExecutorDefaultQueueSizeFullWaitTime|0| -在内部作业队列已满之后,执行下一次查询之前,获取作业(包括定时器作业及异步作业)的线程将等待的时间(以毫秒记)。默认值为0(为保证向后兼容性)。设置为较大的值,可以让异步执行器有机会多执行掉一些队列作业,腾出队列空间。 -|asyncExecutorTimerLockTimeInMillis|5分钟|异步执行器获取定时器作业之后锁定的时间(以毫秒记)。在这段时间内,其它异步执行器不会尝试获取或锁定这个作业。 -|asyncExecutorAsyncJobLockTimeInMillis|5分钟|异步执行器获取异步作业之后锁定的时间(以毫秒记)。在这段时间内,其它异步执行器不会尝试获取或锁定这个作业。 -|asyncExecutorSecondsToWaitOnShutdown|60|当请求关闭执行器(或流程引擎)后,等待执行作业的线程池安全关闭的时间(以秒记)。 -|asyncExecutorResetExpiredJobsInterval|60秒|在两次__超时作业(expired job)__检查之间等待的时间(以毫秒记)。超时作业指的是已经锁定(某个执行器已经为其写入了锁持有人以及超时时间),但一直没有完成的作业。在检查中,会解锁超时作业,即移除其锁持有人以及超时时间。这样其他执行器就可以重新获取它。作业的锁超时时间在当前时间之前则视作超时。 -|asyncExecutorResetExpiredJobsPageSize|3|异步执行器的__超时重置(reset expired)__检查线程一次获取的作业数量。 -|=============== - -[[_message_queue_based_async_executor]] -==== 基于消息队列的异步执行器 - -阅读<>章节之后,很明显架构的灵感来自消息队列。异步执行器设计思路保证了可以很轻松地用消息队列代替线程池的工作,处理异步作业。 - -跑分显示,相比基于线程池的异步执行器,消息队列性能出众,吞吐量大。但需要额外的中间件,当然也就增加了安装配置、维护及监控的复杂度。对于多数用户来说,基于线程池的异步执行器性能已经足够用了。但能够知道在性能要求增长之后,仍有改进方案,也是挺好的。 - -目前,唯一直接可用的是带有JMS的Spring。选择首先支持Spring的原因是,Spring提供了非常好的功能,解决了使用线程以及处理多个消息消费者造成的麻烦。但是其实集成也很简单,因此可以轻松改用任何其他消息队列实现或协议(Stomp、AMPQ等等)。我们欢迎用户反馈下一个应该支持什么消息队列。 - -使用消息队列后,当引擎创建新的异步作业时,会在消息队列中放入一条包含有作业标识的消息(处在一个事务提交监听器中,这样就可以确保该作业条目已经提交至数据库)。之后消息消费者可以获取作业标识,并获取及执行该作业。异步执行器不再创建线程池,而是会在另一个单独线程中插入及查询定时器。当定时器到时触发时,将会被移至异步作业表,同时向消息队列发送一条消息。消息队列也可能失败,所以__超时重置__线程会按照原逻辑处理。只不过不是__解锁__作业,而是重发消息。异步执行器不再轮询异步作业。 - -主要由两个类实现: - -* __org.flowable.engine.impl.asyncexecutor.JobManager__接口的实现,将消息发送至消息队列而不是线程池。 - -* __jakarta.jms.MessageListener__接口的实现。从消息队列中消费消息,并使用消息中的作业标识获取及执行该作业。 - -首先添加__flowable-jms-spring-executor__依赖: - -[source,xml,linenums] ----- - - org.flowable - flowable-jms-spring-executor - ${flowable.version} - ----- - -在流程引擎配置中进行如下设置启用基于消息队列的异步执行器: - -* __asyncExecutorActivate__为__true__ -* __asyncExecutorMessageQueueMode__为__true__ -* __org.flowable.spring.executor.jms.MessageBasedJobManager__注入为__JobManager__ - -下面是一个基于Java配置的完整例子,使用__ActiveMQ__作为消息中间件。 - -请注意: - -* 需要为__MessageBasedJobManager__注入一个配置了正确的__connectionFactory__的__JMSTemplate__。 -* 我们使用Spring的__MessageListenerContainer__,因为它大幅简化了线程与多消费者的使用。 - -[source,java,linenums] ----- -@Configuration -public class SpringJmsConfig { - - @Bean - public DataSource dataSource() { - // 略 - } - - @Bean(name = "transactionManager") - public PlatformTransactionManager transactionManager(DataSource dataSource) { - DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(); - transactionManager.setDataSource(dataSource); - return transactionManager; - } - - @Bean - public SpringProcessEngineConfiguration processEngineConfiguration(DataSource dataSource, PlatformTransactionManager transactionManager, - JobManager jobManager) { - SpringProcessEngineConfiguration configuration = new SpringProcessEngineConfiguration(); - configuration.setDataSource(dataSource); - configuration.setTransactionManager(transactionManager); - configuration.setDatabaseSchemaUpdate(SpringProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE); - configuration.setAsyncExecutorMessageQueueMode(true); - configuration.setAsyncExecutorActivate(true); - configuration.setJobManager(jobManager); - return configuration; - } - - @Bean - public ProcessEngine processEngine(ProcessEngineConfiguration processEngineConfiguration) { - return processEngineConfiguration.buildProcessEngine(); - } - - @Bean - public MessageBasedJobManager jobManager(JmsTemplate jmsTemplate) { - MessageBasedJobManager jobManager = new MessageBasedJobManager(); - jobManager.setJmsTemplate(jmsTemplate); - return jobManager; - } - - @Bean - public ConnectionFactory connectionFactory() { - ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616"); - activeMQConnectionFactory.setUseAsyncSend(true); - activeMQConnectionFactory.setAlwaysSessionAsync(true); - return new CachingConnectionFactory(activeMQConnectionFactory); - } - - @Bean - public JmsTemplate jmsTemplate(ConnectionFactory connectionFactory) { - JmsTemplate jmsTemplate = new JmsTemplate(); - jmsTemplate.setDefaultDestination(new ActiveMQQueue("flowable-jobs")); - jmsTemplate.setConnectionFactory(connectionFactory); - return jmsTemplate; - } - - @Bean - public MessageListenerContainer messageListenerContainer(JobMessageListener jobMessageListener) { - DefaultMessageListenerContainer messageListenerContainer = new DefaultMessageListenerContainer(); - messageListenerContainer.setConnectionFactory(connectionFactory()); - messageListenerContainer.setDestinationName("flowable-jobs"); - messageListenerContainer.setMessageListener(jobMessageListener); - messageListenerContainer.setConcurrentConsumers(2); - messageListenerContainer.start(); - return messageListenerContainer; - } - - @Bean - public JobMessageListener jobMessageListener(ProcessEngineConfiguration processEngineConfiguration) { - JobMessageListener jobMessageListener = new JobMessageListener(); - jobMessageListener.setProcessEngineConfiguration(processEngineConfiguration); - return jobMessageListener; - } - -} ----- - -在上面的代码中,__flowable-jms-spring-executor__模块提供的只有__JobMessageListener__与__MessageBasedJobManager__两个类。其他的所有代码都来自Spring。因此,如果想要替换为其他的队列/协议,就需要替换这些类。 - -[[advanced_parseHandlers]] - -=== 深入流程解析 - -BPMN 2.0 XML需要解析为Flowable的内部模型,才能在Flowable引擎中执行。部署流程时,或是在内存中找不到流程时,会从数据库中读取XML并进行解析。 - -++BpmnParser++类会为每个流程创建一个++BpmnParser++实例,作为解析过程的容器。解析本身很简单:引擎对于每一个BPMN 2.0元素都有一个对应的++org.flowable.engine.parse.BpmnParseHandler++的实例,解析器将BPMN 2.0元素类映射至++BpmnParseHandler++实例。默认情况下,Flowable使用++BpmnParseHandler++实例处理所有支持的元素,并为流程的步骤附加执行监听器,以创建历史。 - -可以在Flowable引擎中添加++org.flowable.engine.parse.BpmnParseHandler++的自定义实例。比如常见使用场景是,为特定步骤添加执行监听器,向某个事件处理队列发送事件。Flowable处理历史就使用的是这种方式。要添加这种自定义处理器,需要调整Flowable配置: - -[source,xml,linenums] ----- - - - - - - - - - - - - ----- - -在++preBpmnParseHandlers++参数中配置的++BpmnParseHandler++实例将添加在默认处理器之前。类似的,++postBpmnParseHandlers++中实例将添加在默认处理器之后。有时顺序会影响自定义解析处理器中包含的逻辑,需要特别注意。 - -++org.flowable.engine.parse.BpmnParseHandler++是一个简单的接口: - -[source,java,linenums] ----- -public interface BpmnParseHandler { - - Collection? extends BaseElement>> getHandledTypes(); - - void parse(BpmnParse bpmnParse, BaseElement element); - -} ----- - -++getHandledTypes()++方法返回该解析器处理的所有类型的集合。集合的泛型提示,可用的类型是++BaseElement++的子类。也可以扩展++AbstractBpmnParseHandler++类,并覆盖++getHandledType()++方法,它只返回一个类而不是一个集合。这个类也包含了一些默认解析处理器通用的辅助方法。当解析器遇到匹配该方法的返回类型的元素时,将调用这个++BpmnParseHandler++实例进行解析。在下面的例子里,当遇到BPMN 2.0 XML中的流程元素时,就会执行其++executeParse++方法(这是一个类型转换方法,替代++BpmnParseHandler++接口中的普通++parse++方法)中的逻辑。 - -[source,java,linenums] ----- -public class TestBPMNParseHandler extends AbstractBpmnParseHandler { - - protected Class getHandledType() { - return Process.class; - } - - protected void executeParse(BpmnParse bpmnParse, Process element) { - .. - } - -} ----- - -**重要提示:**在实现自定义解析处理器时,不要使用任何用于解析BPMN 2.0结构的内部类。否则会很难查找bug。安全的做法是实现__BpmnParseHandler__接口,或扩展内部抽象类__org.flowable.engine.impl.bpmn.parser.handler.AbstractBpmnParseHandler__。 - -可以(但不常用)替换默认用于将BPMN 2.0元素解析为Flowable内部模型的++BpmnParseHandler++实例。可以通过下面的代码片段实现: - -[source,xml,linenums] ----- - - - ... - - ----- - -简单的例子,强制所有服务任务都异步执行: - -[source,java,linenums] ----- -public class CustomUserTaskBpmnParseHandler extends ServiceTaskParseHandler { - - protected void executeParse(BpmnParse bpmnParse, ServiceTask serviceTask) { - - // 进行常规操作 - super.executeParse(bpmnParse, serviceTask); - - // 保证异步执行 - serviceTask.setAsynchronous(true); - } - -} ----- - - -[[advanced.uuid.generator]] - - -=== 高并发下使用的UUID ID生成器 - -在某些(非常)高并发负载的情况下,默认的ID生成器可能会由于不能足够快地获取新的id块而产生异常。每个流程引擎都有一个ID生成器。默认的ID生成器会在数据库中保存一块ID,这样其他引擎就不能使用同一个块中的ID。引擎运行时,当ID生成器发现ID块已经用完,就会启动一个新的事务,来获取一个新的块。在(非常)有限的使用场景下,当负载非常高时可能导致问题。对于大多数用例来说,默认的ID生成器已经足够使用了。默认的++org.flowable.engine.impl.db.DbIdGenerator++也有一个++idBlockSize++参数,用于配置保留的ID块的大小,调整获取ID的行为。 - -可以使用++org.flowable.engine.impl.persistence.StrongUuidGenerator++替换默认的ID生成器。它会在本地生成唯一的link:$$http://en.wikipedia.org/wiki/Universally_unique_identifier$$[UUID],并将其用于所有实体的标识符。因为UUID不需要访问数据库就能生成,因此在非常高并发的使用场景下更合适。请注意取决于机器,性能可能与默认的ID生成器不同(更好更坏都有可能)。 - -可以在flowable配置中,像下面这样配置UUID生成器: - -[source,xml,linenums] ----- - - - ----- - -使用UUID id生成器需要添加下列额外依赖: - -[source,xml,linenums] ----- - - com.fasterxml.uuid - java-uuid-generator - 3.1.3 - ----- - - -[[advanced.tenancy]] - - -=== 多租户 - -总的来说,多租户是指一个软件为多个不同组织提供服务。其核心是数据隔离,一个组织不能看到其他组织的数据。在这个语境中,一个这样的组织(或部门、团队,等等)被称为一个__租户(tenant)__。 - -请注意它与多实例部署有本质区别。多实例部署是指每一个组织都分别运行一个Flowable流程引擎实例(且使用不同的数据库账户)。尽管Flowable比较轻量级,运行一个流程引擎实例不会花费太多资源,但多实例部署仍然增加了复杂度与维护量。但是,在某些使用场景中,多实例部署可能是正确的解决方案。 - -Flowable中的多租户主要围绕着隔离数据实现。要注意__Flowable并不强制多租户规则__。换句话说,查询与使用数据时,不会验证进行操作的用户是否属于正确的租户。这应该在调用Flowable引擎的层次实现。Flowable负责确保可以存储租户信息,并可在获取流程数据时使用。 - -在Flowable流程引擎中部署流程定义时,可以传递一个__租户标识符(tenant identifier)__。这是一个字符串(可以是UUID,部门id,等等……),限制为256个字符长,唯一标识一个租户: - -[source,java,linenums] ----- -repositoryService.createDeployment() - .addClassPathResource(...) - .tenantId("myTenantId") - .deploy(); ----- - - -在部署时传入一个租户ID意味着: - -* 部署中包含的所有流程定义都将从该部署继承租户标识符。 -* 从这些流程定义启动的所有流程实例都将从流程定义继承租户标识符。 -* 在执行流程实例时,创建所有任务都将从流程实例继承租户标识符。独立任务也可以有租户标识符。 -* 执行流程实例时,创建的所有执行都将从流程实例继承租户标识符。 -* (在流程内或通过API)触发信号抛出事件时可以提供租户标识符。这个信号将只在该租户的上下文中执行。也就是说,如果有多个使用相同名字的信号捕获事件,只会触发带有正确租户标识符的捕获事件。 -* 所有作业(定时器与异步操作)要么从流程定义(如定时器启动事件),要么从流程实例(运行时创建的作业,如异步操作)继承租户标识符。这样就可以在自定义作业执行器中,为租户设置优先级。 -* 所有历史实体(历史流程实例、任务与活动)都从其对应的运行时对象继承租户标识符。 -* 另外,模型也可以有租户标识符(模型用于Flowable Modeler存储BPMN 2.0)。 - -所有查询API都可以通过租户标识符进行过滤。例如(也可以换成其他实体的查询): - -[source,java,linenums] ----- -runtimeService.createProcessInstanceQuery() - .processInstanceTenantId("myTenantId") - .processDefinitionKey("myProcessDefinitionKey") - .variableValueEquals("myVar", "someValue") - .list() ----- - -查询API也可以使用__like__语义通过租户标识符过滤,也可以过滤掉没有租户标识符的实体。 - -**重要的实现细节:**由于数据库的原因(更确切地说,对唯一约束中null的处理),__默认的__代表__没有租户__的租户标识符为**空字符串**。这是因为(流程定义key,流程定义版本,租户标识符)的组合需要是唯一的(由数据库约束保证)。也请注意租户标识符不能设置为null,不然会影响查询,因为某些数据库(Oracle)会将空字符串当做null值处理(这也就是为什么__.withoutTenantId__查询不检查空字符串还是null)。所以可以为多个租户部署(有相同的流程定义key的)同一个流程定义,并且每一个租户都有他们自己的版本。不影响未使用租户时的使用方式。 - -**请注意,集群运行多个Flowable实例与上面所说不冲突。** - -[实验性] 可以调用__repositoryService__的__changeDeploymentTenantId(String deploymentId, String newTenantId)__方法修改租户标识符。并将连带修改每一处之前继承的租户标识符。在从非多租户环境迁移至多租户部署时很有用。查看该方法的Javadoc了解更多信息。 - -[[advanced.custom.sql.queries]] - -=== 执行自定义SQL - -Flowable提供了与数据库交互的高级API。例如,要获取数据,查询API与原生(Native)查询API各有用武之地。但有时会需要更高的灵活性。下面介绍如何在Flowable流程引擎范围内(所以可以使用相同的事务设置等)的数据存储中,执行完全自定义的SQL语句(select、insert、update与delete都可以)。 - -Flowable引擎使用其底层框架MyBatis的功能自定义SQL语句。可以在link:$$http://mybatis.github.io/mybatis-3/java-api.html$$[MyBatis用户手册]找到更多信息。 - -[[_annotation_based_mapped_statements]] -==== 基于注解的映射语句 - -使用基于注解的映射语句(Annotation based Mapped Statement)时,首先要做的是创建一个MyBatis映射类。例如,假设在某个用例中,不需要完整的任务数据,而只需要其中很少一部分,就可以通过映射类(Mapper)完成,像是这样: - -[source,java,linenums] ----- -public interface MyTestMapper { - - @Select("SELECT ID_ as id, NAME_ as name, CREATE_TIME_ as createTime FROM ACT_RU_TASK") - List> selectTasks(); - -} ----- - -必须像下面这样为流程引擎配置映射类: - -[source,xml,linenums] ----- -... - - - org.flowable.standalone.cfg.MyTestMapper - - -... ----- - -请注意这是一个接口。底层的MyBatis框架会构造一个它的实例,并在运行时使用。也请注意方法的返回值没有类型,而只是一个map的list(代表了带有列数据的行的列表)。如果需要,可以通过MyBatis映射类设置类型。 - -使用__managementService.executeCustomSql__方法执行上面的查询。这个方法使用__CustomSqlExecution__的实例作为包装器,将引擎需要处理的内部数据隐藏起来。 - -不幸的是,Java泛型降低了可读性。下面的两个泛型类是映射类与其返回类型类。只是简单的调用映射方法,并返回其结果(若有)。 - -[source,java,linenums] ----- -CustomSqlExecution>> customSqlExecution = - new AbstractCustomSqlExecution>>(MyTestMapper.class) { - - public List> execute(MyTestMapper customMapper) { - return customMapper.selectTasks(); - } - -}; - -List> results = managementService.executeCustomSql(customSqlExecution); ----- - -在这个例子里,上面列出的Map只包含__id, name与创建时间__,而不是完整的任务对象。 - -按照上面的方法可以使用任何SQL。另一个更复杂的例子: - -[source,java,linenums] ----- - @Select({ - "SELECT task.ID_ as taskId, variable.LONG_ as variableValue FROM ACT_RU_VARIABLE variable", - "inner join ACT_RU_TASK task on variable.TASK_ID_ = task.ID_", - "where variable.NAME_ = #{variableName}" - }) - List> selectTaskWithSpecificVariable(String variableName); ----- - -任务表join变量表,只选择变量有特定名字的记录,并返回任务id与对应的数字值。 - -请参考单元测试__org.flowable.standalone.cfg.CustomMybatisMapperTest__及src/test/java/org/flowable/standalone/cfg/与src/test/resources/org/flowable/standalone/cfg/目录中的其它类与资源,了解基于注解的映射语句的更多使用例子。 - -[[_xml_based_mapped_statements]] -==== 基于XML的映射语句 - -可以使用基于XML的映射语句(XML based Mapped Statement),在XML文件中定义语句。对于不需要完整的任务数据,而只需要其中很少一部分数据的用例,XML文件像是下面这样: - -[source,xml,linenums] ----- - - - - - - - - - - - ----- - -结果映射为如下的__org.flowable.standalone.cfg.CustomTask__类的实例: - -[source,java,linenums] ----- -public class CustomTask { - - protected String id; - protected String name; - protected Date createTime; - - public String getId() { - return id; - } - public String getName() { - return name; - } - public Date getCreateTime() { - return createTime; - } -} ----- - -必须像下面这样为流程引擎配置提供映射XML文件: - -[source,xml,linenums] ----- -... - - - org/flowable/standalone/cfg/custom-mappers/CustomTaskMapper.xml - - -... ----- - -这样执行语句: - -[source,java,linenums] ----- -List tasks = managementService.executeCommand(new Command>() { - - @SuppressWarnings("unchecked") - @Override - public List execute(CommandContext commandContext) { - return (List) CommandContextUtil.getDbSqlSession().selectList("selectCustomTaskList"); - } - }); ----- - -XML映射语句在需要更复杂语句的时候很好用。Flowable内部就使用XML映射语句,所以能使用底层功能。 - -假设某个用例下,需要基于id、name、type、userId等字段,查询附件数据。要实现这个用例,可以创建下面这样的扩展了__org.flowable.engine.impl.AbstractQuery__的查询类__AttachmentQuery__: - -[source,java,linenums] ----- -public class AttachmentQuery extends AbstractQuery { - - protected String attachmentId; - protected String attachmentName; - protected String attachmentType; - protected String userId; - - public AttachmentQuery(ManagementService managementService) { - super(managementService); - } - - public AttachmentQuery attachmentId(String attachmentId){ - this.attachmentId = attachmentId; - return this; - } - - public AttachmentQuery attachmentName(String attachmentName){ - this.attachmentName = attachmentName; - return this; - } - - public AttachmentQuery attachmentType(String attachmentType){ - this.attachmentType = attachmentType; - return this; - } - - public AttachmentQuery userId(String userId){ - this.userId = userId; - return this; - } - - @Override - public long executeCount(CommandContext commandContext) { - return (Long) CommandContextUtil.getDbSqlSession() - .selectOne("selectAttachmentCountByQueryCriteria", this); - } - - @Override - public List executeList(CommandContext commandContext, Page page) { - return CommandContextUtil.getDbSqlSession() - .selectList("selectAttachmentByQueryCriteria", this); - } ----- - -请注意在扩展__AbstractQuery__时,子类需要为super构造函数传递一个__ManagementService__的实例,并需要实现__executeCount__与__executeList__来调用映射语句。 - -包含映射语句的XML文件如下: - -[source,xml,linenums] ----- - - - - - - - - from ${prefix}ACT_HI_ATTACHMENT RES - - - RES.ID_ = #{attachmentId} - - - and RES.NAME_ = #{attachmentName} - - - and RES.TYPE_ = #{attachmentType} - - - and RES.USER_ID_ = #{userId} - - - - ----- - -可以在语句中使用例如分页、排序、表名前缀等功能(因为parameterType为__AbstractQuery__的子类)。可以使用引擎定义的__org.flowable.engine.impl.persistence.entity.AttachmentEntity.attachmentResultMap__来映射结果。 - -最后,可以这样使用__AttachmentQuery__: - -[source,java,linenums] ----- -.... -// 获取附件的总数 -long count = new AttachmentQuery(managementService).count(); - -// 获取id为10025的附件 -Attachment attachment = new AttachmentQuery(managementService).attachmentId("10025").singleResult(); - -// 获取前10个附件 -List attachments = new AttachmentQuery(managementService).listPage(0, 10); - -// 获取用户kermit上传的所有附件 -attachments = new AttachmentQuery(managementService).userId("kermit").list(); -.... ----- - -请参考单元测试__org.flowable.standalone.cfg.CustomMybatisXMLMapperTest___及src/test/java/org/flowable/standalone/cfg/与src/test/resources/org/flowable/standalone/cfg/目录中的其它类与资源,了解基于XML的映射语句的更多使用例子。 - -[[advanced.process.engine.configurators]] - - -=== 使用ProcessEngineConfigurator进行高级流程引擎配置 - -深入控制流程引擎配置的高级方法是使用__ProcessEngineConfigurator__。创建一个__org.flowable.engine.cfg.ProcessEngineConfigurator__接口的实现,并将它注入到流程引擎配置中: - -[source,xml,linenums] ----- - - - ... - - - - - ... - - - - - ... - - ----- - -这个接口需要实现两个方法。__configure__方法,使用一个__ProcessEngineConfiguration__实例作为参数。可以使用这个方式添加自定义配置,并且这个方法会保证**在流程引擎创建之前,所有默认配置已经完成之后**被调用。另一个方法是__getPriority__方法,可以指定配置器的顺序,以备某些配置器对其他的有依赖。 - -这种配置器的一个例子是<>,使用配置器将默认的用户与组管理类替换为可以处理LDAP用户的实现。可见配置器可以相当大程度地改变及调整流程引擎,以适应非常高级的使用场景。另一个例子是使用自定义的缓存替换流程引擎缓存: - -[source,java,linenums] ----- -public class ProcessDefinitionCacheConfigurator extends AbstractProcessEngineConfigurator { - - public void configure(ProcessEngineConfigurationImpl processEngineConfiguration) { - MyCache myCache = new MyCache(); - processEngineConfiguration.setProcessDefinitionCache(enterpriseProcessDefinitionCache); - } - -} ----- - -也可以使用link:$$http://docs.oracle.com/javase/7/docs/api/java/util/ServiceLoader.html$$[ServiceLoader]的方法,从classpath中自动发现流程引擎配置器。也就是说必须将包含配置器实现的jar放在classpath下,并且jar的__META-INF/services__目录下需要有名为**org.flowable.engine.cfg.ProcessEngineConfigurator**的文件,内容是自定义实现的全限定类名。当流程引擎启动时,日志会提示找到这些配置器: - ----- -INFO org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl - Found 1 auto-discoverable Process Engine Configurators -INFO org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl - Found 1 Process Engine Configurators in total: -INFO org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl - class org.flowable.MyCustomConfigurator ----- - -请注意某些环境下可能不能使用ServiceLoader方法。可以通过ProcessEngineConfiguration的__enableConfiguratorServiceLoader__参数显式禁用(默认为true)。 - -[[advanced.task.query.switching]] - -=== 高级查询API:在运行时与历史任务查询间无缝切换 - -BPM用户界面的核心组件是任务列表。一般来说,最终用户执行待办任务,通过不同方式过滤收件箱中的任务。有时也需要在列表中显示历史任务,并进行类似的过滤。为了简化代码,__TaskQuery__与__HistoricTaskInstanceQuery__有共同的父接口,其中包含了所有公共操作(大多数操作都是公共的)。 - -这个公共接口是__org.flowable.engine.task.TaskInfoQuery__类。__org.flowable.engine.task.Task__与__org.flowable.engine.task.HistoricTaskInstance__都有公共父类__org.flowable.engine.task.TaskInfo__(并带有公共参数),作为__list()__等方法的返回值。然而,有时Java泛型会帮倒忙:如果想要直接使用__TaskInfoQuery__类型,将会像是这样: - -[source,java,linenums] ----- -TaskInfoQuery, ? extends TaskInfo> taskInfoQuery ----- - -呃……好吧。为了“解决”这个问题,可以使用__org.flowable.engine.task.TaskInfoQueryWrapper__类来避免泛型(下面的代码来自REST的代码,将返回一个任务列表,且用户可以选择查看进行中还是已完成的任务): - -[source,java,linenums] ----- -TaskInfoQueryWrapper taskInfoQueryWrapper = null; -if (runtimeQuery) { - taskInfoQueryWrapper = new TaskInfoQueryWrapper(taskService.createTaskQuery()); -} else { - taskInfoQueryWrapper = new TaskInfoQueryWrapper(historyService.createHistoricTaskInstanceQuery()); -} - -List taskInfos = taskInfoQueryWrapper.getTaskInfoQuery().or() - .taskNameLike("%k1%") - .taskDueAfter(new Date(now.getTime() + (3 * 24L * 60L * 60L * 1000L))) -.endOr() -.list(); ----- - - -[[advanced.custom.session.manager]] - - -=== 通过覆盖标准SessionFactory自定义身份管理 - -如果不想像<>中那样使用完整的__ProcessEngineConfigurator__实现,但仍然希望在框架中插入自定义的身份管理,也可以覆盖__IdmIdentityServiceImpl__类,或者直接实现__IdmIdentityService__接口,并使用实现类作为__ProcessEngineConfiguration__中的__idmIdentityService__参数。在Spring中,可以简单地向__ProcessEngineConfiguration__bean定义添加下面的代码实现: - -[source,xml,linenums] ----- - - - ... - - - - - - ... - - - ----- - -__LDAPIdentityServiceImpl__类是一个介绍如何实现__IdmIdentityService__接口中方法的很好的例子。你需要自行判断需要在自定义身份服务类中实现什么方法。例如下面的调用: - -[source,java,linenums] ----- -long potentialOwners = identityService.createUserQuery().memberOfGroup("management").count(); ----- - -会调用__IdmIdentityService__接口的下列成员: - -[source,java,linenums] ----- -UserQuery createUserQuery(); ----- - -<>中的代码包含了如何实现这些的完整示例。可以在GitHub查看代码:link:$$https://github.com/flowable/flowable-engine/blob/master/modules/flowable-ldap/src/main/java/org/flowable/ldap/LDAPIdentityServiceImpl.java$$[LDAPIdentityServiceImpl]。 - -[[advanced.safe.bpmn.xml]] - -=== 启用安全BPMN 2.0 XML - -在大多数情况下,部署至Flowable引擎的BPMN 2.0流程处在开发团队等的严格控制下。然而,有的时候会希望能够向引擎上传任意的BPMN 2.0 XML。在这种情况下,需要考虑动机不良的用户可能会像link:$$http://www.jorambarrez.be/blog/2013/02/19/uploading-a-funny-xml-can-bring-down-your-server/$$[这里]描述的一样,破坏服务器。 - -要避免上面链接中描述的攻击,可以在流程引擎配置中设置__enableSafeBpmnXml__参数: - -[source,xml,linenums] ----- - ----- - -**默认情况下这个功能是禁用的!**原因是它依赖link:$$http://download.java.net/jdk7/archive/b123/docs/api/javax/xml/transform/stax/StAXSource.html$$[StaxSource]类。而不幸的是,某些平台(JDK6,JBoss等)不能使用这个类(由于使用的是过时的XML解析器),因此不能启用安全BPMN 2.0 XML功能。 - -如果运行Flowable的平台支持,请一定要启用这个功能。 - -[[advanced.event.logging]] - -=== 事件日志 - -Flowable引入了事件日志机制。日志机制基于<>,并默认禁用。总的来说,来源于引擎的事件会被捕获,并创建一个包含了所有事件数据(甚至更多)的map,提供给__org.flowable.engine.impl.event.logger.EventFlusher__,由它将这些数据保存其他地方。默认情况下,使用简单的基于数据库的事件处理器/保存器,用Jackson将上述map序列化为JSON,并将其作为__EventLogEntryEntity__实例存入数据库。默认会在数据库中创建__$$ACT_EVT_LOG$$__表保存事件日志。如果不使用事件日志,可以删除这个表。 - -要启用数据库记录器: - -[source,java,linenums] ----- -processEngineConfigurationImpl.setEnableDatabaseEventLogging(true); ----- - -或在运行时: - -[source,java,linenums] ----- -databaseEventLogger = new EventLogger(processEngineConfiguration.getClock(), - processEngineConfiguration.getObjectMapper()); -runtimeService.addEventListener(databaseEventLogger); ----- - -如果默认的数据库记录不符合要求,可以扩展EventLogger类。__createEventFlusher()__方法需要返回__org.flowable.engine.impl.event.logger.EventFlusher__接口的实例。可以使用__managementService.getEventLogEntries(startLogNr, size);__获取__EventLogEntryEntity__实例。 - -显然,这个表中的数据也可以JSON的形式存入NoSQL存储,如MongoDB,Elastic Search等。也容易看出这里使用的类(org.flowable.engine.impl.event.logger.EventLogger/EventFlusher与许多其他EventHandler类)是可插拔的,可以按你的使用场景调整。(比如将JSON直接发送给队列或NoSQL,而不存入数据库) - -请注意这个事件日志机制是独立于Flowable的“传统”历史管理器的。尽管所有数据都保存在数据库表中,但并未对查询或快速恢复做优化。实际使用场景主要是审计及存入大数据存储。 - -[[_disabling_bulk_inserts]] -=== 禁用批量插入 - -默认情况下,引擎会将对同一个数据库表的多个插入语句组合在一起,作为__批量插入__。这样能够提高性能,并已在所有支持的数据库中实现及测试。 - -然而,即使是支持及测试过的数据库,也可能有某个特定版本不支持批量插入(例如有报告说DB2在z/OS上不支持,尽管一般来说DB2是支持的)。这时可以在流程引擎配置中禁用批量插入: - -[source,xml,linenums] ----- - ----- - -[[advancedSecureScripting]] -=== 安全脚本 - -默认情况下,使用<>时,执行的脚本与Java代码具有相似的能力。可以完全访问JVM,永远运行(无限循环),或占用大量内存。 - -相较而言,Java代码需要放在classpath的jar中,与流程定义的生命周期不一样。最终用户一般不会撰写Java代码,这基本上是开发者的工作。 - -而脚本是流程定义的一部分,生命周期一致。脚本任务不需要额外的jar部署步骤,而是在流程部署后就可以执行。有时,脚本任务中的脚本不是由开发者撰写的。所以会产生这个问题:脚本可以完全访问JVM,也可以在执行脚本时阻塞许多系统资源。因此允许执行来自任何人的脚本并不是一个好主意。 - -可以启用__安全脚本__功能解决这个问题。目前,这个功能只实现了__javascript__脚本,在项目中添加__flowable-secure-javascript__依赖启用。Maven: - -[source,xml,linenums] ----- - - org.flowable - flowable-secure-javascript - ${flowable.version} - ----- - -添加这个依赖会同时引入Rhino依赖(参见link:$https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rhino$$[https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rhino])。Rhino是一个用于JDK的javascript引擎。过去包含在JDK6与7中,并已被Nashorn引擎取代。然而,Rhino项目仍然在继续开发。许多(包括Flowable用于实现安全脚本的)功能都在之后才加入。在撰写本手册的时候,Nashorn**还没有**实现安全脚本功能需要的功能。 - -这意味着脚本可能存在一些(基本很少)区别(例如,Rhino使用__importPackage__,而Nashorn使用__load()__)。 - -通过专门的__Configurator__对象配置安全脚本,并在流程引擎实例化之前将其传递给流程引擎配置: - -[source,java,linenums] ----- -SecureJavascriptConfigurator configurator = new SecureJavascriptConfigurator() - .setWhiteListedClasses(new HashSet(Arrays.asList("java.util.ArrayList"))) - .setMaxStackDepth(10) - .setMaxScriptExecutionTime(3000L) - .setMaxMemoryUsed(3145728L) - .setNrOfInstructionsBeforeStateCheckCallback(10); - -processEngineConfig.addConfigurator(configurator); ----- - -可以使用下列设置: - -* *enableClassWhiteListing*: 为true时,会将所有类加入黑名单。需要在白名单中添加希望运行的所有类,严格控制暴露给脚本的东西。默认为__false__。 -* *whiteListedClasses*: 一个全限定类名字符串的集合,表示允许在脚本中使用的类。例如,要在脚本中使用__execution__对象,需要在这个集合中添加__org.flowable.engine.impl.persistence.entity.ExecutionEntityImpl__字符串。默认为__空__。 -* *maxStackDepth*: 限制在脚本中调用函数时的最大栈深度。可以用于避免在脚本中递归调用方法而导致的栈溢出异常。默认为__-1__(禁用)。 -* *maxScriptExecutionTime*: 脚本允许运行的最大时间。默认为__-1__(禁用)。 -* *maxMemoryUsed*: 脚本允许使用的最大内存数量,以字节计。请注意脚本引擎自己也要需要一定量的内存,也会算在这里。默认为__-1__(禁用)。 -* *nrOfInstructionsBeforeStateCheckCallback*: 脚本每执行x个指令,就通过回调函数进行一次脚本执行时间与内存检测。请注意这不是指脚本指令,而是指java字节码指令(一行脚本可能有上百行字节码指令)。默认为100。 - -__请注意:____maxMemoryUsed__设置只能用于支持com.sun.management.ThreadMXBean#getThreadAllocatedBytes()方法的JVM,如Oracle JDK。 - -ScriptExecutionListener与ScriptTaskListener也有安全形式:__org.flowable.scripting.secure.listener.SecureJavascriptExecutionListener__与__org.flowable.scripting.secure.listener.SecureJavascriptTaskListener__。 - -像这样使用: - -[source,xml,linenums] ----- - - - - - - - - ----- - -可以通过link:$$https://github.com/Flowable/Flowable/tree/master/modules/flowable-secure-javascript/src/test/resources$$[GitHub上的单元测试], -查看不安全脚本以及通过__安全脚本__功能将其变得安全的例子, diff --git a/docs/userguide/src/zh_CN/bpmn/ch17-Ldap.adoc b/docs/userguide/src/zh_CN/bpmn/ch17-Ldap.adoc deleted file mode 100644 index ed224cbf57a..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch17-Ldap.adoc +++ /dev/null @@ -1,211 +0,0 @@ -[[chapter_ldap]] - -== LDAP integration - -Companies often already have a user and group store in the form of an LDAP system. Flowable offers an out-of-the-box solution for easily configuring how Flowable should connect with an LDAP system. - -In earlier versions, it was already possible to integrate LDAP, but since then, the configuration has been simplified a lot. However, the 'old' way of configuring LDAP still works. More specifically, the simplified configuration is just a wrapper on top of the 'old' infrastructure. - - -[[ldap_usage]] - - -=== Usage - -To add the LDAP integration code to your project, simply add the following dependency to your pom.xml: - -[source,xml,linenums] ----- - - org.flowable - flowable-ldap-configurator - latest.version - ----- - - -[[ldap_usecases]] - - -=== Use cases - -The LDAP integration has currently two main use cases: - -* Allow for authentication through the IdentityService. This could be useful when doing everything through the IdentityService. -* Fetching the groups of a user. This is important when for example querying tasks to see which tasks a certain user can see (i.e. tasks with a candidate group). - - -[[ldap_configuration]] - - -=== Configuration - -Integrating the LDAP system with Flowable is done by injecting an instance of +org.flowable.ldap.LDAPConfigurator+ in the +idmProcessEngineConfigurator+ section of the process engine configuration. This class is highly extensible: methods can be easily overridden and many dependent beans are pluggable if the default implementation would not fit the use case. - -This is an example configuration (note: of course, when creating the engine programmatically this is completely similar). Don't worry about all the properties for now, we'll look at them in detail in a next section. - -[source,xml,linenums] ----- - - ... - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ----- - -[[ldap_properties]] - - -=== Properties - - -Following properties can be set on ++org.flowable.ldap.LDAPConfiguration++: - - .LDAP configuration properties -[options="header"] -|=============== -|Property name|Description|Type|Default value -|server|The server on which the LDAP system can be reached. For example 'ldap://localhost:33389'|String| -|port|The port on which the LDAP system is running|int| -|user|The user id that is used to connect to the LDAP system|String| -|password|The password that is used to connect to the LDAP system|String| -|initialContextFactory|The InitialContextFactory name used to connect to the LDAP system|String|com.sun.jndi.ldap.LdapCtxFactory -|securityAuthentication|The value that is used for the 'java.naming.security.authentication' property used to connect to the LDAP system|String|simple -|customConnectionParameters|Allows to set all LDAP connection parameters which do not have a dedicated setter. - See for example http://docs.oracle.com/javase/tutorial/jndi/ldap/jndi.html for custom - properties. Such properties are for example to configure connection pooling, specific - security settings, etc. All the provided parameters will be provided when creating a - connection to the LDAP system.|Map| -|baseDn|The base 'distinguished name' (DN) from which the searches for users and groups are started|String| -|userBaseDn|The base 'distinguished name' (DN) from which the searches for users are started. If not provided, baseDn (see above) will be used|String| -|groupBaseDn|The base 'distinguished name' (DN) from which the searches for groups are started. If not provided, baseDn (see above) will be used|String| -|searchTimeLimit|The timeout that is used when doing a search in LDAP in milliseconds|long|one hour -|queryUserByUserId| - The query that is executed when searching for a user by userId. - For example: (&(objectClass=inetOrgPerson)(uid={0})) - Here, all the objects in LDAP with the class 'inetOrgPerson' - and who have the matching 'uid' attribute value will be returned. - As shown in the example, the user id is injected by using - {0}. If setting the query alone is insufficient for your specific - LDAP setup, you can alternatively plug in a different - LDAPQueryBuilder, which allows for more customization than only the query. - |string| -|queryUserByFullNameLike| - The query that is executed when searching for a user by full name. - For example: (& (objectClass=inetOrgPerson) (|({0}=*{1}*)({2}=*{3}*)) ) - Here, all the objects in LDAP with the class 'inetOrgPerson' - and who have the matching first name and last name values will be returned. - Note that {0} injects the firstNameAttribute (as defined above), {1} and {3} the search text - and {2} the lastNameAttribute. If setting the query alone is insufficient for your specific - LDAP setup, you can alternatively plug in a different - LDAPQueryBuilder, which allows for more customization than only the query. - |string| -|queryAllUsers| - The query that is executed when searching on users without a filter. - For example: (objectClass=inetOrgPerson) - Here, all the objects in LDAP with the class 'inetOrgPerson' will be returned. - |string| -|queryGroupsForUser|The query that is executed when searching for the groups of a specific user. - For example: (&(objectClass=groupOfUniqueNames)(uniqueMember={0})) - Here, all the objects in LDAP with the class 'groupOfUniqueNames' - and where the provided DN (matching a DN for a user) is a 'uniqueMember' are returned. - As shown in the example, the user id is injected by using {0} - If setting the query alone is insufficient for your specific - LDAP setup, you can alternatively plug in a different - LDAPQueryBuilder, which allows for more customization than only the query.|string| -|queryAllGroups| - The query that is executed when searching on groups without a filter. - For example: (objectClass=groupOfUniqueNames) - Here, all the objects in LDAP with the class 'groupOfUniqueNames' will be returned. - |string| -|userIdAttribute|Name of the attribute that matches the user id. - This property is used when looking for a User object - and the mapping between the LDAP object and the Flowable User object - is done.|string| -|userFirstNameAttribute|Name of the attribute that matches the user first name. - This property is used when looking for a User object - and the mapping between the LDAP object and the Flowable User object is done.|string| -|userLastNameAttribute|Name of the attribute that matches the user last name. - This property is used when looking for a User object - and the mapping between the LDAP object and the Flowable User object is done.|string| -|groupIdAttribute|Name of the attribute that matches the group id. - This property is used when looking for a Group object - and the mapping between the LDAP object and the Flowable Group object is done.|string| -|groupNameAttribute|Name of the attribute that matches the group name. - This property is used when looking for a Group object - and the mapping between the LDAP object and the Flowable Group object is done.|String| -|groupTypeAttribute|Name of the attribute that matches the group type. - This property is used when looking for a Group object - and the mapping between the LDAP object and the Flowable Group object - is done.|String| - -|=============== - - -Following properties are when one wants to customize default behavior or introduced group caching: - -.Advanced properties -[options="header"] -|=============== -|Property name|Description|Type|Default value -|ldapUserManagerFactory|Set a custom implementation of the LDAPUserManagerFactory if the default implementation is not suitable.|instance of LDAPUserManagerFactory| -|ldapGroupManagerFactory|Set a custom implementation of the LDAPGroupManagerFactory if the default implementation is not suitable.|instance of LDAPGroupManagerFactory| -|ldapMemberShipManagerFactory|Set a custom implementation of the LDAPMembershipManagerFactory if the default implementation is not suitable. - Note that this is very unlikely, as membership are managed in the LDAP system itself normally.|An instance of LDAPMembershipManagerFactory| -|ldapQueryBuilder|Set a custom query builder if the default implementation is not suitable. - The LDAPQueryBuilder instance is used when the LDAPUserManager or - LDAPGroupManage} does an actual query against the LDAP system. - The default implementation uses the properties as set on this instance - such as queryGroupsForUser and queryUserById|An instance of org.flowable.ldap.LDAPQueryBuilder| -|groupCacheSize| Allows to set the size of the group cache. - This is an LRU cache that caches groups for users and thus - avoids hitting the LDAP system each time the groups of - a user needs to be known. - - The cache will not be instantiated if the value is less than zero. - By default set to -1, so no caching is done. - |int|-1 -|groupCacheExpirationTime|Sets the expiration time of the group cache in milliseconds. - When groups for a specific user are fetched, and if the group cache exists, - the groups will be stored in this cache for the time set in this property. - I.e. when the groups were fetched at 00:00 and the expiration time is 30 minutes, - any fetch of the groups for that user after 00:30 will not come from the cache, but do - a fetch again from the LDAP system. Likewise, everything group fetch for that user done - between 00:00 - 00:30 will come from the cache.|long|one hour - -|=============== - - -Note when using Active Directory: people have reported that for Active Directory, the 'InitialDirContext' needs to be set to Context.REFERRAL. This can be passed through the customConnectionParameters map as described above. - diff --git a/docs/userguide/src/zh_CN/bpmn/ch18-Advanced.adoc b/docs/userguide/src/zh_CN/bpmn/ch18-Advanced.adoc deleted file mode 100644 index de4c3fa2588..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch18-Advanced.adoc +++ /dev/null @@ -1,886 +0,0 @@ - -== Advanced - -The following sections cover advanced use cases of Flowable, that go beyond typical execution of BPMN 2.0 processes. As such, a certain proficiency and experience with Flowable is advised to understand the topics described here. - -=== Async Executor - -In Flowable v5, the Async executor was added in addition to the existing job executor. The Async Executor has proved to be more performant than the old job executor by many users of Flowable and in our benchmarks. - -From Flowable V6, the async executor is the only one available. For V6, the async executor has been completely refactored for optimal performance and pluggability, while still being compatible with existing APIs. - -[[async_executor_design]] - -==== Async Executor design - -Two types of jobs exist: timers (such as those belonging to a boundary event on a user task) and async continuations (belonging to a service task with the _flowable:async="true"_ attribute). - -*Timers* are the easiest to explain: they are persisted in the ACT_RU_TIMER_JOB table with a certain due date. There is a thread in the async executor that periodically checks if there are new timers that should fire (in other words, the due date is 'before' the current time). When that happens, the timer is removed and an async job is created. - -An *async job* is inserted in the database during the execution of process instance steps (which means, during some API call that was made). If the async executor is active for the current Flowable engine, the async job is actually already _locked_. This means that the job entry is inserted in the ACT_RU_JOB table and will have a _lock owner_ and a _lock expiration time_ set. A transaction listener that fires on a successful commit of the API call triggers the async executor of the same engine to execute the job (so the data is guaranteed to be in the database). To do this, the async executor has a configurable thread pool from which a thread will execute the job and continue the process asynchronously. If the Flowable engine does not have the async executor enabled, the async job is inserted in the ACT_RU_JOB table without being locked. - -Similar to the thread that checks for new timers, the async executor has a thread that 'acquires' new async jobs. These are jobs that are present in the table that are not locked. This thread will lock these jobs for the current Flowable engine and pass it to the async executor. - -The thread pool executing the jobs uses an in-memory queue from which to take jobs. When this queue is full (this is configurable), the job will be unlocked and re-inserted into its table. This way, other async executors can pick it up instead. - -If an exception happens during job execution, the async job will be transformed to a timer job with a due date. Later, it will be picked up like a regular timer job and become an async job again, to be retried soon. When a job has been retried for a (configurable) number of times and continues to fail, the job is assumed to be 'dead' and moved to the ACT_RU_DEADLETTER_JOB. The 'deadletter' concept is widely used in various other systems. An administrator will now need to inspect the exception for the failed job and decide what the best course of action is. - -Process definitions and process instances can be suspended. Suspended jobs related to these definitions or instances are put in the ACT_RU_SUSPENDED_JOB table, to make sure the query to acquire jobs has as few possible conditions in its where clause. - -One thing that is clear from the above: for people familiar with the old implementations of the job/async executor, the main goal is to allow the 'acquire queries' to be as simple as possible. In the past (before V6), one table was used for all job types/states, which made the 'where' condition large as it catered for all the use cases. This problem is now solved and our benchmarks have proved that this new design delivers better performance and is more scalable. - - -==== Async executor configuration - -The async executor is a highly configurable component. It's always recommended to look into the default settings of the async executor and validate if they match the requirements of your processes. - -Alternatively, it's possible to extend the default implementation or replace the _org.flowable.engine.impl.asyncexecutor.AsyncExecutor_ interface with your own implementation. - -The following properties are available on the process engine configuration through setters: - -.Async executor configuration options -[options="header"] -|=============== -|Name|Default value|Description - -|asyncExecutorThreadPoolQueueSize|100|The size of the queue on which jobs to be executed are placed after being acquired, before they are actually executed by a thread from the thread pool -|asyncExecutorCorePoolSize|8|The minimal number of threads that are kept alive in the thread pool for job execution. -|asyncExecutorMaxPoolSize|8|The maximum number of threads that are created in the thread pool for job execution. -|asyncExecutorThreadKeepAliveTime|5000|The time (in milliseconds) a thread used for job execution must be kept alive before it is destroyed. Having a setting > 0 takes resources, but in the case of many job executions it avoids creating new threads all the time. If 0, threads will be destroyed after they've been used for job execution. -|asyncExecutorNumberOfRetries|3|The number of times a job will be retried before it is moved to the 'deadletter' table. -|asyncExecutorMaxTimerJobsPerAcquisition|1|The number of timer jobs that are acquired in one query. Default value is 1, as this lowers the potential for optimistic locking exceptions. Larger values can perform better, but the chance of optimistic locking exceptions occurring between different engines becomes larger too. -|asyncExecutorMaxAsyncJobsDuePerAcquisition|1|The number of async jobs that are acquired during one query. Default value is 1, as this lowers the potential for optimistic locking exceptions. Larger values can perform better, but the chance of optimistic locking exceptions occurring between different engines becomes larger too. -|asyncExecutorDefaultTimerJobAcquireWaitTime|10000|The time (in milliseconds) the timer acquisition thread will wait to execute the next query. This happens when no new timer jobs are found or when less timer jobs have been fetched than set in _asyncExecutorMaxTimerJobsPerAcquisition_. -|asyncExecutorDefaultAsyncJobAcquireWaitTime|10000|The time (in milliseconds) the async job acquisition thread will wait to execute the next query. This happens when no new async jobs were found or when less async jobs have been fetched than set in _asyncExecutorMaxAsyncJobsDuePerAcquisition_. -|asyncExecutorDefaultQueueSizeFullWaitTime|0|The time (in milliseconds) the async job (both timer and async continuations) acquisition thread will wait when the internal job queue is full to execute the next query. By default set to 0 (for backwards compatibility). Setting this property to a higher value allows the async executor to hopefully clear its queue a bit. -|asyncExecutorTimerLockTimeInMillis|5 minutes|The amount of time (in milliseconds) a timer job is locked when acquired by the async executor. During this period of time, no other async executor will try to acquire and lock this job. -|asyncExecutorAsyncJobLockTimeInMillis|5 minutes|The amount of time (in milliseconds) an async job is locked when acquired by the async executor. During this period of time, no other async executor will try to acquire and lock this job. -|asyncExecutorSecondsToWaitOnShutdown|60|The time (in seconds) that is waited to gracefully shut down the thread pool used for job execution when a shutdown on the executor (or process engine) is requested. -|asyncExecutorResetExpiredJobsInterval|60 seconds|The amount of time (in milliseconds) that is between two consecutive checks of 'expired jobs'. Expired jobs are jobs that were locked (a lock owner + time was written by some executor, but the job was never completed). During such a check, jobs that are expired are made available again, meaning the lock owner and lock time will be removed. Other executors will now be able to pick it up. A job is deemed expired if the lock time is before the current date. -|asyncExecutorResetExpiredJobsPageSize|3|The amount of jobs that are fetched at once by the 'reset expired' thread of the async executor. -|=============== - -==== Message Queue based Async Executor - -When reading the <>, it becomes clear that the architecture is inspired by message queues. The async executor is designed in such a way that a message queue can easily be used to take over the job of the thread pool and the handling of async jobs. - -Benchmarks have shown that using a message queue is superior, throughput-wise, to the thread pool-backed async executor. However, it does come with an extra architectural component, which of course makes setup, maintenance and monitoring more complex. For many users, the performance of the thread pool-backed async executor is more than sufficient. It is nice to know however, that there is an alternative if the required performance grows. - -Currently, the only option that is supported out-of-the-box is JMS with Spring. The reason for supporting Spring before anything else is because Spring has some very nice features that ease a lot of the pain when it comes to threading and dealing with multiple message consumers. However, the integration is so simple, that it can easily be ported to any message queue implementation or protocol (Stomp, AMPQ, and so on). Feedback is appreciated for what should be the next implementation. - -When a new async job is created by the engine, a message is put on a message queue (in a transaction committed transaction listener, so we're sure the job entry is in the database) containing the job identifier. A message consumer then takes this job identifier to fetch the job, and execute the job. The async executor will not create a thread pool anymore. It will insert and query for timers from a separate thread. When a timer fires, it is moved to the async job table, which now means a message is sent to the message queue too. The 'reset expired' thread will also unlock jobs as usual, as message queues can fail too. Instead of 'unlocking' a job, a message will now be resent. The async executor will not poll for async jobs anymore. - -The implementation consists of two classes: - -* An implementation of the _org.flowable.engine.impl.asyncexecutor.JobManager_ interface that puts a message on a message queue instead of passing it to the thread pool. -* A _jakarta.jms.MessageListener_ implementation that consumes a message from the message queue, using the job identifier in the message to fetch and execute the job. - -First of all, add the _flowable-jms-spring-executor_ dependency to your project: - -[source,xml,linenums] ----- - - org.flowable - flowable-jms-spring-executor - ${flowable.version} - ----- - -To enable the message queue based async executor, in the process engine configuration, the following needs to be done: - -* _asyncExecutorActivate_ must be set to _true_, as usual -* _asyncExecutorMessageQueueMode_ needs to be set to _true_ -* The _org.flowable.spring.executor.jms.MessageBasedJobManager_ must be injected as _JobManager_ - -Below is a complete example of a Java based configuration, using _ActiveMQ_ as the message queue broker. - -Some things to note: - -* The _MessageBasedJobManager_ expects a _JMSTemplate_ to be injected that is configured with a correct _connectionFactory_. -* We're using the _MessageListenerContainer_ concept from Spring, as this simplifies threading and multiple consumers a lot. - -[source,java,linenums] ----- -@Configuration -public class SpringJmsConfig { - - @Bean - public DataSource dataSource() { - // Omitted - } - - @Bean(name = "transactionManager") - public PlatformTransactionManager transactionManager(DataSource dataSource) { - DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(); - transactionManager.setDataSource(dataSource); - return transactionManager; - } - - @Bean - public SpringProcessEngineConfiguration processEngineConfiguration(DataSource dataSource, PlatformTransactionManager transactionManager, - JobManager jobManager) { - SpringProcessEngineConfiguration configuration = new SpringProcessEngineConfiguration(); - configuration.setDataSource(dataSource); - configuration.setTransactionManager(transactionManager); - configuration.setDatabaseSchemaUpdate(SpringProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE); - configuration.setAsyncExecutorMessageQueueMode(true); - configuration.setAsyncExecutorActivate(true); - configuration.setJobManager(jobManager); - return configuration; - } - - @Bean - public ProcessEngine processEngine(ProcessEngineConfiguration processEngineConfiguration) { - return processEngineConfiguration.buildProcessEngine(); - } - - @Bean - public MessageBasedJobManager jobManager(JmsTemplate jmsTemplate) { - MessageBasedJobManager jobManager = new MessageBasedJobManager(); - jobManager.setJmsTemplate(jmsTemplate); - return jobManager; - } - - @Bean - public ConnectionFactory connectionFactory() { - ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616"); - activeMQConnectionFactory.setUseAsyncSend(true); - activeMQConnectionFactory.setAlwaysSessionAsync(true); - return new CachingConnectionFactory(activeMQConnectionFactory); - } - - @Bean - public JmsTemplate jmsTemplate(ConnectionFactory connectionFactory) { - JmsTemplate jmsTemplate = new JmsTemplate(); - jmsTemplate.setDefaultDestination(new ActiveMQQueue("flowable-jobs")); - jmsTemplate.setConnectionFactory(connectionFactory); - return jmsTemplate; - } - - @Bean - public MessageListenerContainer messageListenerContainer(JobMessageListener jobMessageListener) { - DefaultMessageListenerContainer messageListenerContainer = new DefaultMessageListenerContainer(); - messageListenerContainer.setConnectionFactory(connectionFactory()); - messageListenerContainer.setDestinationName("flowable-jobs"); - messageListenerContainer.setMessageListener(jobMessageListener); - messageListenerContainer.setConcurrentConsumers(2); - messageListenerContainer.start(); - return messageListenerContainer; - } - - @Bean - public JobMessageListener jobMessageListener(ProcessEngineConfiguration processEngineConfiguration) { - JobMessageListener jobMessageListener = new JobMessageListener(); - jobMessageListener.setProcessEngineConfiguration(processEngineConfiguration); - return jobMessageListener; - } - -} ----- - -In the code above, the _JobMessageListener_ and _MessageBasedJobManager_ are the only classes from the _flowable-jms-spring-executor_ module. All the other code is from Spring. As such, when wanting to port this to other queues/protocols, these classes must be ported. - - -[[advanced_parseHandlers]] - -=== Hooking into process parsing - -A BPMN 2.0 XML needs to be parsed to the Flowable internal model to be executed on the Flowable engine. This parsing happens during a deployment of the process or when a process is not found in memory, and the XML is fetched from the database. - -For each of these processes, the +BpmnParser+ class creates a new +BpmnParse+ instance. This instance will be used as container for all things that are done during parsing. The parsing, by itself, is very simple: for each BPMN 2.0 element, there is a matching instance of the +org.flowable.engine.parse.BpmnParseHandler+ available in the engine. As such, the parser has a map that basically maps a BPMN 2.0 element class to an instance of +BpmnParseHandler+. By default, Flowable has +BpmnParseHandler+ instances to handle all supported elements and also uses it to attach execution listeners to steps of the process for creating the history. - -It is possible to add custom instances of +org.flowable.engine.parse.BpmnParseHandler+ to the Flowable engine. An often seen use case, for example, is to add execution listeners to certain steps that fire events to some queue for event processing. The history handling is done in such a way internally in Flowable. To add such custom handlers, the Flowable configuration needs to be tweaked: - -[source,xml,linenums] ----- - - - - - - - - - - - - ----- - -The list of +BpmnParseHandler+ instances that is configured in the +preBpmnParseHandlers+ property are added before any of the default handlers. Likewise, the +postBpmnParseHandlers+ are added after those. This can be important if the order of things matter for the logic contained in the custom parse handlers. - -+org.flowable.engine.parse.BpmnParseHandler+ is a simple interface: - -[source,java,linenums] ----- -public interface BpmnParseHandler { - - Collection? extends BaseElement>> getHandledTypes(); - - void parse(BpmnParse bpmnParse, BaseElement element); - -} ----- - -The +getHandledTypes()+ method returns a collection of all the types handled by this parser. The possible types are a subclass of +BaseElement+, as directed by the generic type of the collection. You can also extend the +AbstractBpmnParseHandler+ class and override the +getHandledType()+ method, which only returns one Class and not a collection. This class also contains some helper methods shared by many of the default parse handlers. The +BpmnParseHandler+ instance will be called when the parser encounters any of the types returned by this method. In the following example, whenever a process contained in some BPMN 2.0 XML is encountered, it will execute the logic in the +executeParse+ method (which is a typecast method that replaces the regular +parse+ method on the +BpmnParseHandler+ interface). - -[source,java,linenums] ----- -public class TestBPMNParseHandler extends AbstractBpmnParseHandler { - - protected Class getHandledType() { - return Process.class; - } - - protected void executeParse(BpmnParse bpmnParse, Process element) { - .. - } - -} ----- - -*Important note:* when writing custom parse handlers, do not use any of the internal classes that are used to parse the BPMN 2.0 constructs. This will cause difficult to find bugs. The safe way to implement a custom handler is to implement the _BpmnParseHandler_ interface or extend the internal abstract class _org.flowable.engine.impl.bpmn.parser.handler.AbstractBpmnParseHandler_. - -It is possible (but less common) to replace the default +BpmnParseHandler+ instances that are responsible for the parsing of the BPMN 2.0 elements to the internal Flowable model. This can be done by following snippet of logic: - -[source,xml,linenums] ----- - - - ... - - ----- - -A simple example could, for example, be to force all of the service tasks to be asynchronous: - -[source,java,linenums] ----- -public class CustomUserTaskBpmnParseHandler extends ServiceTaskParseHandler { - - protected void executeParse(BpmnParse bpmnParse, ServiceTask serviceTask) { - - // Do the regular stuff - super.executeParse(bpmnParse, serviceTask); - - // Make always async - serviceTask.setAsynchronous(true); - } - -} ----- - - -[[advanced.uuid.generator]] - - -=== UUID ID generator for high concurrency - -In some (very) high concurrency load cases, the default ID generator may cause exceptions due to not being able to fetch new ID blocks quickly enough. Every process engine has one ID generator. The default ID generator reserves a block of IDs in the database, such that no other engine will be able to use IDs from the same block. During engine operations, when the default ID generator notices that the ID block is used up, a new transaction is started to fetch a new block. In (very) limited use cases this can cause problems when there is a real high load. For most use cases the default ID generator is more than sufficient. The default +org.flowable.engine.impl.db.DbIdGenerator+ also has a property +idBlockSize+ which can be configured to set the size of the reserved block of IDs and to tweak the behavior of the ID fetching. - -The alternative to the default ID generator is the +org.flowable.engine.impl.persistence.StrongUuidGenerator+, which generates a unique link:$$http://en.wikipedia.org/wiki/Universally_unique_identifier$$[UUID] locally and uses that as an identifier for all entities. Since the UUID is generated without the need for database access, it copes better with very high concurrency use cases. Do note that performance may differ from the default ID generator (both positive and negative) depending on the machine. - -The UUID generator can be set up in the Flowable configuration as follows: - -[source,xml,linenums] ----- - - - ----- - - -The use of the UUID ID generator has the following extra dependency: - -[source,xml,linenums] ----- - - com.fasterxml.uuid - java-uuid-generator - 3.1.3 - ----- - - -[[advanced.tenancy]] - - -=== Multitenancy - - -Multitenancy in general is a concept where the software is capable of serving multiple different organizations. Key is that the data is partitioned and no organization can see the data of other ones. In this context, such an organization (or a department, or a team or whatever, is called a _tenant_. - -Note that this is fundamentally different from a multi-instance setup, where a Flowable Process engine instance is running for each organization separately (and with a different database schema). Although Flowable is lightweight, and running a Process Engine instance doesn't take much resources, it does add complexity and more maintenance. But, for some use cases it might be the right solution. - -Multitenancy in Flowable is mainly implemented around partitioning the data. It is important to note that _Flowable does not enforce multi tenancy rules_. This means it will not verify when querying and using data whether the user doing the operation belongs to the correct tenant. This should be done in the layer calling the Flowable engine. Flowable does make sure that tenant information can be stored and used when retrieving process data. - -When deploying process definition to the Flowable Process engine it is possible to pass a _tenant identifier_. This is a string (e.g. a UUID, department id, etc.), limited to 256 characters which uniquely identifies the tenant: - -[source,java,linenums] ----- -repositoryService.createDeployment() - .addClassPathResource(...) - .tenantId("myTenantId") - .deploy(); ----- - - -Passing a tenant ID during a deployment has following implications: - -* All the process definitions contained in the deployment inherit the tenant identifier from this deployment. -* All process instances started from those process definitions inherit this tenant identifier from the process definition. -* All tasks created at runtime when executing the process instance inherit this tenant identifier from the process instance. Standalone tasks can have a tenant identifier too. -* All executions created during process instance execution inherit this tenant identifier from the process instance. -* Firing a signal throw event (in the process itself or through the API) can be done whilst providing a tenant identifier. The signal will only be executed in the tenant context: i.e. if there are multiple signal catch events with the same name, only the one with the correct tenant identifier will actually be called. -* All jobs (timers and async continuations) inherit the tenant identifier from either the process definition (e.g. timer start event) or the process instance (when a job is created at runtime, e.g. an async continuation). This could potentially be used for giving priority to some tenants in a custom job executor. -* All the historic entities (historic process instance, task and activities) inherit the tenant identifier from their runtime counterparts. -* As a side note, models can have a tenant identifier too (models are used e.g. by the Flowable modeler to store BPMN 2.0 models). - -To actually make use of the tenant identifier on the process data, all the query API's have the capability to filter on tenant. For example (and can be replaced by the relevant query implementation of the other entities): - -[source,java,linenums] ----- -runtimeService.createProcessInstanceQuery() - .processInstanceTenantId("myTenantId") - .processDefinitionKey("myProcessDefinitionKey") - .variableValueEquals("myVar", "someValue") - .list() ----- - -The query API's also allow to filter on the tenant identifier with _like_ semantics and also to filter out entities without tenant id. - -*Important implementation detail:* due to database quirks (more specifically: null handling in unique constraints) the _default_ tenant identifier value indicating _no tenant_ is the *empty string*. The combination of (process definition key, process definition version, tenant identifier) needs to be unique (and there is a database constraint checking this). Also note that the tenant identifier shouldn't be set to null, as this will affect the queries since certain databases (Oracle) treat empty string as a null value (that's why the query _.withoutTenantId_ does a check against the empty string or null). This means that the same process definition (with same process definition key) can be deployed for multiple tenants, each with their own versioning. This does not affect the usage when tenancy is not used. - -*Do note that all of the above does not conflict with running multiple Flowable instances in a cluster.* - -[Experimental] It is possible to change the tenant identifier by calling the _changeDeploymentTenantId(String deploymentId, String newTenantId)_ method on the _repositoryService_. This will change the tenant identifier everywhere it was inherited before. This can be useful when going from a non-multitenant setup to a multitenant configuration. See the Javadoc on the method for more detailed information. - -In case you would like to merge two existing tenants, you can use _changeDeploymentTenantId(String deploymentId, String newTenantId, String mergeMode)_. -Those methods are taking care of conflict handling, in case you have the same process definition key and version number. -It allows you to specify the mode by setting _mergeMode_ to one of the following: - -* _MergeMode.AS_NEW_: adds the merged deployment with the most recent version number. This is the most efficient merging version which is not throwing a conflict but will make the merged version the default for all new processes with this definition key. -* _MergeMode.AS_OLD_: will increase the version number for all existing process definition and insert the merged version with the version number _1_. -* _MergeMode.BY_DATE_: will insert the process definition by the deployment date of the deployed apps. This needs to lookup the deployment date, which makes it inefficient. - -It is also possible to implement an own strategy by implementing _DeploymentMergeStrategy_ and using the _changeDeploymentTenantId(String deploymentId, String newTenantId, DeploymentMergeStrategy deploymentMergeStrategy)_ method. - -[[advanced.custom.sql.queries]] - - -=== Execute custom SQL - -The Flowable API allows for interacting with the database using a high level API. For example, for retrieving data the Query API and the Native Query API are powerful in its usage. However, for some use cases they might not be flexible enough. The following section describes how a completely custom SQL statement (select, insert, update and delete are possible) can be executed against the Flowable data store, but completely within the configured Process Engine (and thus levering the transaction setup for example). - -To define custom SQL statements, the Flowable engine leverages the capabilities of its underlying framework, MyBatis. More info can be read link:$$http://mybatis.github.io/mybatis-3/java-api.html$$[in the MyBatis user guide]. - -==== Annotation based Mapped Statements - -The first thing to do when using Annotation based Mapped Statements, is to create a MyBatis mapper class. For example, suppose that for some use case not the whole task data is needed, but only a small subset of it. A Mapper that could do this, looks as follows: - -[source,java,linenums] ----- -public interface MyTestMapper { - - @Select("SELECT ID_ as id, NAME_ as name, CREATE_TIME_ as createTime FROM ACT_RU_TASK") - List> selectTasks(); - -} ----- - - -This mapper must be provided to the Process Engine configuration as follows: - -[source,xml,linenums] ----- -... - - - org.flowable.standalone.cfg.MyTestMapper - - -... ----- - -Notice that this is an interface. The underlying MyBatis framework will make an instance of it that can be used at runtime. Also notice that the return value of the method is not typed, but a list of maps (which corresponds to the list of rows with column values). Typing is possible with the MyBatis mappers if wanted. - -To execute the query above, the _managementService.executeCustomSql_ method must be used. This method takes in a _CustomSqlExecution_ instance. This is a wrapper that hides the internal bits of the engine otherwise needed to make it work. - - -Unfortunately, Java generics make it a bit less readable than it could have been. The two generic types below are the mapper class and the return type class. However, the actual logic is simply to call the mapper method and return its results (if applicable). - -[source,java,linenums] ----- -CustomSqlExecution>> customSqlExecution = - new AbstractCustomSqlExecution>>(MyTestMapper.class) { - - public List> execute(MyTestMapper customMapper) { - return customMapper.selectTasks(); - } - -}; - -List> results = managementService.executeCustomSql(customSqlExecution); ----- - - -The Map entries in the list above will only contain _id, name and create time_ in this case and not the full task object. - -Any SQL is possible when using the approach above. Another more complex example: - -[source,java,linenums] ----- - @Select({ - "SELECT task.ID_ as taskId, variable.LONG_ as variableValue FROM ACT_RU_VARIABLE variable", - "inner join ACT_RU_TASK task on variable.TASK_ID_ = task.ID_", - "where variable.NAME_ = #{variableName}" - }) - List> selectTaskWithSpecificVariable(String variableName); ----- - -Using this method, the task table will be joined with the variables table. Only where the variable has a certain name is retained, and the task id and the corresponding numerical value is returned. - -For a working example on using Annotation based Mapped Statements check the unit test _org.flowable.standalone.cfg.CustomMybatisMapperTest_ and other classes and resources in folders src/test/java/org/flowable/standalone/cfg/ and src/test/resources/org/flowable/standalone/cfg/ - - -==== XML based Mapped Statements - -When using XML based Mapped Statements, statements are defined in XML files. For the use case where not the whole task data is needed, but only a small subset of it. The XML file can look as follows: - -[source,xml,linenums] ----- - - - - - - - - - - - ----- - -Results are mapped to instances of _org.flowable.standalone.cfg.CustomTask_ class which can look as follows: - -[source,java,linenums] ----- -public class CustomTask { - - protected String id; - protected String name; - protected Date createTime; - - public String getId() { - return id; - } - public String getName() { - return name; - } - public Date getCreateTime() { - return createTime; - } -} ----- - -Mapper XML files must be provided to the Process Engine configuration as follows: - -[source,xml,linenums] ----- -... - - - org/flowable/standalone/cfg/custom-mappers/CustomTaskMapper.xml - - -... ----- - -The statement can be executed as follows: -[source,java,linenums] ----- -List tasks = managementService.executeCommand(new Command>() { - - @SuppressWarnings("unchecked") - @Override - public List execute(CommandContext commandContext) { - return (List) CommandContextUtil.getDbSqlSession().selectList("selectCustomTaskList"); - } - }); ----- - -For uses cases that require more complicated statements, XML Mapped Statements can be helpful. Since Flowable uses XML Mapped Statements internally, it's possible to make use of the underlying capabilities. - -Suppose that for some use case the ability to query attachments data is required based on id, name, type, userId, etc! To fulfill the use case a query class _AttachmentQuery_ that extends _org.flowable.engine.impl.AbstractQuery_ can be created as follows: - -[source,java,linenums] ----- -public class AttachmentQuery extends AbstractQuery { - - protected String attachmentId; - protected String attachmentName; - protected String attachmentType; - protected String userId; - - public AttachmentQuery(ManagementService managementService) { - super(managementService); - } - - public AttachmentQuery attachmentId(String attachmentId){ - this.attachmentId = attachmentId; - return this; - } - - public AttachmentQuery attachmentName(String attachmentName){ - this.attachmentName = attachmentName; - return this; - } - - public AttachmentQuery attachmentType(String attachmentType){ - this.attachmentType = attachmentType; - return this; - } - - public AttachmentQuery userId(String userId){ - this.userId = userId; - return this; - } - - @Override - public long executeCount(CommandContext commandContext) { - return (Long) CommandContextUtil.getDbSqlSession() - .selectOne("selectAttachmentCountByQueryCriteria", this); - } - - @Override - public List executeList(CommandContext commandContext, Page page) { - return CommandContextUtil.getDbSqlSession() - .selectList("selectAttachmentByQueryCriteria", this); - } ----- - -Note that when extending _AbstractQuery_ extended classes should pass an instance of _ManagementService_ to super constructor and methods _executeCount_ and _executeList_ need to be implemented to call the mapped statements. - -The XML file containing the mapped statements can look as follows: - -[source,xml,linenums] ----- - - - - - - - - from ${prefix}ACT_HI_ATTACHMENT RES - - - RES.ID_ = #{attachmentId} - - - and RES.NAME_ = #{attachmentName} - - - and RES.TYPE_ = #{attachmentType} - - - and RES.USER_ID_ = #{userId} - - - - ----- - -Capabilities such as pagination, ordering, table name prefixing are available and can be used in the statements (since the parameterType is a subclass of _AbstractQuery_). Note that to map results the predefined _org.flowable.engine.impl.persistence.entity.AttachmentEntity.attachmentResultMap_ resultMap can be used. - -Finally, the _AttachmentQuery_ can be used as follows: - -[source,java,linenums] ----- -.... -// Get the total number of attachments -long count = new AttachmentQuery(managementService).count(); - -// Get attachment with id 10025 -Attachment attachment = new AttachmentQuery(managementService).attachmentId("10025").singleResult(); - -// Get first 10 attachments -List attachments = new AttachmentQuery(managementService).listPage(0, 10); - -// Get all attachments uploaded by user kermit -attachments = new AttachmentQuery(managementService).userId("kermit").list(); -.... ----- - -For working examples on using XML Mapped Statements check the unit test _org.flowable.standalone.cfg.CustomMybatisXMLMapperTest_ and other classes and resources in folders src/test/java/org/flowable/standalone/cfg/ and src/test/resources/org/flowable/standalone/cfg/ - - -[[advanced.process.engine.configurators]] - - -=== Advanced Process Engine configuration with a ProcessEngineConfigurator - -An advanced way of hooking into the process engine configuration is through the use of a _ProcessEngineConfigurator_. The idea is that an implementation of the _org.flowable.engine.cfg.ProcessEngineConfigurator_ interface is created and injected into the process engine configuration: - -[source,xml,linenums] ----- - - - ... - - - - - ... - - - - - ... - - ----- - - -There are two methods required to implement this interface. The _configure_ method, which gets a _ProcessEngineConfiguration_ instance as parameter. The custom configuration can be added this way, and this method will guaranteed be called *before the process engine is created, but after all default configuration has been done*. The other method is the _getPriority_ method, which allows for ordering the configurators in the case where some configurators are dependent on each other. - -An example of such a configurator is the <>, where the configurator is used to replace the default user and group manager classes with one that is capable of handling an LDAP user store. So basically a configurator allows to change or tweak the process engine quite heavily and is meant for very advanced use cases. Another example is to swap the process definition cache with a customized version: - -[source,java,linenums] ----- -public class ProcessDefinitionCacheConfigurator extends AbstractProcessEngineConfigurator { - - public void configure(ProcessEngineConfigurationImpl processEngineConfiguration) { - MyCache myCache = new MyCache(); - processEngineConfiguration.setProcessDefinitionCache(enterpriseProcessDefinitionCache); - } - -} ----- - -Process Engine configurators can also be auto discovered from the classpath using the link:$$http://docs.oracle.com/javase/7/docs/api/java/util/ServiceLoader.html$$[ServiceLoader] approach. This means that a jar with the configurator implementation must be put on the classpath, containing a file in the _META-INF/services_ folder in the jar called *org.flowable.engine.cfg.ProcessEngineConfigurator*. The content of the file needs to be the fully qualified classname of the custom implementation. When the process engine is booted, the logging will show that these configurators are found: - ----- -INFO org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl - Found 1 auto-discoverable Process Engine Configurators -INFO org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl - Found 1 Process Engine Configurators in total: -INFO org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl - class org.flowable.MyCustomConfigurator ----- - -Note that this ServiceLoader approach might not work in certain environments. It can be explicitly disabled using the _enableConfiguratorServiceLoader_ property of the ProcessEngineConfiguration (true by default). - - -[[advanced.task.query.switching]] - - -=== Advanced query API: seamless switching between runtime and historic task querying - - -One core component of any BPM user interface is the task list. Typically, end users work on open, runtime tasks, filtering their inbox with various setting. Often also the historic tasks need to be displayed in those lists, with similar filtering. To make that code-wise easier, the _TaskQuery_ and _HistoricTaskInstanceQuery_ both have a shared parent interface, which contains all common operations (and most of the operations are common). - -This common interface is the _org.flowable.engine.task.TaskInfoQuery_ class. Both _org.flowable.engine.task.Task_ and _org.flowable.engine.task.HistoricTaskInstance_ have a common superclass _org.flowable.engine.task.TaskInfo_ (with common properties) which is returned from e.g. the _list()_ method. However, Java generics are sometimes more harming than helping: if you want to use the _TaskInfoQuery_ type directly, it would look like this: - -[source,java,linenums] ----- -TaskInfoQuery, ? extends TaskInfo> taskInfoQuery ----- - -Ugh, Right. To 'solve' this, a _org.flowable.engine.task.TaskInfoQueryWrapper_ class that can be used to avoid the generics (the following code could come from REST code that returns a task list where the user can switch between open and completed tasks): - -[source,java,linenums] ----- -TaskInfoQueryWrapper taskInfoQueryWrapper = null; -if (runtimeQuery) { - taskInfoQueryWrapper = new TaskInfoQueryWrapper(taskService.createTaskQuery()); -} else { - taskInfoQueryWrapper = new TaskInfoQueryWrapper(historyService.createHistoricTaskInstanceQuery()); -} - -List taskInfos = taskInfoQueryWrapper.getTaskInfoQuery().or() - .taskNameLike("%k1%") - .taskDueAfter(new Date(now.getTime() + (3 * 24L * 60L * 60L * 1000L))) -.endOr() -.list(); ----- - - -[[advanced.custom.session.manager]] - - -=== Custom identity management by overriding standard SessionFactory - -If you do not want to use a full _ProcessEngineConfigurator_ implementation like in the <>, but still want to plug in your custom identity management framework, then you can also override the _IdmIdentityServiceImpl_ class or implement the _IdmIdentityService_ interface directly and use the implemented class for the _idmIdentityService_ property in the _ProcessEngineConfiguration_. In Spring this can be easily done by adding the following to the _ProcessEngineConfiguration_ bean definition: - -[source,xml,linenums] ----- - - - ... - - - - - - ... - - - ----- - -Have a look at the _LDAPIdentityServiceImpl_ class implementation to have a good example of how to implement the methods of the _IdmIdentityService_ interface. -You have to figure out which methods you want to implement in the custom identity service class. For example the following call: - -[source,java,linenums] ----- -long potentialOwners = identityService.createUserQuery().memberOfGroup("management").count(); ----- - -leads to a call on the following member of the _IdmIdentityService_ interface: - -[source,java,linenums] ----- -UserQuery createUserQuery(); ----- - - -The code for the <> contains full examples of how to implement this. Check out the code on Github: link:$$https://github.com/flowable/flowable-engine/blob/master/modules/flowable-ldap/src/main/java/org/flowable/ldap/LDAPIdentityServiceImpl.java$$[LDAPIdentityServiceImpl]. - - -[[advanced.safe.bpmn.xml]] - - -=== Enable safe BPMN 2.0 xml - - -In most cases the BPMN 2.0 processes that are being deployed to the Flowable engine are under tight control of e.g. the development team. However, in some use cases it might be desirable to upload arbitrary BPMN 2.0 xml to the engine. In that case, take into consideration that a user with bad intentions can bring the server down as described link:$$http://www.jorambarrez.be/blog/2013/02/19/uploading-a-funny-xml-can-bring-down-your-server/$$[here]. - -To avoid the attacks described in the link above, a property _enableSafeBpmnXml_ can be set on the process engine configuration: - -[source,xml,linenums] ----- - ----- - -*By default this feature is disabled!* The reason for this is that it relies on the availability of the StaxSource class of the JDK. Unfortunately, on some platforms this class is unavailable (due to older xml parser implementation) and thus the safe BPMN 2.0 xml feature cannot be enabled. - -If the platform on which Flowable runs does support it, do enable this feature. - - -[[advanced.event.logging]] - - -=== Event logging - -An event logging mechanism has been introduced. The logging mechanism builds upon the general-purpose <> and is disabled by default. The idea is that the events originating from the engine are caught, and a map containing all the event data (and some more) is created and provided to an _org.flowable.engine.impl.event.logger.EventFlusher_ which will flush this data to somewhere else. By default, simple database-backed event handlers/flusher is used, which serializes the said map to JSON using Jackson and stores it in the database as an _EventLogEntryEntity_ instance. The table required for this database logging is created by default (called __$$ACT_EVT_LOG$$__). This table can be deleted if the event logging is not used. - -To enable the database logger: - -[source,java,linenums] ----- -processEngineConfigurationImpl.setEnableDatabaseEventLogging(true); ----- - -or at runtime: - -[source,java,linenums] ----- -databaseEventLogger = new EventLogger(processEngineConfiguration.getClock(), - processEngineConfiguration.getObjectMapper()); -runtimeService.addEventListener(databaseEventLogger); ----- - -The EventLogger class can be extended. In particular, the _createEventFlusher()_ method needs to return an instance of the _org.flowable.engine.impl.event.logger.EventFlusher_ interface if the default database logging is not wanted. The _managementService.getEventLogEntries(startLogNr, size);_ can be used to retrieve the _EventLogEntryEntity_ instances through Flowable. - -It is easy to see how this table data can now be used to feed the JSON into a big data NoSQL store such as MongoDB, Elastic Search, etc. It is also easy to see that the classes used here (org.flowable.engine.impl.event.logger.EventLogger/EventFlusher and many EventHandler classes) are pluggable and can be tweaked to your own use case (eg not storing the JSON in the database, but firing it straight onto a queue or big data store). - -Note that this event logging mechanism is additional to the 'traditional' history manager of Flowable. Although all the data is in the database tables, -it is not optimized for querying nor for easy retrieval. The real use case is audit trailing and feeding it into a big data store. - -=== Disabling bulk inserts - -By default, the engine will group multiple insert statements for the same database table together in a _bulk insert_, thus improving performance. This has been tested and implemented for all supported databases. - -However, it could be a specific version of a supported and tested database does not allow bulk inserts (we have for example a report for DB2 on z/OS, although DB2 in general works), the bulk insert can be disabled on the process engine configuration: - -[source,xml,linenums] ----- - ----- - -[[advancedSecureScripting]] -=== Secure Scripting - -By default, when using a <>, the script that is executed has similar capabilities as a Java delegate. It has full access to the JVM, can run forever (due to infinite loops) or use up a lot of memory. However, Java delegates need to be written and put on the classpath in a jar and they have a different life cycle from a process definitions. End-users generally will not write Java delegates, as this is a typical the job of a developer. - -Scripts on the other hand are part of the process definition and its lifecycle is the same. Script tasks don't need the extra step of a jar deployment, but can be executed from the moment the process definition is deployed. Sometimes, scripts for script tasks are not written by developers. Yet, this poses a problem as stated above: a script has full access to the JVM and it is possible to block many system resources when executing the script. Allowing scripts from just about anyone is thus not a good idea. - -To solve this problem, the _secure scripting_ feature can be enabled. Currently, this feature is implemented for _javascript_ scripting only. To enable it, add the _flowable-secure-javascript_ dependency to your project. When using maven: - -[source,xml,linenums] ----- - - org.flowable - flowable-secure-javascript - ${flowable.version} - ----- - -Adding this dependency will transitively bring in the Rhino dependency (see link:$https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rhino$$[https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rhino]). Rhino is a javascript engine for the JDK. It used to be included in JDK version 6 and 7 and was superseded by the Nashorn engine. However, the Rhino project continued development after it was included in the JDK. Many features (including the ones Flowable uses to implement the secure scripting) were added afterwards. At the time of writing, the Nashorn engine *does not* have the features that are needed to implement the secure scripting feature. - -This does mean that there could be (typically small) differences between scripts (for example, _importPackage_ works on Rhino, but _load()_ has to be used on Nashorn). - -Configuring the secure scripting is done through a dedicated _Configurator_ object that is passed to the process engine configuration before the process engine is instantiated: - -[source,java,linenums] ----- -SecureJavascriptConfigurator configurator = new SecureJavascriptConfigurator() - .setWhiteListedClasses(new HashSet(Arrays.asList("java.util.ArrayList"))) - .setMaxStackDepth(10) - .setMaxScriptExecutionTime(3000L) - .setMaxMemoryUsed(3145728L) - .setNrOfInstructionsBeforeStateCheckCallback(10); - -processEngineConfig.addConfigurator(configurator); ----- - -Following settings are possible: - -* *enableClassWhiteListing*: When true, all classes will be blacklisted and all classes that want to be used will need to be whitelisted individually. This gives tight control over what is exposed to scripts. By default _false_. -* *whiteListedClasses*: a Set of Strings corresponding with fully qualified classnames of the classes that are allowed to be used in the script. For example, to expose the _execution_ object in a script, the _org.flowable.engine.impl.persistence.entity.ExecutionEntityImpl_ String needs to be added to this Set. By default _empty_. -* *maxStackDepth*: Limits the stack depth while calling functions within a script. This can be used to avoid stack overflow exceptions that occur when recursively calling a method defined in the script. By default _-1_ (disabled). -* *maxScriptExecutionTime*: The maximum time a script is allowed to run. By default _-1_ (disabled). -* *maxMemoryUsed*: The maximum memory, in bytes, that the script is allowed to use. Note that the script engine itself takes a a certain amount of memory that is counted here too. By default _-1_ (disabled). -* *nrOfInstructionsBeforeStateCheckCallback*: The maximum script execution time and memory usage is implemented using a callback that is called every x instructions of the script. Note that these are not script instructions, but java byte code instructions (which means one script line could be hundreds of byte code instructions). By default 100. - -_Note:_ the _maxMemoryUsed_ setting can only be used by a JVM that supports the com.sun.management.ThreadMXBean#getThreadAllocatedBytes() method. The Oracle JDK has this. - -There is also a secure variant of the ScriptExecutionListener and ScriptTaskListener: _org.flowable.scripting.secure.listener.SecureJavascriptExecutionListener_ and _org.flowable.scripting.secure.listener.SecureJavascriptTaskListener_. - -It's used as follows: - -[source,xml,linenums] ----- - - - - - - - - ----- - -For examples that demonstrate unsecure scripts and how they are made secure by the _secure scripting_ feature, please check the link:$$https://github.com/Flowable/Flowable/tree/master/modules/flowable-secure-javascript/src/test/resources$$[unit tests on Github] diff --git a/docs/userguide/src/zh_CN/bpmn/ch18-tooling.adoc b/docs/userguide/src/zh_CN/bpmn/ch18-tooling.adoc deleted file mode 100755 index 92bb51a4d08..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch18-tooling.adoc +++ /dev/null @@ -1,174 +0,0 @@ -[[Tooling]] -== 工具 - -[[JMX]] - - -=== JMX - -[[jmxIntroduction]] - -==== 介绍 - -可以使用标准Java管理扩展(Java Management Extensions, JMX)技术连接Flowable引擎,查询信息或修改配置。任何符合标准的JMX客户端都可以使用。通过JMX可以完成启用与禁用作业执行器、部署新的流程定义文件或删除流程等操作,而不需要写一行代码。 - -[[jmxQuickStart]] - - -==== 快速开始 - -默认情况下没有启用JMX。用Maven或其他方法将flowable-jmx jar文件加入classpath即可使用默认配置启动JMX。如果使用Maven,可以在pom.xml中添加下列依赖: - -[source,xml,linenums] ----- - - org.flowable - flowable-jmx - latest.version - ----- - -在添加依赖并启动流程引擎后,就可以使用JMX进行连接了。可以使用在标准JDK发行版中提供的jconsole。在本地线程列表中,可以找到运行Flowable的JVM。如果在“本地进程”中没有列出Flowable的JVM,可以尝试使用这个URL从“远程进程”中连接: - ----- -service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi/flowable ----- - -可以在日志文件中找到正确的本地URL。连接成功后,可以看到标准的JVM信息以及MBean。选择MBeans页签,并在右侧面板选择"org.flowable.jmx.Mbeans",查看Flowable的MBean。选择任何MBean,都可以查询相应的信息或修改配置。如下图所示: - -image::images/jmx.jconsole.png[align="center"] - -不只是jconsole,任何JMX客户端都可以访问MBeans。大多数数据中心的监控工具都会提供连接至JMX MBeans的连接器。 - -[[_attributes_and_operations]] -==== 属性与操作 - -下表是目前可用的属性与操作的列表。这个列表可能根据需要在未来版本中扩展。 - -[options="header"] -|=============== -|MBean|类型|名字|描述 -|ProcessDefinitionsMBean|属性|processDefinitions|已部署流程定义的++Id++、++Name++、++Version++、++IsSuspended++等参数,是一个字符串的list -||属性|deployments|当前部署的++Id++、++Name++、++TenantId++参数 -||方法|getProcessDefinitionById(String id)|给定id流程定义的++Id++、++Name++、++Version++与++IsSuspended++参数 -||方法|deleteDeployment(String id)|删除给定++Id++的部署 -||方法|suspendProcessDefinitionById(String id)|暂停给定++Id++的流程定义 -||方法|activatedProcessDefinitionById(String id)|激活给定++Id++的流程定义 -||方法|suspendProcessDefinitionByKey(String id)|暂停给定++key++的流程定义 -||方法|activatedProcessDefinitionByKey(String id)|激活给定++key++的流程定义 -||方法|deployProcessDefinition(String resourceName, String processDefinitionFile)|部署流程定义文件 -|JobExecutorMBean|属性|isJobExecutorActivated|返回作业执行器是否在运行 -||方法|setJobExecutorActivate(Boolean active)|启用或停用作业执行器 - -|=============== - -[[_configuration_3]] -==== 配置 - -JMX默认配置为最常使用的配置,以简化部署。但也可以很容易地以代码或配置文件的方式修改默认配置。下列代码展示了如何修改配置文件: - -[source,xml,linenums] ----- - - ... - - - - - - - - ... - - - - ----- - -下表展示了可配置的参数与其默认值: - -[options="header"] -|=============== -|名字|默认值|描述 -|disabled|false|若值为true,即使已添加依赖也不会启动JMX -|domain|org.flowable.jmx.Mbeans|MBean的域 -|createConnector|true|若值为true,则会创建一个连接器至MbeanServer -|MBeanDomain|DefaultDomain|MBean服务器的域 -|registryPort|1099|注册端口,组成服务URL -|serviceUrlPath|/jmxrmi/flowable|组成服务URL -|connectorPort|-1|如果大于0,则作为连接端口组成服务URL - -|=============== - -[[_jmx_service_url]] -==== JMX服务URL - -JMX服务URL格式如下: - ----- -service:jmx:rmi://:/jndi/rmi://:/ ----- - -++hostName++自动设置为机器的网络名。可以配置++connectorPort++、++registryPort++与++serviceUrlPath++。 - -如果++connectionPort++小于0,则服务URL不包括这部分,简化为: - ----- -service:jmx:rmi:///jndi/rmi://::/ ----- - - -[[mavenArchetypes]] -=== Maven脚手架 - -[[_create_test_case]] -==== 创建测试用例 - -在开发过程中,有时会需要在实际实现前,先构建一个小型的测试用例来测试想法或功能。这样可以用测试来明确目标。JUnit测试用例也是沟通功能需求及报告Bug的推荐工具。在一份bug报告或功能需求jira单中附加一个测试用例,可以显著减少修复所用的时间。 - -用maven脚手架可以快速创建标准测试用例,简化测试用例的创建过程。标准库中应该已经有脚手架了。如果没有,也可以在**tooling/archtypes**目录下键入**mvn install**,轻松安装到本地maven仓库目录中。 - -使用下列命令创建单元测试项目: - -[source] -mvn archetype:generate \ --DarchetypeGroupId=org.flowable \ --DarchetypeArtifactId=flowable-archetype-unittest \ --DarchetypeVersion= \ --DgroupId=org.myGroup \ --DartifactId=myArtifact - -下表介绍每个参数的作用: - -.单元测试脚手架生成参数 -|=== -|行|参数|说明 -|1|archetypeGroupId|脚手架的Group id。需要为**org.flowable** -|2|archetypeArtifactId|脚手架Artifact id。需要为**flowable-archetype-unittest** -|3|archetypeVersion|生成的测试项目中使用的Flowable版本 -|4|groupId|生成的测试项目的Group id -|5|artifactId|生成的测试项目的Artifact id -|=== - -生成的项目的目录结构像是这样: - ----- -. -├── pom.xml -└── src - └── test - ├── java - │   └── org - │   └── myGroup - │   └── MyUnitTest.java - └── resources - ├── flowable.cfg.xml - ├── log4j.properties - └── org - └── myGroup - └── my-process.bpmn20.xml ----- - -可以修改java单元测试用例及相应的流程模型,或者添加新的单元测试用例与流程模型。 -如果用该项目来描述bug或功能,测试用例应该在初始时失败,并在修复了bug或实现了预期的功能以后成功。 -请确保在发送之前键入**mvn clean**清理项目。 diff --git a/docs/userguide/src/zh_CN/bpmn/ch19-tooling.adoc b/docs/userguide/src/zh_CN/bpmn/ch19-tooling.adoc deleted file mode 100644 index 92bb51a4d08..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/ch19-tooling.adoc +++ /dev/null @@ -1,174 +0,0 @@ -[[Tooling]] -== 工具 - -[[JMX]] - - -=== JMX - -[[jmxIntroduction]] - -==== 介绍 - -可以使用标准Java管理扩展(Java Management Extensions, JMX)技术连接Flowable引擎,查询信息或修改配置。任何符合标准的JMX客户端都可以使用。通过JMX可以完成启用与禁用作业执行器、部署新的流程定义文件或删除流程等操作,而不需要写一行代码。 - -[[jmxQuickStart]] - - -==== 快速开始 - -默认情况下没有启用JMX。用Maven或其他方法将flowable-jmx jar文件加入classpath即可使用默认配置启动JMX。如果使用Maven,可以在pom.xml中添加下列依赖: - -[source,xml,linenums] ----- - - org.flowable - flowable-jmx - latest.version - ----- - -在添加依赖并启动流程引擎后,就可以使用JMX进行连接了。可以使用在标准JDK发行版中提供的jconsole。在本地线程列表中,可以找到运行Flowable的JVM。如果在“本地进程”中没有列出Flowable的JVM,可以尝试使用这个URL从“远程进程”中连接: - ----- -service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi/flowable ----- - -可以在日志文件中找到正确的本地URL。连接成功后,可以看到标准的JVM信息以及MBean。选择MBeans页签,并在右侧面板选择"org.flowable.jmx.Mbeans",查看Flowable的MBean。选择任何MBean,都可以查询相应的信息或修改配置。如下图所示: - -image::images/jmx.jconsole.png[align="center"] - -不只是jconsole,任何JMX客户端都可以访问MBeans。大多数数据中心的监控工具都会提供连接至JMX MBeans的连接器。 - -[[_attributes_and_operations]] -==== 属性与操作 - -下表是目前可用的属性与操作的列表。这个列表可能根据需要在未来版本中扩展。 - -[options="header"] -|=============== -|MBean|类型|名字|描述 -|ProcessDefinitionsMBean|属性|processDefinitions|已部署流程定义的++Id++、++Name++、++Version++、++IsSuspended++等参数,是一个字符串的list -||属性|deployments|当前部署的++Id++、++Name++、++TenantId++参数 -||方法|getProcessDefinitionById(String id)|给定id流程定义的++Id++、++Name++、++Version++与++IsSuspended++参数 -||方法|deleteDeployment(String id)|删除给定++Id++的部署 -||方法|suspendProcessDefinitionById(String id)|暂停给定++Id++的流程定义 -||方法|activatedProcessDefinitionById(String id)|激活给定++Id++的流程定义 -||方法|suspendProcessDefinitionByKey(String id)|暂停给定++key++的流程定义 -||方法|activatedProcessDefinitionByKey(String id)|激活给定++key++的流程定义 -||方法|deployProcessDefinition(String resourceName, String processDefinitionFile)|部署流程定义文件 -|JobExecutorMBean|属性|isJobExecutorActivated|返回作业执行器是否在运行 -||方法|setJobExecutorActivate(Boolean active)|启用或停用作业执行器 - -|=============== - -[[_configuration_3]] -==== 配置 - -JMX默认配置为最常使用的配置,以简化部署。但也可以很容易地以代码或配置文件的方式修改默认配置。下列代码展示了如何修改配置文件: - -[source,xml,linenums] ----- - - ... - - - - - - - - ... - - - - ----- - -下表展示了可配置的参数与其默认值: - -[options="header"] -|=============== -|名字|默认值|描述 -|disabled|false|若值为true,即使已添加依赖也不会启动JMX -|domain|org.flowable.jmx.Mbeans|MBean的域 -|createConnector|true|若值为true,则会创建一个连接器至MbeanServer -|MBeanDomain|DefaultDomain|MBean服务器的域 -|registryPort|1099|注册端口,组成服务URL -|serviceUrlPath|/jmxrmi/flowable|组成服务URL -|connectorPort|-1|如果大于0,则作为连接端口组成服务URL - -|=============== - -[[_jmx_service_url]] -==== JMX服务URL - -JMX服务URL格式如下: - ----- -service:jmx:rmi://:/jndi/rmi://:/ ----- - -++hostName++自动设置为机器的网络名。可以配置++connectorPort++、++registryPort++与++serviceUrlPath++。 - -如果++connectionPort++小于0,则服务URL不包括这部分,简化为: - ----- -service:jmx:rmi:///jndi/rmi://::/ ----- - - -[[mavenArchetypes]] -=== Maven脚手架 - -[[_create_test_case]] -==== 创建测试用例 - -在开发过程中,有时会需要在实际实现前,先构建一个小型的测试用例来测试想法或功能。这样可以用测试来明确目标。JUnit测试用例也是沟通功能需求及报告Bug的推荐工具。在一份bug报告或功能需求jira单中附加一个测试用例,可以显著减少修复所用的时间。 - -用maven脚手架可以快速创建标准测试用例,简化测试用例的创建过程。标准库中应该已经有脚手架了。如果没有,也可以在**tooling/archtypes**目录下键入**mvn install**,轻松安装到本地maven仓库目录中。 - -使用下列命令创建单元测试项目: - -[source] -mvn archetype:generate \ --DarchetypeGroupId=org.flowable \ --DarchetypeArtifactId=flowable-archetype-unittest \ --DarchetypeVersion= \ --DgroupId=org.myGroup \ --DartifactId=myArtifact - -下表介绍每个参数的作用: - -.单元测试脚手架生成参数 -|=== -|行|参数|说明 -|1|archetypeGroupId|脚手架的Group id。需要为**org.flowable** -|2|archetypeArtifactId|脚手架Artifact id。需要为**flowable-archetype-unittest** -|3|archetypeVersion|生成的测试项目中使用的Flowable版本 -|4|groupId|生成的测试项目的Group id -|5|artifactId|生成的测试项目的Artifact id -|=== - -生成的项目的目录结构像是这样: - ----- -. -├── pom.xml -└── src - └── test - ├── java - │   └── org - │   └── myGroup - │   └── MyUnitTest.java - └── resources - ├── flowable.cfg.xml - ├── log4j.properties - └── org - └── myGroup - └── my-process.bpmn20.xml ----- - -可以修改java单元测试用例及相应的流程模型,或者添加新的单元测试用例与流程模型。 -如果用该项目来描述bug或功能,测试用例应该在初始时失败,并在修复了bug或实现了预期的功能以后成功。 -请确保在发送之前键入**mvn clean**清理项目。 diff --git a/docs/userguide/src/zh_CN/bpmn/generate-html.sh b/docs/userguide/src/zh_CN/bpmn/generate-html.sh deleted file mode 100755 index f06cc32bf82..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/generate-html.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -asciidoctor -a stylesheet=../base/flowable.css -o output/index.html index-html.adoc -asciidoctor -a stylesheet=../base/flowable.css -o output/migration.html migration.adoc - -rm -rf output/images -mkdir output/images -cp -r images output - -## Copy Base Images -cp -r ../base/images output/ \ No newline at end of file diff --git a/docs/userguide/src/zh_CN/bpmn/generate-pdf.sh b/docs/userguide/src/zh_CN/bpmn/generate-pdf.sh deleted file mode 100755 index e32fd3d4354..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/generate-pdf.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -rm -rf output/activiti-userguide.pdf -asciidoctor-pdf -r asciidoctor-pdf-cjk-kai_gen_gothic -a pdf-style=KaiGenGothicCN -o output/activiti-userguide.pdf index-pdf.adoc diff --git a/docs/userguide/src/zh_CN/bpmn/images/FinancialReportProcess.bpmn20.xml b/docs/userguide/src/zh_CN/bpmn/images/FinancialReportProcess.bpmn20.xml deleted file mode 100755 index cb523eec355..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/images/FinancialReportProcess.bpmn20.xml +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - - - - - Write monthly financial report for publication to shareholders. - - - - accountancy - - - - - - - - - Verify monthly financial report composed by the accountancy department. - This financial report is going to be sent to all the company shareholders. - - - - management - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/userguide/src/zh_CN/bpmn/images/api.services.png b/docs/userguide/src/zh_CN/bpmn/images/api.services.png deleted file mode 100755 index 7086ac4817d..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/api.services.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/api.test.debug.breakpoint.png b/docs/userguide/src/zh_CN/bpmn/images/api.test.debug.breakpoint.png deleted file mode 100755 index b6760c034c4..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/api.test.debug.breakpoint.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/api.test.debug.h2.login.png b/docs/userguide/src/zh_CN/bpmn/images/api.test.debug.h2.login.png deleted file mode 100755 index d404e8fb015..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/api.test.debug.h2.login.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/api.test.debug.h2.tables.png b/docs/userguide/src/zh_CN/bpmn/images/api.test.debug.h2.tables.png deleted file mode 100755 index 84d6fd3b731..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/api.test.debug.h2.tables.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/api.test.debug.start.h2.server.2.png b/docs/userguide/src/zh_CN/bpmn/images/api.test.debug.start.h2.server.2.png deleted file mode 100755 index 08c6405f3d3..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/api.test.debug.start.h2.server.2.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/api.test.debug.start.h2.server.png b/docs/userguide/src/zh_CN/bpmn/images/api.test.debug.start.h2.server.png deleted file mode 100755 index 590252c4721..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/api.test.debug.start.h2.server.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/api.test.debug.view.png b/docs/userguide/src/zh_CN/bpmn/images/api.test.debug.view.png deleted file mode 100755 index fb82601df4e..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/api.test.debug.view.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/api.transient.variable.example.png b/docs/userguide/src/zh_CN/bpmn/images/api.transient.variable.example.png deleted file mode 100755 index d9034292640..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/api.transient.variable.example.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/async.example.async.PNG b/docs/userguide/src/zh_CN/bpmn/images/async.example.async.PNG deleted file mode 100755 index c936e791ad4..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/async.example.async.PNG and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/async.example.no.async.PNG b/docs/userguide/src/zh_CN/bpmn/images/async.example.no.async.PNG deleted file mode 100755 index 8c823a2d453..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/async.example.no.async.PNG and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/blockquote-arrow.png b/docs/userguide/src/zh_CN/bpmn/images/blockquote-arrow.png deleted file mode 100755 index ff47ab182ab..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/blockquote-arrow.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.boundary.cancel.event.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.boundary.cancel.event.png deleted file mode 100755 index 0c51fb5ba74..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.boundary.cancel.event.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.boundary.compensation.event.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.boundary.compensation.event.png deleted file mode 100755 index 74bc423ec5f..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.boundary.compensation.event.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.boundary.error.event.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.boundary.error.event.png deleted file mode 100755 index 8d0d4b5ea04..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.boundary.error.event.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.boundary.error.example.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.boundary.error.example.png deleted file mode 100755 index 6026dd245d5..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.boundary.error.example.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.boundary.message.event.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.boundary.message.event.png deleted file mode 100755 index 4a942a35636..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.boundary.message.event.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.boundary.signal.event.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.boundary.signal.event.png deleted file mode 100755 index 8cc8a91cbe2..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.boundary.signal.event.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.boundary.timer.event.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.boundary.timer.event.png deleted file mode 100755 index 38fd37ef2fd..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.boundary.timer.event.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.business.rule.task.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.business.rule.task.png deleted file mode 100755 index 30476e4addf..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.business.rule.task.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.call.activity.async.complete.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.call.activity.async.complete.png deleted file mode 100644 index 0e2dd59c4ca..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.call.activity.async.complete.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.call.activity.sub.process.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.call.activity.sub.process.png deleted file mode 100755 index bbaab49a465..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.call.activity.sub.process.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.call.activity.super.process.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.call.activity.super.process.png deleted file mode 100755 index 37f36fdf9bc..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.call.activity.super.process.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.cancel.end.event.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.cancel.end.event.png deleted file mode 100755 index 0fbc8d603aa..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.cancel.end.event.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.clock.start.event.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.clock.start.event.png deleted file mode 100755 index cff9765882e..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.clock.start.event.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.collapsed.call.activity.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.collapsed.call.activity.png deleted file mode 100755 index 3af3de92bdb..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.collapsed.call.activity.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.collapsed.subprocess.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.collapsed.subprocess.png deleted file mode 100755 index 42ca89f35c9..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.collapsed.subprocess.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.conditional.sequence.flow.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.conditional.sequence.flow.png deleted file mode 100755 index 79ba1da37c6..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.conditional.sequence.flow.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.default.sequence.flow.example.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.default.sequence.flow.example.png deleted file mode 100755 index 7e0fecd7178..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.default.sequence.flow.example.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.default.sequence.flow.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.default.sequence.flow.png deleted file mode 100755 index ce705a0ec8f..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.default.sequence.flow.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.error.end.event.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.error.end.event.png deleted file mode 100755 index 1aeb9006269..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.error.end.event.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.event.based.gateway.example.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.event.based.gateway.example.png deleted file mode 100755 index 61a498416ec..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.event.based.gateway.example.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.event.based.gateway.notation.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.event.based.gateway.notation.png deleted file mode 100755 index 4825d5caba1..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.event.based.gateway.notation.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.exclusive.gateway.notation.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.exclusive.gateway.notation.png deleted file mode 100755 index 52e9e2c9e94..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.exclusive.gateway.notation.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.exclusive.gateway.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.exclusive.gateway.png deleted file mode 100755 index 441c254b4bf..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.exclusive.gateway.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.expanded.subprocess.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.expanded.subprocess.png deleted file mode 100755 index 68cc4fab087..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.expanded.subprocess.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.financial.report.example.claim.task.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.financial.report.example.claim.task.png deleted file mode 100755 index 687c5c2aaa2..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.financial.report.example.claim.task.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.financial.report.example.process.ended.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.financial.report.example.process.ended.png deleted file mode 100755 index 1abb28689d3..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.financial.report.example.process.ended.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.financial.report.example.start.process.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.financial.report.example.start.process.png deleted file mode 100755 index 7d75f4c21e6..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.financial.report.example.start.process.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.financial.report.example.task.assigned.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.financial.report.example.task.assigned.png deleted file mode 100755 index 602aa8f9b0e..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.financial.report.example.task.assigned.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.gateway.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.gateway.png deleted file mode 100755 index cfc8a973b1b..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.gateway.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.inclusive.gateway.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.inclusive.gateway.png deleted file mode 100755 index 1c7e613effa..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.inclusive.gateway.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.intermediate.compensation.throw.event.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.intermediate.compensation.throw.event.png deleted file mode 100755 index 1077034a83b..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.intermediate.compensation.throw.event.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.intermediate.message.catch.event.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.intermediate.message.catch.event.png deleted file mode 100755 index 61d0e4e5682..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.intermediate.message.catch.event.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.intermediate.none.event.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.intermediate.none.event.png deleted file mode 100755 index b0618062734..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.intermediate.none.event.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.intermediate.signal.catch.event.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.intermediate.signal.catch.event.png deleted file mode 100755 index 95088412d68..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.intermediate.signal.catch.event.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.intermediate.signal.throw.event.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.intermediate.signal.throw.event.png deleted file mode 100755 index 6f3c9e1cebc..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.intermediate.signal.throw.event.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.intermediate.timer.event.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.intermediate.timer.event.png deleted file mode 100755 index a6794c0a907..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.intermediate.timer.event.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.java.service.task.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.java.service.task.png deleted file mode 100755 index 423f51c1d84..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.java.service.task.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.known.issue.boundary.event.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.known.issue.boundary.event.png deleted file mode 100755 index 1532ad9180a..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.known.issue.boundary.event.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.manual.task.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.manual.task.png deleted file mode 100755 index c940e3c5ca7..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.manual.task.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.multi.instance.boundary.event.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.multi.instance.boundary.event.png deleted file mode 100755 index 45ce89f8a72..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.multi.instance.boundary.event.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.multi.instance.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.multi.instance.png deleted file mode 100755 index 0a561abed01..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.multi.instance.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.non.interrupting.boundary.timer.event.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.non.interrupting.boundary.timer.event.png deleted file mode 100755 index 2ac5855a6bf..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.non.interrupting.boundary.timer.event.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.none.end.event.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.none.end.event.png deleted file mode 100755 index 5097e85c6dd..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.none.end.event.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.none.start.event.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.none.start.event.png deleted file mode 100755 index 72878e24365..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.none.start.event.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.parallel.gateway.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.parallel.gateway.png deleted file mode 100755 index e048be1312a..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.parallel.gateway.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.receive.task.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.receive.task.png deleted file mode 100755 index 4c7737cd373..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.receive.task.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.scripttask.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.scripttask.png deleted file mode 100755 index 8c4d3970055..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.scripttask.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.sequence.flow.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.sequence.flow.png deleted file mode 100755 index 43e6266617c..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.sequence.flow.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.signal.event.catch.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.signal.event.catch.png deleted file mode 100755 index f56b82354ca..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.signal.event.catch.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.signal.event.throw.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.signal.event.throw.png deleted file mode 100755 index 63914e3b571..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.signal.event.throw.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.signal.event.warning.1.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.signal.event.warning.1.png deleted file mode 100755 index 8e4c8e42130..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.signal.event.warning.1.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.start.error.event.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.start.error.event.png deleted file mode 100755 index a8f98b7f180..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.start.error.event.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.start.message.event.example.1.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.start.message.event.example.1.png deleted file mode 100755 index 9d37522d35c..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.start.message.event.example.1.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.start.message.event.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.start.message.event.png deleted file mode 100755 index 4ef63dea053..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.start.message.event.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.start.signal.event.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.start.signal.event.png deleted file mode 100755 index 94fe466cb86..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.start.signal.event.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.subprocess.eventSubprocess.example.1.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.subprocess.eventSubprocess.example.1.png deleted file mode 100755 index 3d028149305..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.subprocess.eventSubprocess.example.1.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.subprocess.eventSubprocess.example.2a.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.subprocess.eventSubprocess.example.2a.png deleted file mode 100755 index 30bba1fee29..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.subprocess.eventSubprocess.example.2a.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.subprocess.eventSubprocess.example.2b.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.subprocess.eventSubprocess.example.2b.png deleted file mode 100755 index b51fd2e533e..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.subprocess.eventSubprocess.example.2b.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.subprocess.eventSubprocess.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.subprocess.eventSubprocess.png deleted file mode 100755 index 08f663c45ea..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.subprocess.eventSubprocess.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.subprocess.with.boundary.timer.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.subprocess.with.boundary.timer.png deleted file mode 100755 index 382f17ea450..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.subprocess.with.boundary.timer.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.terminate.end.event.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.terminate.end.event.png deleted file mode 100755 index b69b4b7a63d..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.terminate.end.event.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.throw.compensation.example1.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.throw.compensation.example1.png deleted file mode 100755 index 96e76649d45..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.throw.compensation.example1.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.transaction.subprocess.example.1.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.transaction.subprocess.example.1.png deleted file mode 100755 index 50dc8833b29..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.transaction.subprocess.example.1.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.transaction.subprocess.example.2.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.transaction.subprocess.example.2.png deleted file mode 100755 index 6b98cd3f5ea..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.transaction.subprocess.example.2.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.transaction.subprocess.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.transaction.subprocess.png deleted file mode 100755 index bddb306d4e0..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.transaction.subprocess.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.uel-expression.on.seq.flow.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.uel-expression.on.seq.flow.png deleted file mode 100755 index db4f77584f9..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.uel-expression.on.seq.flow.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.unbalanced.parallel.gateway.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.unbalanced.parallel.gateway.png deleted file mode 100755 index be8d102db10..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.unbalanced.parallel.gateway.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.user.task.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.user.task.png deleted file mode 100755 index f44cf8ccd06..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.user.task.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.web.service.task.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.web.service.task.png deleted file mode 100755 index 2b14a39d787..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.web.service.task.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/bpmn.why.exclusive.jobs.png b/docs/userguide/src/zh_CN/bpmn/images/bpmn.why.exclusive.jobs.png deleted file mode 100755 index d9c42298cd8..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/bpmn.why.exclusive.jobs.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/custom.identityLinkType.example.png b/docs/userguide/src/zh_CN/bpmn/images/custom.identityLinkType.example.png deleted file mode 100755 index 7cb363cd9cd..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/custom.identityLinkType.example.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/deployment.explorer.2.png b/docs/userguide/src/zh_CN/bpmn/images/deployment.explorer.2.png deleted file mode 100755 index 8ca0464d764..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/deployment.explorer.2.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/deployment.explorer.png b/docs/userguide/src/zh_CN/bpmn/images/deployment.explorer.png deleted file mode 100755 index 33a46e77057..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/deployment.explorer.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/deployment.image.generation.png b/docs/userguide/src/zh_CN/bpmn/images/deployment.image.generation.png deleted file mode 100755 index 758f57d4a08..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/deployment.image.generation.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.add.update.site.png b/docs/userguide/src/zh_CN/bpmn/images/designer.add.update.site.png deleted file mode 100755 index cb92298d114..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.add.update.site.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.bpmn.file.png b/docs/userguide/src/zh_CN/bpmn/images/designer.bpmn.file.png deleted file mode 100755 index d7967c5d866..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.bpmn.file.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.create.deployment.png b/docs/userguide/src/zh_CN/bpmn/images/designer.create.deployment.png deleted file mode 100755 index 8502b35c256..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.create.deployment.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.create.flowable.project.png b/docs/userguide/src/zh_CN/bpmn/images/designer.create.flowable.project.png deleted file mode 100755 index 9c41b32b536..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.create.flowable.project.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.deployment.dir.png b/docs/userguide/src/zh_CN/bpmn/images/designer.deployment.dir.png deleted file mode 100755 index 5ccd4decaa6..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.deployment.dir.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.embeddedprocess.canvas.png b/docs/userguide/src/zh_CN/bpmn/images/designer.embeddedprocess.canvas.png deleted file mode 100755 index add64535f6c..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.embeddedprocess.canvas.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.listener.configuration.png b/docs/userguide/src/zh_CN/bpmn/images/designer.listener.configuration.png deleted file mode 100755 index bbf4e2f7598..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.listener.configuration.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.mailtask.property.png b/docs/userguide/src/zh_CN/bpmn/images/designer.mailtask.property.png deleted file mode 100755 index 87165a57c00..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.mailtask.property.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.model.eventsubprocess.png b/docs/userguide/src/zh_CN/bpmn/images/designer.model.eventsubprocess.png deleted file mode 100755 index 4d639facedd..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.model.eventsubprocess.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.model.labels.png b/docs/userguide/src/zh_CN/bpmn/images/designer.model.labels.png deleted file mode 100755 index 56f5aa281fb..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.model.labels.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.model.poolandlanes.png b/docs/userguide/src/zh_CN/bpmn/images/designer.model.poolandlanes.png deleted file mode 100755 index 8829ff284d3..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.model.poolandlanes.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.model.process.png b/docs/userguide/src/zh_CN/bpmn/images/designer.model.process.png deleted file mode 100755 index 41ef3fdefeb..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.model.process.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.model.quick.change.png b/docs/userguide/src/zh_CN/bpmn/images/designer.model.quick.change.png deleted file mode 100755 index eb85fae8efa..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.model.quick.change.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.model.quick.new.png b/docs/userguide/src/zh_CN/bpmn/images/designer.model.quick.new.png deleted file mode 100755 index 005e845f82f..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.model.quick.new.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.multipage.editor.png b/docs/userguide/src/zh_CN/bpmn/images/designer.multipage.editor.png deleted file mode 100755 index e904a2ab240..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.multipage.editor.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.open.importedfile.png b/docs/userguide/src/zh_CN/bpmn/images/designer.open.importedfile.png deleted file mode 100755 index 99088c3f506..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.open.importedfile.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.palette.add.money.help.png b/docs/userguide/src/zh_CN/bpmn/images/designer.palette.add.money.help.png deleted file mode 100755 index 649e23799e7..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.palette.add.money.help.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.palette.add.money.png b/docs/userguide/src/zh_CN/bpmn/images/designer.palette.add.money.png deleted file mode 100755 index f31fa9388fd..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.palette.add.money.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.palette.add.money.properties.required.png b/docs/userguide/src/zh_CN/bpmn/images/designer.palette.add.money.properties.required.png deleted file mode 100755 index f91221114ac..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.palette.add.money.properties.required.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.palette.disable.all.png b/docs/userguide/src/zh_CN/bpmn/images/designer.palette.disable.all.png deleted file mode 100755 index 090d09f8883..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.palette.disable.all.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.palette.disable.manual.and.script.png b/docs/userguide/src/zh_CN/bpmn/images/designer.palette.disable.manual.and.script.png deleted file mode 100755 index bc73cae96b1..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.palette.disable.manual.and.script.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.preferences.userlibraries.flowable.empty.png b/docs/userguide/src/zh_CN/bpmn/images/designer.preferences.userlibraries.flowable.empty.png deleted file mode 100755 index 2ee50b28b37..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.preferences.userlibraries.flowable.empty.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.preferences.userlibraries.flowable.moneytasks.png b/docs/userguide/src/zh_CN/bpmn/images/designer.preferences.userlibraries.flowable.moneytasks.png deleted file mode 100755 index e43513a2b1c..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.preferences.userlibraries.flowable.moneytasks.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.preferences.userlibraries.png b/docs/userguide/src/zh_CN/bpmn/images/designer.preferences.userlibraries.png deleted file mode 100755 index 416ce1c832d..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.preferences.userlibraries.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.problem.view.png b/docs/userguide/src/zh_CN/bpmn/images/designer.problem.view.png deleted file mode 100755 index ea5431f176f..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.problem.view.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.project.maven.png b/docs/userguide/src/zh_CN/bpmn/images/designer.project.maven.png deleted file mode 100755 index 7672edb3d72..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.project.maven.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.property.boolean.choice.png b/docs/userguide/src/zh_CN/bpmn/images/designer.property.boolean.choice.png deleted file mode 100755 index 43925b5ef5b..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.property.boolean.choice.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.property.combobox.choice.invalid.png b/docs/userguide/src/zh_CN/bpmn/images/designer.property.combobox.choice.invalid.png deleted file mode 100755 index 1c1323ecb75..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.property.combobox.choice.invalid.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.property.combobox.choice.png b/docs/userguide/src/zh_CN/bpmn/images/designer.property.combobox.choice.png deleted file mode 100755 index 25fcdb4d1b4..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.property.combobox.choice.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.property.datagrid.png b/docs/userguide/src/zh_CN/bpmn/images/designer.property.datagrid.png deleted file mode 100755 index 5abafe594e0..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.property.datagrid.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.property.date.picker.png b/docs/userguide/src/zh_CN/bpmn/images/designer.property.date.picker.png deleted file mode 100755 index 8ea5b3f0472..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.property.date.picker.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.property.multiline.text.invalid.png b/docs/userguide/src/zh_CN/bpmn/images/designer.property.multiline.text.invalid.png deleted file mode 100755 index d095b3f014c..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.property.multiline.text.invalid.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.property.multiline.text.png b/docs/userguide/src/zh_CN/bpmn/images/designer.property.multiline.text.png deleted file mode 100755 index 7491117b174..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.property.multiline.text.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.property.period.invalid.png b/docs/userguide/src/zh_CN/bpmn/images/designer.property.period.invalid.png deleted file mode 100755 index 59f238f7cba..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.property.period.invalid.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.property.period.png b/docs/userguide/src/zh_CN/bpmn/images/designer.property.period.png deleted file mode 100755 index 7789ed92203..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.property.period.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.property.radio.choice.invalid.png b/docs/userguide/src/zh_CN/bpmn/images/designer.property.radio.choice.invalid.png deleted file mode 100755 index 340a509a2e5..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.property.radio.choice.invalid.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.property.radio.choice.png b/docs/userguide/src/zh_CN/bpmn/images/designer.property.radio.choice.png deleted file mode 100755 index a4a272915ca..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.property.radio.choice.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.property.text.invalid.png b/docs/userguide/src/zh_CN/bpmn/images/designer.property.text.invalid.png deleted file mode 100755 index 185ed4bcd94..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.property.text.invalid.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.property.text.png b/docs/userguide/src/zh_CN/bpmn/images/designer.property.text.png deleted file mode 100755 index 29a2ba9ccea..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.property.text.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.sequence.condition.png b/docs/userguide/src/zh_CN/bpmn/images/designer.sequence.condition.png deleted file mode 100755 index 570d70cdd8c..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.sequence.condition.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.servicetask.property.png b/docs/userguide/src/zh_CN/bpmn/images/designer.servicetask.property.png deleted file mode 100755 index cddc4550382..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.servicetask.property.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.timerboundary.canvas.png b/docs/userguide/src/zh_CN/bpmn/images/designer.timerboundary.canvas.png deleted file mode 100755 index 8806b3f686a..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.timerboundary.canvas.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.unittest.generate.png b/docs/userguide/src/zh_CN/bpmn/images/designer.unittest.generate.png deleted file mode 100755 index 4bd38acf141..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.unittest.generate.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.userlibraries.project.png b/docs/userguide/src/zh_CN/bpmn/images/designer.userlibraries.project.png deleted file mode 100755 index 3a316b7714d..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.userlibraries.project.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/designer.xml.contentassist.png b/docs/userguide/src/zh_CN/bpmn/images/designer.xml.contentassist.png deleted file mode 100755 index 4fe3bee4b68..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/designer.xml.contentassist.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/eclipse.setup.xml.catalog.png b/docs/userguide/src/zh_CN/bpmn/images/eclipse.setup.xml.catalog.png deleted file mode 100755 index 2e6e836aea9..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/eclipse.setup.xml.catalog.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/eclipsesetup.import.existing.projects.png b/docs/userguide/src/zh_CN/bpmn/images/eclipsesetup.import.existing.projects.png deleted file mode 100755 index 2ea6abf8d0e..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/eclipsesetup.import.existing.projects.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/eclipsesetup.import.png b/docs/userguide/src/zh_CN/bpmn/images/eclipsesetup.import.png deleted file mode 100755 index f8e0874b265..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/eclipsesetup.import.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/eclipsesetup.select.directory.png b/docs/userguide/src/zh_CN/bpmn/images/eclipsesetup.select.directory.png deleted file mode 100755 index 843d89d3ebf..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/eclipsesetup.select.directory.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/email.task.result.png b/docs/userguide/src/zh_CN/bpmn/images/email.task.result.png deleted file mode 100755 index 5ad57c685a8..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/email.task.result.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/explorer.case.overview.png b/docs/userguide/src/zh_CN/bpmn/images/explorer.case.overview.png deleted file mode 100755 index 4c0e273dfc1..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/explorer.case.overview.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/explorer.database.png b/docs/userguide/src/zh_CN/bpmn/images/explorer.database.png deleted file mode 100755 index a67aff643e3..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/explorer.database.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/explorer.deployments.png b/docs/userguide/src/zh_CN/bpmn/images/explorer.deployments.png deleted file mode 100755 index cdc825c5aa1..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/explorer.deployments.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/explorer.jobs.png b/docs/userguide/src/zh_CN/bpmn/images/explorer.jobs.png deleted file mode 100755 index 8ae99975351..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/explorer.jobs.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/explorer.my.instances.png b/docs/userguide/src/zh_CN/bpmn/images/explorer.my.instances.png deleted file mode 100755 index 9de7bb17864..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/explorer.my.instances.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/explorer.process.definition.image.png b/docs/userguide/src/zh_CN/bpmn/images/explorer.process.definition.image.png deleted file mode 100755 index bd73a4ea854..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/explorer.process.definition.image.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/explorer.process.definitions.png b/docs/userguide/src/zh_CN/bpmn/images/explorer.process.definitions.png deleted file mode 100755 index 0fe0f6cc8ed..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/explorer.process.definitions.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/explorer.report.example.png b/docs/userguide/src/zh_CN/bpmn/images/explorer.report.example.png deleted file mode 100755 index 35e5f439672..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/explorer.report.example.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/explorer.reporting.explained.png b/docs/userguide/src/zh_CN/bpmn/images/explorer.reporting.explained.png deleted file mode 100755 index 1791a2d592e..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/explorer.reporting.explained.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/explorer.reporting.png b/docs/userguide/src/zh_CN/bpmn/images/explorer.reporting.png deleted file mode 100755 index 03c8461d14e..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/explorer.reporting.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/explorer.reporting.start.form.png b/docs/userguide/src/zh_CN/bpmn/images/explorer.reporting.start.form.png deleted file mode 100755 index 6b235d70a87..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/explorer.reporting.start.form.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/explorer.tabs.png b/docs/userguide/src/zh_CN/bpmn/images/explorer.tabs.png deleted file mode 100755 index 1117c5bf535..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/explorer.tabs.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/explorer.tasks.png b/docs/userguide/src/zh_CN/bpmn/images/explorer.tasks.png deleted file mode 100755 index ceb08214120..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/explorer.tasks.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/explorer.upload.deployment.png b/docs/userguide/src/zh_CN/bpmn/images/explorer.upload.deployment.png deleted file mode 100755 index f056a4294a2..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/explorer.upload.deployment.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/explorer.users.png b/docs/userguide/src/zh_CN/bpmn/images/explorer.users.png deleted file mode 100755 index 24aa7db78da..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/explorer.users.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/financial.report.example.diagram.png b/docs/userguide/src/zh_CN/bpmn/images/financial.report.example.diagram.png deleted file mode 100755 index eb73e3e60f6..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/financial.report.example.diagram.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_admin_configuration_screen.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_admin_configuration_screen.png deleted file mode 100755 index cb4c2f72d07..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_admin_configuration_screen.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_admin_deploymentdetails_screen.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_admin_deploymentdetails_screen.png deleted file mode 100755 index 6ecd6c041f1..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_admin_deploymentdetails_screen.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_admin_deployments_screen.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_admin_deployments_screen.png deleted file mode 100755 index af0bcdd6359..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_admin_deployments_screen.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_admin_processdefinitiondetails_screen.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_admin_processdefinitiondetails_screen.png deleted file mode 100755 index ea42a14b7f0..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_admin_processdefinitiondetails_screen.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_idm_login_screen.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_idm_login_screen.png deleted file mode 100755 index 490a4af1306..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_idm_login_screen.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_idm_privilege_screen.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_idm_privilege_screen.png deleted file mode 100755 index 4bf0f72c28d..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_idm_privilege_screen.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_idm_startup_screen.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_idm_startup_screen.png deleted file mode 100755 index ec7e7fcf5ea..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_idm_startup_screen.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_appdetails_screen.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_appdetails_screen.png deleted file mode 100755 index 24f5c09bda2..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_appdetails_screen.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_appeditor_screen.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_appeditor_screen.png deleted file mode 100755 index 3accf2a3eb7..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_appeditor_screen.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_createmodel_popup.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_createmodel_popup.png deleted file mode 100755 index c512d0b4ba8..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_createmodel_popup.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_design_screen.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_design_screen.png deleted file mode 100755 index c6450db70f5..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_design_screen.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_dmneditor_screen.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_dmneditor_screen.png deleted file mode 100755 index 8ca012d49ca..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_dmneditor_screen.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_editfield_popup.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_editfield_popup.png deleted file mode 100755 index 43dfad83584..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_editfield_popup.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_formdesign_screen.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_formdesign_screen.png deleted file mode 100755 index 6ba417736c4..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_formdesign_screen.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_formoverview_screen.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_formoverview_screen.png deleted file mode 100755 index ea745e19d43..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_formoverview_screen.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_modelselection_popup.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_modelselection_popup.png deleted file mode 100755 index 5fe0ee81b32..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_modelselection_popup.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_script_popup.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_script_popup.png deleted file mode 100755 index ac3dd451526..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_script_popup.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_sequenceflowcondition_popup.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_sequenceflowcondition_popup.png deleted file mode 100755 index 8cd9f135cd3..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_sequenceflowcondition_popup.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_startup_screen.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_startup_screen.png deleted file mode 100755 index 9402fa97e27..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_startup_screen.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_vacationrequest_screen.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_vacationrequest_screen.png deleted file mode 100755 index 51b85628356..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_modeler_vacationrequest_screen.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_task_completedform_screen.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_task_completedform_screen.png deleted file mode 100755 index 11acaf35075..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_task_completedform_screen.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_task_dashboard_screen.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_task_dashboard_screen.png deleted file mode 100755 index f8d0f8667fe..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_task_dashboard_screen.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_task_processdetails_screen.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_task_processdetails_screen.png deleted file mode 100755 index b44f08a78e5..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_task_processdetails_screen.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_task_processhistory_screen.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_task_processhistory_screen.png deleted file mode 100755 index adc84fca588..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_task_processhistory_screen.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_task_taskdetails_screen.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_task_taskdetails_screen.png deleted file mode 100755 index 6c2f509fb87..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_task_taskdetails_screen.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_task_taskfilter_screen.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_task_taskfilter_screen.png deleted file mode 100755 index 2435ea93e95..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_task_taskfilter_screen.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/flowable_task_tasklist_screen.png b/docs/userguide/src/zh_CN/bpmn/images/flowable_task_tasklist_screen.png deleted file mode 100755 index 74f48c0f351..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/flowable_task_tasklist_screen.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/forms.explorer.png b/docs/userguide/src/zh_CN/bpmn/images/forms.explorer.png deleted file mode 100755 index 43879dfed38..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/forms.explorer.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/getting.started.bpmn.process.png b/docs/userguide/src/zh_CN/bpmn/images/getting.started.bpmn.process.png deleted file mode 100755 index 40cdd455541..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/getting.started.bpmn.process.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/getting.started.console.logging.png b/docs/userguide/src/zh_CN/bpmn/images/getting.started.console.logging.png deleted file mode 100755 index 047b1b6288b..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/getting.started.console.logging.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/getting.started.console.logging2.png b/docs/userguide/src/zh_CN/bpmn/images/getting.started.console.logging2.png deleted file mode 100755 index df42a079f4f..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/getting.started.console.logging2.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/getting.started.console.logging3.png b/docs/userguide/src/zh_CN/bpmn/images/getting.started.console.logging3.png deleted file mode 100755 index 97db1583454..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/getting.started.console.logging3.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/getting.started.console.logging4.png b/docs/userguide/src/zh_CN/bpmn/images/getting.started.console.logging4.png deleted file mode 100755 index 74edd295743..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/getting.started.console.logging4.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/getting.started.new.maven.png b/docs/userguide/src/zh_CN/bpmn/images/getting.started.new.maven.png deleted file mode 100755 index 3c405b6c567..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/getting.started.new.maven.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/getting.started.new.maven2.png b/docs/userguide/src/zh_CN/bpmn/images/getting.started.new.maven2.png deleted file mode 100755 index c690629962a..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/getting.started.new.maven2.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/getting.started.new.maven3.png b/docs/userguide/src/zh_CN/bpmn/images/getting.started.new.maven3.png deleted file mode 100755 index 6a3750d49c3..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/getting.started.new.maven3.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/getting.started.run.main.png b/docs/userguide/src/zh_CN/bpmn/images/getting.started.run.main.png deleted file mode 100755 index 9df32dc391f..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/getting.started.run.main.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/h2.console.login.png b/docs/userguide/src/zh_CN/bpmn/images/h2.console.login.png deleted file mode 100755 index d8258446d46..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/h2.console.login.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/jmx.jconsole.png b/docs/userguide/src/zh_CN/bpmn/images/jmx.jconsole.png deleted file mode 100755 index 182d54366b9..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/jmx.jconsole.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/jpa.spring.example.process.png b/docs/userguide/src/zh_CN/bpmn/images/jpa.spring.example.process.png deleted file mode 100755 index 8f825a364bc..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/jpa.spring.example.process.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/kickstart.bpmn20.xml.png b/docs/userguide/src/zh_CN/bpmn/images/kickstart.bpmn20.xml.png deleted file mode 100755 index 8941fcec3ab..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/kickstart.bpmn20.xml.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/kickstart.capture.initiator.png b/docs/userguide/src/zh_CN/bpmn/images/kickstart.capture.initiator.png deleted file mode 100755 index 9cd3ddbf775..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/kickstart.capture.initiator.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/kickstart.create.process.png b/docs/userguide/src/zh_CN/bpmn/images/kickstart.create.process.png deleted file mode 100755 index 917b62d9a30..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/kickstart.create.process.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/kickstart.diagram.png b/docs/userguide/src/zh_CN/bpmn/images/kickstart.diagram.png deleted file mode 100755 index ff3b1f98db4..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/kickstart.diagram.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/kickstart.enhance.png b/docs/userguide/src/zh_CN/bpmn/images/kickstart.enhance.png deleted file mode 100755 index d322cd23869..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/kickstart.enhance.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/kickstart.form.in.explorer.png b/docs/userguide/src/zh_CN/bpmn/images/kickstart.form.in.explorer.png deleted file mode 100755 index fd5c1f43aa0..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/kickstart.form.in.explorer.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/kickstart.form.png b/docs/userguide/src/zh_CN/bpmn/images/kickstart.form.png deleted file mode 100755 index 8e0b5a3eaf3..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/kickstart.form.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/kickstart.process.in.explorer.png b/docs/userguide/src/zh_CN/bpmn/images/kickstart.process.in.explorer.png deleted file mode 100755 index 9846326006b..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/kickstart.process.in.explorer.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/kickstart.reference.form.properties.png b/docs/userguide/src/zh_CN/bpmn/images/kickstart.reference.form.properties.png deleted file mode 100755 index 48fc9bc59c3..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/kickstart.reference.form.properties.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/migration.ant.convert.processes.png b/docs/userguide/src/zh_CN/bpmn/images/migration.ant.convert.processes.png deleted file mode 100755 index 7d5138ed469..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/migration.ant.convert.processes.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/migration.code.overview.png b/docs/userguide/src/zh_CN/bpmn/images/migration.code.overview.png deleted file mode 100755 index daac481059d..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/migration.code.overview.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/migration.process.conversion.completed.png b/docs/userguide/src/zh_CN/bpmn/images/migration.process.conversion.completed.png deleted file mode 100755 index 7cc68a0d2d8..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/migration.process.conversion.completed.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/migration.processes.location.png b/docs/userguide/src/zh_CN/bpmn/images/migration.processes.location.png deleted file mode 100755 index 9f5df5ddce7..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/migration.processes.location.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/migration.zip.contents.png b/docs/userguide/src/zh_CN/bpmn/images/migration.zip.contents.png deleted file mode 100755 index cecafa6ea67..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/migration.zip.contents.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/modeler.convert.png b/docs/userguide/src/zh_CN/bpmn/images/modeler.convert.png deleted file mode 100755 index 466e6ea6f3f..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/modeler.convert.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/modeler.deploy.png b/docs/userguide/src/zh_CN/bpmn/images/modeler.deploy.png deleted file mode 100755 index 467ace3e8a0..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/modeler.deploy.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/modeler.editor.canvas.png b/docs/userguide/src/zh_CN/bpmn/images/modeler.editor.canvas.png deleted file mode 100755 index d4ceb607a4d..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/modeler.editor.canvas.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/modeler.example.process.png b/docs/userguide/src/zh_CN/bpmn/images/modeler.example.process.png deleted file mode 100755 index f2914d7ecf5..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/modeler.example.process.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/modeler.export.png b/docs/userguide/src/zh_CN/bpmn/images/modeler.export.png deleted file mode 100755 index c885461448c..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/modeler.export.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/modeler.import.png b/docs/userguide/src/zh_CN/bpmn/images/modeler.import.png deleted file mode 100755 index 23dea05a7c6..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/modeler.import.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/new.bpmn.procdef.png b/docs/userguide/src/zh_CN/bpmn/images/new.bpmn.procdef.png deleted file mode 100755 index 5e5dd703e19..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/new.bpmn.procdef.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/org.activiti.designer.integration-0.6.0.jar b/docs/userguide/src/zh_CN/bpmn/images/org.activiti.designer.integration-0.6.0.jar deleted file mode 100755 index 80b90d092e9..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/org.activiti.designer.integration-0.6.0.jar and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/taskform.example.png b/docs/userguide/src/zh_CN/bpmn/images/taskform.example.png deleted file mode 100755 index 09667fe5105..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/taskform.example.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/taskform.vacation.request.adjust.form.png b/docs/userguide/src/zh_CN/bpmn/images/taskform.vacation.request.adjust.form.png deleted file mode 100755 index c9e2d212880..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/taskform.vacation.request.adjust.form.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/taskform.vacation.request.approve.form.png b/docs/userguide/src/zh_CN/bpmn/images/taskform.vacation.request.approve.form.png deleted file mode 100755 index a0ed326d8b1..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/taskform.vacation.request.approve.form.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/taskform.vacation.request.management.group.png b/docs/userguide/src/zh_CN/bpmn/images/taskform.vacation.request.management.group.png deleted file mode 100755 index 909b539dff7..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/taskform.vacation.request.management.group.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/images/taskform.vacation.request.model.png b/docs/userguide/src/zh_CN/bpmn/images/taskform.vacation.request.model.png deleted file mode 100755 index d4115e9d5fd..00000000000 Binary files a/docs/userguide/src/zh_CN/bpmn/images/taskform.vacation.request.model.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/bpmn/index-common.adoc b/docs/userguide/src/zh_CN/bpmn/index-common.adoc deleted file mode 100755 index eb0e39b8ed2..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/index-common.adoc +++ /dev/null @@ -1,49 +0,0 @@ -[[_introduction]] -== 简介 - -include::../base/header-Introduction.adoc[] - -include::ch02-GettingStarted.adoc[] - -include::ch03-Configuration.adoc[] - -include::ch04-API.adoc[] - -include::ch05-Spring.adoc[] - -include::ch05a-Spring-Boot.adoc[] - -include::ch06-Deployment.adoc[] - -include::ch07a-BPMN-Introduction.adoc[] - -include::ch07b-BPMN-Constructs.adoc[] - -include::ch08-Forms.adoc[] - -include::ch09-JPA.adoc[] - -include::ch10-History.adoc[] - -include::ch11-IDM.adoc[] - -include::ch12-Designer.adoc[] - -include::ch13-UI.adoc[] - - -[[restApiChapter]] - -== REST API - -include::../base/header-REST.adoc[] - -include::ch15-REST.adoc[] - -include::ch16-Cdi.adoc[] - -include::ch16-Ldap.adoc[] - -include::ch17-Advanced.adoc[] - -include::ch18-tooling.adoc[] diff --git a/docs/userguide/src/zh_CN/bpmn/index-html.adoc b/docs/userguide/src/zh_CN/bpmn/index-html.adoc deleted file mode 100755 index 13f4ad816a0..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/index-html.adoc +++ /dev/null @@ -1,19 +0,0 @@ -= Flowable BPMN 用户手册 (v 6.5.0.event-SNAPSHOT) -:doctype: book -:docinfodir: ../base -:docinfo1: header -:icons: font -:numbered: -:source-highlighter: pygments -:pygments-css: class -:pygments-linenums-mode: table -:compat-mode: -:pdf-page-size: A4 -:nofooter: -:github-tag: master -:github-code: https://github.com/flowable/flowable-engine/tree/{github-tag} -:sc-flowable-starter: {github-code}/modules/flowable-spring-boot/flowable-spring-boot-starters -:sc-flowable-boot: {sc-flowable-starter}/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot -:sc-flowable-ui-admin: {github-code}/modules/flowable-ui-admin - -include::index-common.adoc[] diff --git a/docs/userguide/src/zh_CN/bpmn/index-pdf.adoc b/docs/userguide/src/zh_CN/bpmn/index-pdf.adoc deleted file mode 100755 index c54d77967a9..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/index-pdf.adoc +++ /dev/null @@ -1,19 +0,0 @@ -= Flowable BPMN 用户手册 (v 6.5.0.event-SNAPSHOT) -:doctype: book -:toc: left -:toclevels: 4 -:icons: font -:numbered: -:source-highlighter: pygments -:pygments-css: class -:pygments-linenums-mode: table -:compat-mode: -:pdf-page-size: A4 -:nofooter: -:github-tag: master -:github-code: https://github.com/flowable/flowable-engine/tree/{github-tag} -:sc-flowable-starter: {github-code}/modules/flowable-spring-boot/flowable-spring-boot-starters -:sc-flowable-boot: {sc-flowable-starter}/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot -:sc-flowable-ui-admin: {github-code}/modules/flowable-ui-admin - -include::index-common.adoc[] diff --git a/docs/userguide/src/zh_CN/bpmn/migration.adoc b/docs/userguide/src/zh_CN/bpmn/migration.adoc deleted file mode 100755 index e0aaeef16f4..00000000000 --- a/docs/userguide/src/zh_CN/bpmn/migration.adoc +++ /dev/null @@ -1,206 +0,0 @@ -= Flowable迁移指导:Flowable V5到Flowable V6 -:doctype: book -:docinfo1: header -:icons: font -:numbered: -:source-highlighter: pygments -:pygments-css: class -:pygments-linenums-mode: table -:compat-mode: -:nofooter: - -== 简介 - -本手册介绍了从Flowable V5.x迁移至Flowable V6时需要注意的事项。 - -== 设计目标 - -V6版本的设计目标是: - -* 完全向前兼容V5版本:数据库层面、概念层面以及代码层面。 -* 重写核心引擎:直接执行BPMN 2.0(不再转换为中间模型)。 -* 更简洁干净的运行时执行数据结构,重点关注结构的可预判性。 -* 解耦持久层,以支持未来的不同实现。 - - -== 数据库迁移 - -从V5至V6不需要数据库迁移:V5与V6的数据库表结构基本一致,只是多了一些表与列。所有Flowable V5生成的数据都可以保留在数据库中,甚至包括活动的、执行中的流程实例。在V6引擎第一次运行时,会对表结构进行自动升级(同V5版本中一样)。除了一些小的数据库结构改动外,主要的改动是将作业表分拆为作业表、定时器作业表、暂停作业表与死信作业表。还未到期的定时器作业将移至新的定时器作业表;用尽重试次数的作业将移至死信作业表;已暂停流程实例的作业将移至暂停作业表。 - -== 概念变化 - -称为Flowable V6的主要原因是完全重写了核心引擎。核心引擎执行的方式已经完全变化,将直接执行BPMN(在V5中使用的是中间模型)。同时,运行时执行的表现形式(__执行树__)也作了修改。总的来说,这些概念都大幅简化了,让执行更简单清晰,也让撰写自定义代码更容易更易懂。在V6中内嵌了一个V5引擎,在需要时可以保证完全的兼容性。 - -我们将在之后的文章中详细介绍引擎内部的工作。 - -== 破坏性改动 - -下列改动是破坏性改动(也就是说很可能导致编译错误)。 - -=== 包重命名:org.activiti重命名为org.flowable - -所有org.activiti包都已重命名为org.flowable。 - -=== Activiti类重命名 - -所有类名中包含的"Activiti"都已重命名,替换为Flowable。 -例如,ActivitiEvent重命名为FlowableEvent,而ActivitiException重命名为FlowableException。 - -=== activiti.cfg.xml重命名为flowable.cfg.xml - -在Flowable引擎启动时读取的默认配置文件,已经从activiti.cfg.xml重命名为flowable.cfg.xml。 -对于默认的Spring配置文件activiti-context.xml也是一样,已经重命名为flowable-context.xml. - - -=== PVM类 - -以前在org.activiti.engine.impl.pvm包(及其子包)下的所有类都已移除。这是因为__PVM__ (流程虚拟机 Process Virtual Machine)模型已被替换为一个更简单更轻量的模型。 - -这意味着__ActivitiImpl__、__ProcessDefinitionImpl__、__ExecutionImpl__及__TransitionImpl__都将失效。 - -在V5中这些类大多用于获取流程定义中包含的信息。在V6中,所有流程定义的信息都可以通过__BpmnModel__获取。这是一个BPMN 2.0 XML流程定义的Java表现形式(并对特定操作及搜索进行了增强)。 - -获取__BpmnModel__流程定义最快捷的方法是使用org.flowable.engine.RepositoryService服务: - ----- -BpmnModel bpmnModel = repositoryService.getBpmnModel(myProcessDefinitionId); ----- - -使用org.flowable.engine.impl.context.Context类获取__RepositoryService__,JavaDelegate或ActivityBehavior实现类: - ----- -RepositoryService repositoryService = Context.getProcessEngineConfiguration().getRepositoryService(); ----- - -(请注意只有在上下文可用时才能如此操作,获取JavaDelegate和ActivityBehavior时也是这样) - - -=== DelegateExecution代替ActivityExecution - -我们移除了ActivityExecution,并使用DelegateExecution类代替它。 - -所有ActivityExecution类中的方法都已复制到DelegateExecution类中。 - - -=== 移除EngineServices - -移除了DelegateExecution中的getEngineServices方法,因为它已经没有实际作用,并导致在Flowable 6与内嵌的Flowable 5引擎中,DelegateExecution的使用不一致。 - -将所有对getEngineServices方法的调用,替换为对org.flowable.engine.impl.context.Context.getProcessEngineConfiguration方法的调用。 - - -=== 作业、定时器、暂停与死信作业 - -Flowable V5中只有一个作业表,导致查询需要执行的作业时,查询条件异常复杂。 - -在Flowable V6中,作业被分拆成了作业表(ACT_RU_JOB)、定时器表(ACT_RU_TIMER_JOB)、暂停表(ACT_RU_SUSPENDED_JOB)与死信表(ACT_RU_DEADLETTER_JOB)。 - -* 作业表中的作业可以直接执行(类似异步作业与到期的定时器作业)。因此就不需要使用复杂的查询,唯一的where条件是lock time(锁定时间)不能为NULL。 -* 定时器作业现在持久化在专门的定时器作业表中,并由一个线程检查到期需要执行的定时器作业。当定时器作业到期需要执行时,该作业会被移至作业表。 -* 当作业执行器线程准备执行作业时,会从作业表获取并执行。 -* 当流程定义或流程实例暂停时,其关联的作业将被移至单独的暂停作业表。这简化了作业执行器的查询,并清楚显示了暂停中的作业。 -* 如果一个作业执行失败,它将被放入定时器作业表,并用 当前时间+引擎配置的作业失败等待时间 作为到期日期。在该作业到期将被执行时,会重新移至作业表,并被执行。如果重试次数减至0,则该作业将被移至死信表,不再自动执行。这样简化了默认的作业执行器查询,也清楚显示了卡住需要人工干预的作业。 - -Flowable V6内嵌的Flowable V5引擎也能够使用这4个作业表。但是只会有一个线程池从数据库中获取作业,这个线程池在两个引擎间共享。当获取到一个作业后,会基于流程定义id检查引擎的版本,以判断作业由Flowable V6还是嵌入的Flowable V5引擎执行。 - -=== 向一个执行发信号 - -在V5中,使用像是__runtimeService.signal(executionI);__这样的方法__向一个执行发信号__十分令人困惑。因为__信号(signal)__是一个BPMN 2.0概念和特性,它们的概念互相冲突。 - -在V6中,__signal()__方法更名为__trigger()__。 - -同时,用于实现可以被外部触发的行为的接口__SignalableActivityBehavior__,改名为__TriggerableActivityBehavior__。 - -=== 受检异常 - -在V5中,__JavaDelegate__与__FlowableBehavior__之类的代理类在其签名中标示抛出__Exception__。像其他现代框架一样,在V6版本中已经不再使用受检异常。 - -=== 代理类 - -__org.flowable.engine.impl.pvm.delegate.ActivityBehavior__的包变更为__org.flowable.engine.impl.delegate__。 - -从__DelegateExecution__中移除了下列方法: - -* end() -* createdExecution() - -而用ExecutionEntityManager的方法代替。可以通过Context.getCommandContext.getExecutionEntityManager()获取ExecutionEntityManager。 - -=== 实体管理器 - -在Flowable V5中,所有的实体管理器类(负责持久化,也包含一些逻辑)都没有接口。在V6中,所有的实体类都已经重命名为__Impl__后缀,并提供了不带后缀的接口。也就是说V5的实体管理器类名现在是相应的接口名。 - -所有的实体管理器接口都扩展了org.flowable.engine.impl.persistence.entity.EntityManager泛型接口。所有的实现类都实现了__AbstractEntityManager__泛型接口。 - -同时,为了保证一致性: - -* UserIdentityManager接口重命名为UserEntityManager -* GroupIdentityManager接口重命名为GroupEntityManager - - -=== 持久化对象重命名为实体 - -__org.flowable.engine.impl.db.PersistentObject__类重命名为__Entity__,与其他类保持一致(实体管理器类等等)。 - -所有使用“持久化对象”的相关类也都已经重构为“实体”。 - - -=== 身份逻辑与表的分离 - -在V5中,身份逻辑及表示流程引擎的必要部分。在V6中,这部分逻辑已经重构为独立的模块,名为__flowable-idm-engine__(其中IDM代表“身份管理(identity management)”)。相关的数据库表由这个引擎管理。为了保证兼容性,在启动流程引擎时,也会默认启用IDM引擎。可以在流程引擎配置中,将__disableIdmEngine__设置为__true__以禁用IDM引擎。如果禁用了IDM,就不会创建身份数据库表(以__ACT_ID__开头)。如果这些表已经存在,也可以删除。 - - -=== Camel端点改名为flowable - -在使用Flowable Camel模块时,请确保使用flowable端点替代activiti端点。下面的Route作为简单的例子: - -[source,java,linenums] ----- -public class SimpleCamelCallRoute extends RouteBuilder { - - @Override - public void configure() throws Exception { - from("flowable:SimpleCamelCallProcess:simpleCall").to("log:org.flowable.camel.examples.SimpleCamelCall"); - } -} ----- - -== V5兼容性 - -在迁移至Flowable V6时(基本上就是替换classpath中的JAR包),所有当前的部署与流程定义都将__标记__为__V5版本__的工件。在很多地方(完成一个任务,启动一个新流程实例,指派任务等等)引擎都会检查相关的流程定义是否__标记为V5版本__。若是,则将其执行代理至__内嵌的微型V5引擎__。 - -也就是说为了简化迁移,可以选择逐步替换:首先在__V5模式__下运行当前的流程定义,直到已经验证并测试其行为与V6版本相同。 - -默认情况下,嵌入的V5引擎是__禁用的__!要启用它,在引擎配置中添加下列配置: - ----- - ----- - -**并且**在classpath中添加**flowable5-compatibility**(手动或通过Maven之类的依赖管理机制)。 - -如果默认的实现__org.flowable.compatibility.DefaultFlowable5CompatibilityHandler__不满足要求,也可以创建自定义的实现。可以将引擎配置中的__flowable5CompatibilityHandlerFactory__参数设置为所创建类的全限定类名。这个工厂类构造用于处理V5与V6桥接的类实例。 - -要让一个V5流程定义使用V6引擎运行,只需要重新部署它即可。新的流程实例将会在__V6模式__下运行,而之前的流程实例仍然在__V5模式__下运行。 - -如果出于某些原因,希望部署的新版流程定义仍然在__V5模式__下运行,可以使用下列代码: - ----- -repositoryService.createDeployment() - .addClasspathResource("xyz") - .deploymentProperty(DeploymentProperties.DEPLOY_AS_FLOWABLE5_PROCESS_DEFINITION, Boolean.TRUE) - .deploy(); ----- - -如果使用Flowable Spring模块,要使用Flowable V5兼容模式需要进行额外配置: - ----- - - - -.... - - ----- - -**并且**在classpath中添加**flowable5-spring**与**flowable5-spring-compatibility** JAR包(手动或通过Maven之类的依赖管理机制)。 diff --git a/docs/userguide/src/zh_CN/cmmn/ch01-Introduction.adoc b/docs/userguide/src/zh_CN/cmmn/ch01-Introduction.adoc deleted file mode 100755 index 61dbfeddc1b..00000000000 --- a/docs/userguide/src/zh_CN/cmmn/ch01-Introduction.adoc +++ /dev/null @@ -1,26 +0,0 @@ - -== 说明 -[[license]] -=== 许可证 -Flowable在链接下发布:http://www.apache.org/licenses/LICENSE-2.0.html[Apache V2许可证] -[[download]] -=== 下载 -下载url:http://www.flowable.org/downloads.html -[[sources]] -=== 来源 -(发行版包含了大部分作为JAR文件的源文件。Flowable的源代码可以在以下链接中找到url:https://github.com/flowable/flowable-engine) -[[experimental]] -=== 实验特性 -标有*[EXPERIMENTAL]*的章节介绍不应认为是稳定的 -所有具有.impl的类,在包名中是内部实现类,不能以任何方式被认为是稳定的或有保证的。但是,如果用户指南将任何类提到为配置值,则支持它们,并且可以认为它们是稳定的。 -[[required.software]] -=== 安装必需的软件 -运行Flowable需要JDK 8或以上版本。可以访问 Oracle Java SE downloads页面url:http://www.oracle.com/technetwork/java/javase/downloads/index.html。该页面上也有安装指导。安装完成后,可以执行 java -version 。能看到JDK的版本信息就说明安装成功了。 - -[[reporting.problems]] -=== 报告问题 - -问题和评论可以在链接上讨论url:https://forum.flowable.org。问题可以在链接中创建url:https://github.com/flowable/flowengine/issue [我们的Github问题跟踪器]。 -[[internal]] -=== 内部实现类 -在JAR文件中,包中的所有类都有.impl.在它们里面是实现类,应该被认为是内部的。对于实现类中的类或接口,没有提供稳定性保证。 \ No newline at end of file diff --git a/docs/userguide/src/zh_CN/cmmn/ch02-Configuration.adoc b/docs/userguide/src/zh_CN/cmmn/ch02-Configuration.adoc deleted file mode 100755 index 94c85b99cfd..00000000000 --- a/docs/userguide/src/zh_CN/cmmn/ch02-Configuration.adoc +++ /dev/null @@ -1,356 +0,0 @@ - -== 配置 - -[[configuration]] - -=== 创建CmmnEngine -Flowable CMMN引擎通过名为+flowable.cmmn.cfg.xml+的XML文件进行配置。 请注意,如果您使用的是“springintegration,构建流程引擎的Spring样式”,则这不适用*。 - - -获得CmmnEngine的最简单方法是使用org.flowable.cmmn.engine.CmmnEngineConfiguration类: -[source,java,linenums] ----- -CmmnEngine cmmnEngine = CmmnEngineConfiguration.createStandaloneCmmnEngineConfiguration(); ----- - -这将在类路径上查找flowable.cmmn.cfg.xml文件,并根据该文件中的配置构造引擎。 以下代码段显示了示例配置。 以下部分将详细介绍配置属性。 - -[source,xml,linenums] ----- - - - - - - - - - - - - - ----- - -请注意,配置XML实际上是一个Spring配置。 这并不意味着Flowable只能在Spring环境中使用!我们只是在内部利用Spring的解析和依赖注入功能来构建引擎。 - -也可以使用配置文件以编程方式创建CmmnEngineConfiguration对象。 也可以使用不同的bean id(例如,参见第3行)。 - -[source,java,linenums] ----- -CmmnEngineConfiguration. - createCmmnEngineConfigurationFromResourceDefault(); - createCmmnEngineConfigurationFromResource(String resource); - createCmmnEngineConfigurationFromResource(String resource, String beanName); - createCmmnEngineConfigurationFromInputStream(InputStream inputStream); - createCmmnEngineConfigurationFromInputStream(InputStream inputStream, String beanName); ----- - -也可以不使用配置文件,并基于创建配置默认值(有关更多信息,请参阅<< configurationClasses,不同支持的类>>)。 - -[source,java,linenums] ----- -CmmnEngineConfiguration.createStandaloneCmmnEngineConfiguration(); -CmmnEngineConfiguration.createStandaloneInMemCmmnEngineConfiguration(); ----- - -所有这些CmmnEngineConfiguration.createXXX()方法返回CmmnEngineConfiguration,如果需要可以进一步调整。 调用buildCmmnEngine()操作后,创建一个 CmmnEngine: - -[source,java,linenums] ----- -CmmnEngine cmmnEngine = CmmnEngineConfiguration.createStandaloneInMemCmmnEngineConfiguration() - .setDatabaseSchemaUpdate(CmmnEngineConfiguration.DB_SCHEMA_UPDATE_TRUE) - .setJdbcUrl("jdbc:h2:mem:my-own-db;DB_CLOSE_DELAY=1000") - .buildCmmnEngine(); ----- - - - -[[configurationRoot]] - - -=== CmmnEngineConfiguration bean - -flowable.cmmn.cfg.xml必须包含一个具有id值为'cmmnEngineConfiguration'的bean。 - -[source,xml,linenums] ----- - ----- -然后使用该bean构造CmmnEngine 。 - - -* *org.flowable.cmmn.engine.impl.cfg.StandaloneInMemCmmnEngineConfiguration*: this is a convenience class for unit testing purposes. Flowable will take care of all transactions. An H2 in-memory database is used by default. The database will be created and dropped when the engine boots and shuts down. When using this, no additional configuration is probably needed. -* *org.flowable.cmmn.spring.SpringCmmnEngineConfiguration*: To be used when the CMMN engine is used in a Spring environment. See <> for more information. - - -[[databaseConfiguration]] - -=== 数据源配置 - - -有两种方法可以配置Flowable CMMN引擎将使用的数据库。 第一个选项是定义数据库的JDBC属性: -* *jdbcUrl*: 数据库的JDBC URL. -* *jdbcDriver*: 为特定数据库类型实现驱动程序. -* *jdbcUsername*: 用于连接数据库的用户名. -* *jdbcPassword*: 用于连接数据库的密码. - -基于提供的JDBC属性构造的数据源将具有默认链接:$$ http://www.mybatis.org/$$ [MyBatis]连接池设置。 可以选择设置以下属性来调整该连接池(取自MyBatis文档): - -* *jdbcMaxActiveConnections*: 连接池中处于被使用状态的连接的最大值。默认为10。 -* *jdbcMaxIdleConnections*: 连接池中处于空闲状态的连接的最大值。 -* *jdbcMaxCheckoutTime*: 连接被取出使用的最长时间,超过时间会被强制回收。 默认为20000(20秒)。 -* *jdbcMaxWaitTime*:这是一个底层配置,让连接池可以在长时间无法获得连接时, 打印一条日志,并重新尝试获取一个连接。(避免因为错误配置导致沉默的操作失败)。 默认为20000(20秒)。 -示例数据库配置: - - -[source,xml,linenums] ----- - - - - ----- - -我们的基准测试表明,在处理大量并发请求时,MyBatis连接池可能扛不住。 因此,我们建议使用javax.sql.DataSource实现并将其注入流程引擎配置(例如HikariCP,Tomcat JDBC连接池等): - -[source,xml,linenums] ----- - - - - - - - - - - - - ... - ----- - - -请注意,Flowable 表单不附带允许您定义此类数据源的库。 所以你必须确保库在你的类路径上。 - -无论您使用的是JDBC还是数据源方法,都可以设置以下属性: - -* *databaseType*: 数据库类型,可以是如下的值(h2, mysql, oracle, postgres, mssql, db2). -* *databaseSchemaUpdate*:允许您设置策略以在表单引擎启动和关闭时如何处理数据库表. -** +false+ (default): 在创建表单引擎时检查库模式的版本,如果版本不匹配则抛出异常. -** ++true++: 在构建表单引擎时,执行检查并在必要时执行模式的更新。 如果schema不存在,则创建它. -** ++create-drop++: 在创建表单引擎时创建schema,并在关闭流程引擎时删除schema. - -[[jndiDatasourceConfig]] - -=== JNDI方式数据源配置 - - -默认情况下,Flowable Form的数据库配置包含在每个Web应用程序的WEB-INF/classes中的db.properties文件中。 这并不总是理想的,因为它 -要求用户修改Flowable源中的db.properties并重新编译WAR文件,或者在每次部署时分解WAR并修改db.properties。 -通过使用JNDI(Java命名和目录接口)获取数据库连接,连接完全由Servlet容器管理,并且可以在WAR部署之外管理配置。 这也允许对db.properties文件提供的连接参数进行更多控制。 - -[[jndi_configuration]] - -==== 配置 - -JNDI数据源的配置将根据您使用的servlet容器应用程序而有所不同。 以下说明适用于Tomcat,但对于其他容器应用程序,请参阅容器应用程序的文档。 - -如果使用Tomcat,则在$CATALINA_BASE/conf/[enginename]/[hostname]/[warname].xml中配置JNDI资源(对于Flowable UI,这通常是$CATALINA_BASE/conf/Catalina/localhost/flowable-app。XML)。 首次部署应用程序时,将从Flowable WAR文件复制默认上下文,因此如果已存在,则需要替换它。 例如,要更改JNDI资源以便应用程序连接到MySQL而不是H2,请将文件更改为以下内容: - -[source,xml,linenums] ----- - - - - ----- - -==== JNDI 属性 - -要配置JNDI数据源,请在Flowable UI的属性文件中使用以下属性: - -* spring.datasource.jndi-name=: 数据源的JNDI名称. -* datasource.jndi.resourceRef: 设置查询是否发生在J2EE容器中,换句话说,如果JNDI名称尚未包含它,则需要添加前缀“java:comp/env/”。 默认为“true”. - - -[[supporteddatabases]] - -=== 支持的数据库厂商 - -下面列出了Flowable用于引用数据库的类型(区分大小写!)。ses. - -[[databaseTypes]] -[options="header"] -|=============== -|数据库类型|连接URL|Notes -|h2|jdbc:h2:tcp://localhost/flowable_form|Default configured database -|mysql|jdbc:mysql://localhost:3306/flowable_form?autoReconnect=true|Tested using mysql-connector-java database driver -|oracle|jdbc:oracle:thin:@localhost:1521:xe| -|postgres|jdbc:postgresql://localhost:5432/flowable_form| -|db2|jdbc:db2://localhost:50000/flowable_form| -|mssql|jdbc:sqlserver://localhost:1433;databaseName=flowable_form (jdbc.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver) _OR_ jdbc:jtds:sqlserver://localhost:1433/flowable_form (jdbc.driver=net.sourceforge.jtds.jdbc.Driver)|Tested using Microsoft JDBC Driver 4.0 (sqljdbc4.jar) and JTDS Driver -|=============== - - -[[creatingDatabaseTable]] - -=== 创建表 - -为数据库创建数据库表的最简单方法是: - - - -* 在classpath中添加flowable-cmmn-engine JARS包 -* 添加合适的数据库驱动 -* 将Flowable配置文件(flowable.cmmn.cfg.xml)添加到类路径中,指向您的数据库(请参阅<< databaseConfiguration,数据库配置部分>>) -* 执行DbSchemaCreate类的main方法 - -但是,通常只有数据库管理员才能在数据库上执行DDL语句。 在生产系统中,这也是最明智的选择。 可以在Flowable下载页面或Flowable分发文件夹内的database 子目录中找到SQL DDL语句。 这些脚本也在引擎JAR(flowable-cmmn-engine-x.jar)中,在包org/ flowable/cmmn/db /create中。 SQL文件的形式 - ----- -flowable.{db}.cmmn.create.sql ----- - -其中__db__是<< supporteddatabases,supported databases >>中的任何一个。 -[[database.tables.explained]] - - -=== 数据库表名称解释 -Flowable CMMN Engine的数据库名称均以* ACT_CMMN_ *开头。 - - -* *ACT_CMMN_**: 没有附加前缀的表包含“static”信息,例如案例定义和案例资源(图像,规则等)。 -* *ACT_CMMN_RU_**: 'RU'代表+运行时+。 这些是包含案例实例,计划项目等的运行时数据的运行时表。 Flowable仅在案例实例执行期间存储运行时数据,并在案例实例结束时删除记录。 这使运行时表保持小而快。 -* *ACT_CMMN_HI_**:'HI'代表历史。 这些是包含历史数据的表,例如过去的案例实例,计划项等。 - - -[[databaseUpgrade]] - - -=== 数据库升级 - -在运行升级之前,请确保备份数据库(使用数据库备份功能)。 - - -默认情况下,每次创建流程引擎时都会执行版本检查。 这通常在应用程序或Flowable Web应用程序的引导时发生一次。 如果Flowable库注意到库版本与Flowable数据库表的版本之间的差异,则抛出异常。 - -要升级,必须首先将以下配置属性放在flowable.cmmn.cfg.xml配置文件中: - -[source,xml,linenums] ----- - - - - - - - - - ----- - - 使用databaseSchemaUpdate设置为true即可完成自动升级。 - - -[[historyConfiguration]] - - -=== 历史配置 - -自定义历史存储的配置是可选的。 这允许您调整影响引擎的“历史记录,历史记录功能”的设置。 有关详细信息,请参阅<< historyConfig,history configuration >>。 - -[source,xml,linenums] ----- - ----- - - - -[[exposingConfigurationBeans]] - - -=== 在表达式和脚本中公开配置bean - - -默认情况下,您在flowable.cmmn.cfg.xml配置或您自己的Spring配置文件中指定的所有bean都可用于表达式和脚本。 如果要限制配置文件中bean的可见性,可以在流程引擎配置中配置名为beans的属性。 CmmnEngineConfiguration中的beans属性是一个map。 指定该属性时,表达式和脚本只能看到该映射中指定的bean。 暴露的bean将使用您在地图中指定的名称公开。 - -[[caseDefinitionCacheConfiguration]] - - -=== 部署缓存配置 - -所有定义都被缓存(在解析之后),以避免每次需要表单时都访问数据库,并且表单数据不会更改。 默认情况下,此缓存没有限制。 要限制表单缓存使用的容器大小,请添加以下属性: - - -[source,xml,linenums] ----- - ----- - - -设置此属性将使默认的LRU算法。 当然,此属性的“最佳”值取决于存储的案例总量和运行时实际使用的案例数。 - -您也可以注入自己的缓存实现。 这必须是实现org.flowable.engine.common.impl.persistence.deploy.DeploymentCache接口的bean: -[source,xml,linenums] ----- - - - ----- - - - -[[loggingConfiguration]] - - -=== 日志 - -所有日志记录(flowable,spring,mybatis,...)都通过SLF4J进行路由,并允许选择您选择的日志记录实现。 - -*默认情况下,flowable-dmn-engine依赖项中不存在SFL4J-binding jar,这应该在项目中添加,以便使用您选择的日志框架。 -*如果没有添加实现jar,SLF4J将使用NOP-logger,不记录任何内容,除了警告不会记录任何内容。 有关这些绑定链接的更多信息,请访问:$$http://www.slf4j.org/codes.html#StaticLoggerBinder$$[http://www.slf4j.org/codes.html#StaticLoggerBinder]。 -使用Maven,添加例如这样的依赖(这里使用log4j),请注意您仍然需要添加一个版本: - - -[source,xml,linenums] ----- - - org.slf4j - slf4j-log4j12 - ----- - - -flowable-ui和flowable-rest webapps配置了使用Log4j binding.。 在运行所有flowable-*模块的测试时也使用Log4j。 - -在类路径中使用带有commons-logging的容器时的重要注意事项: -为了通过SLF4J路由spring-logging,使用了一个桥接器(参见链接:$$http://www.slf4j.org/legacy.html#jclOverSLF4J$$[http://www.slf4j.org/legacy.html#jclOverSLF4J])。 -如果您的容器提供了commons-logging实现,请按照此页面上的说明进行操作:$$http://www.slf4j.org/codes.html#release$$[http://www.slf4j.org/codes.html#release]确保稳定性。 - -使用Maven时的示例(省略版本): - -[source,xml,linenums] ----- - - org.slf4j - jcl-over-slf4j - ----- - diff --git a/docs/userguide/src/zh_CN/cmmn/ch03-API.adoc b/docs/userguide/src/zh_CN/cmmn/ch03-API.adoc deleted file mode 100755 index 85ad2f6d576..00000000000 --- a/docs/userguide/src/zh_CN/cmmn/ch03-API.adoc +++ /dev/null @@ -1,394 +0,0 @@ -[[chapterApi]] - -== The Flowable CMMN API - -[[apiEngine]] - - -=== 流程 CMMN 引擎 API 与服务类 - -引擎 API 是与 Flowable 交互的最常用方式。核心起点是可以通过<>中描述的几种方式创建的 ++CMMN 引擎++。从 CMMN 引擎中,您可以获得包含案例/CMMN 方法的各种服务类。CMMN 引擎和其服务类对象是线程安全的,因此您可以为整个服务保留其中一个引用。 - -[source,java,linenums] ----- -CmmnEngine cmmnEngine = CmmnEngineConfiguration.createStandaloneCmmnEngineConfiguration(); - -CmmnRuntimeService runtimeService = cmmnEngine.getCmmnRuntimeService(); -CmmnRepositoryService repositoryService = cmmnEngine.getCmmnRepositoryService(); -CmmnTaskService taskService = cmmnEngine.getCmmnTaskService(); -CmmnManagementService managementService = cmmnEngine.getCmmnManagementService(); -CmmnHistoryService historyService = cmmnEngine.getCmmnHistoryService(); ----- - -+CmmnEngineConfiguration.createStandaloneCmmnEngineConfiguration()+ 将初始化并构建 CMMN 引擎,然后始终返回这个 CMMN 引擎。 - - -CmmnEngineConfiguration 类将扫描所有 +flowable.cmmn.cfg.xml+ 和 +flowable-cmmn-context.xml+ 配置文件。对于所有 +flowable.cmmn.cfg.xml+ 配置文件,CMMN 引擎将以典型的 Flowable 方式构建:+CmmnEngineConfiguration.createCmmnEngineConfigurationFromInputStream(inputStream).buildCmmnEngine()+。对于所有 +flowable-cmmn-context.xml+ 配置文件,CMMN 引擎将以 Spring 方式构建:首先创建 Spring 应用程序上下文,然后 CMMN 引擎会从该应用程序上下文中获取。 - -所有的服务类均是无状态的。这意味着您可以轻松地在群集中的多个节点上运行Flowable,每个节点都连接同一个数据库,而不必担心哪台机器实际执行了旧的调用。对任何服务类的任何调用都是幂等的,无论它在何处执行。 - -*CmmnRepositoryService* 可能是 Flowable CMMN 引擎工作时所需的第一个服务类。该服务类提供用于管理和使用++部署文件++和++案例定义++的操作。案例定义是 CMMN 1.1案例的 Java 对应物,它表示案例的每个步骤的结构和行为,这里不再过多介绍。++部署文件++是 Flowable CMMN 引擎中的打包单元。部署文件可以包含多个CMMN 1.1 XML文件和任何其他资源,其中具体包含哪些内容取决于开发人员。它的范围可以从单个流程 CMMN 1.1 XML 文件到整个案例和相关资源的包(例如,部署文件“hr-cases”可能包含与 HR 案例相关的所有内容)。+CmmnRepositoryService+ 可以++发布++这样的包。发布一个部署文件意味着将其上载到引擎,在该引擎中,所有案例在存储到数据库之前都会被检查和解析。从那一刻起,系统会感知到这个部署文件,并且部署文件中包含的任何流程都可以被发起。 - -此外,这个服务类允许您: - -* 查询引擎已知的部署文件和案例定义。 -* 检索各种资源,例如部署文件中包含的文件或引擎自动生成的案例图。 -* 检索案例定义的 POJO 版本,它可用于使用 Java 而不是 JSON 进行内省。 - -+CmmnRepositoryService+ 主要与静态信息(数据不会改变,至少不会变很多)有关,而 *CmmnRuntimeService* 恰恰相反,它涉及启动案例定义的新案例实例。如上所述,++案例定义++定义了案例的不同步骤的结构和行为。案例实例是案例定义的一次执行。对于每个案例定义,通常会有许多实例同时运行。CmmnRuntimeService 也是用于检索和存储案例变量的服务类。变量是特定于指定案例实例的数据,并且可以让案例中的各种结构使用(例如,方案的跳转条件通常使用流程变量来确定选择哪个路径来继续流转该案例)。CmmnRuntimeService 还允许您查询案例实例和方案条目。方案条目是 CMMN 1.1的已启用方案条目的表示。最后,无论何时案例实例需要继续流转并等待外部触发时都会使用 CmmnRuntimeService。案例实例可以具有各种等待状态,该服务类包含各种操作来向实例“发信号”并由外部触发器接收,然后案例实例可以继续流转。 - - -需要由系统的操作用户执行的任务是 Flowable 这类 CMMN 引擎的核心。围绕任务的所有内容都分组在 *CmmnTaskService* 中,例如: - -* 查询分配给用户或组的任务 -* 创建新的独立任务,这些任务与流程实例无关。 -* 操作派遣任务的参与人或以某种方式参与任务的用户。 -* 签收并完成一个任务。 签收意味着某人决定成为该任务的操作人,这意味着该用户将审批该任务,审批意味着“完成任务”。通常这是填写一种表单。 - -*CmmnHistoryService* 暴露 Flowable CMMN 引擎收集的所有历史数据。在执行案例时,引擎可以保存大量数据(可以通过配置决定是否启用),例如案例实例开始时间,谁执行哪些任务,审批任务花费多长时间,每个案例实例流经哪条路径等。此服务类主要暴露查询功能以访问此类数据。 - -*CmmnManagementService* 提供对数据库表低级信息的访问,允许查询不同类型的工作并执行它们。 - -有关服务操作和引擎 API 的更多详细信息,请参阅link:$$http://www.flowable.org/docs/javadocs/index.html$$[文档]。 - - -=== 异常策略 - -Flowable 中的基础异常是 +org.flowable.engine.FlowableException+,这是一个未经检查的异常。这种异常可以被 API 随时抛出,其他特定方法中发生的“预期中的”异常被记录在link:$$http://www.flowable.org/docs/javadocs/index.html$$[文档]中。例如 ++CmmnTaskService++ 的摘录: - -[source,java,linenums] ----- -/** - * 成功执行任务时调用。 - * @param taskId 要完成的任务的id,不能为空。 - * @throws FlowableObjectNotFoundException 当指定id的任务不存在时抛出。 - */ - void complete(String taskId); ----- - -在上面的示例中,当传递不存在的任务 id 时,将抛出异常。同样的,由于 Java 文档**明确声明 taskId 不能为 null,因此在传递 +null+ 时将抛出 +FlowableIllegalArgumentException+** 。 - -尽管我们想要避免一个大的异常层次结构,下列的异常子类仍会在特定情况下被抛出。在流程执行或 API 调用期间发生的所有其他错误都不适合下面可能发生的异常,这些错误将作为常规 ++FlowableExceptions++ 抛出。 - -* ++FlowableWrongDbException++:当 Flowable 引擎发现数据库 Schema 版本与引擎版本不匹配时抛出。 -* ++FlowableOptimisticLockingException++:当由同一数据条目的并发访问引起的数据存储中发生乐观锁问题时抛出。 -* ++FlowableClassLoadingException++:当未找到请求加载的类或加载时发生错误时抛出(例如 Java 代理类、任务监听器等)。 -* ++FlowableObjectNotFoundException++:当请求或操作的对象不存在时抛出。 -* ++FlowableIllegalArgumentException++:这个异常表示在 Flowable API 调用中使用了非法参数、在引擎的配置中配置了非法值。 -* ++FlowableTaskAlreadyClaimedException++:当一个任务已经被签收时,再次调用 +taskService.claim(...)+ 时抛出。 - - -[[queryAPI]] - - -=== 查询 API - -有两种方法可以从引擎查询数据:使用查询 API 和本地查询。查询 API 允许您使用流畅的 API 编写完全类型安全的查询。您可以为查询添加各种查询条件(所有条件共同应用逻辑与)与一个排序参数。示例如下: - -[source,java,linenums] ----- -List tasks = taskService.createTaskQuery() - .taskAssignee("kermit") - .orderByDueDate().asc() - .list(); ----- - -[[apiVariables]] - -=== 变量 - -每个案例实例都需要并使用数据来执行自身节点来进行流转。在 Flowable 中, 这种数据被称为__变量__, 它们存储在数据库中。变量可以在表达式中使用(例如在哨兵的条件中)、在调用外部服务时的 Java 服务任务中使用(例如提供输入或存储服务调用的结果)等。 - -案例实例可以包含变量(称为__案例变量__), 同样的__方案条目实例__和人工任务也可以包含变量。案例实例可以包含任意数量的变量。每个变量都存储在 __ACT_RU_VARIABLE__ 数据库表的一行中。 - -_createCaseInstanceBuilder_方法具有可选方法,用于通过 _CmmnRuntimeService_ 创建案例实例并启动时提供变量: - -[source,java,linenums] ----- -CaseInstance caseInstance = runtimeService.createCaseInstanceBuilder().variable("var1", "test").start(); ----- - -在案例执行期间可以添加变量。例如 _CmmnRuntimeService_: - -[source,java,linenums] ----- -void setVariables(String caseInstanceId, Map variables); ----- - -如下所示,变量同样可以被检索。请注意 _CmmnTaskService_ 上存在类似的方法。 - -[source,java,linenums] ----- -Map getVariables(String caseInstanceId); -Object getVariable(String caseInstanceId, String variableName); ----- - -变量通常用于 Java 服务任务、达式和脚本中等。 - -[[apiTransientVariables]] - -=== 临时变量 - -临时变量是行为类似于常规变量的变量,但不是持久变量。通常,临时变量用于高级用例。如有疑问,请使用常规案例变量。 - -以下情况适用于临时变量: - -* 临时变量根本不会存储历史记录。 -* 与__常规__变量一样,临时变量在设置时会放在__最高级父节点__上。这意味着在方案条目上设置变量时,临时变量实际存储在案例执行实例中。与常规变量一样,如果在特定方案条目或任务上设置变量,则存在方法的__本地__变体。 -* 临时变量只能在案例定义中的下一个“等待状态”之前访问。在那之后无法访问。在这里,等待状态表示案例实例中持久化到数据存储的时间点。 -* 临时变量只能由 _setTransientVariable(name, value)_ 设置,但在调用 _getVariable(name)_ 时也会返回临时变量(临时变量在 _getTransientVariable(name)_ 中也存在,它只检查瞬态变量)。这样做的原因是使表达式的编写变得容易,并且使用变量的现有逻辑适用于这两种变量类型。 -* 临时变量会__优先于__相同名称的持久变量。这意味着当在同一案例实例上设置相同名称的持久变量和临时变量后调用 _getVariable("someVariable")_ 时,将返回临时变量值。 - -您可以在暴露常规变量的大多数地方设置和获取临时变量: - -* 在 _PlanItemJavaDelegate_ 实现中的 _DelegatePlanItemInstance_ 上 -* 通过运行时服务类启动案例实例时 -* 审批一个任务时 - -这些方法遵循常规案例变量的命名约定: - -[source,java,linenums] ----- -CaseInstance caseInstance = runtimeService.createCaseInstanceBuilder().transientVariable("var1", "test").start(); ----- - - -[[apiExpressions]] - - -=== 表达式 - -Flowable 使用 UEL 进行表达式解析。UEL 即 __Unified Expression Language(统一表达语言)__并且是 Java EE 6规范的一部分(详情参见 link:$$http://docs.oracle.com/javaee/6/tutorial/doc/gjddd.html$$[Java EE6 规范] )。 - -表达式可用于例如 Java 服务任务和方案条目流转。虽然有两种类型的表达式:值表达式和方法表达式,但 Flowable 对此进行了抽象,因此它们都可以在需要++表达式++的地方使用。 - -* *值表达式*:解析为一个值。默认情况下,可以使用所有案例变量。此外,所有 Spring-beans(如果使用 Spring 的话)都可用于表达式。一些例子: - ----- -${myVar} -${myBean.myProperty} ----- - - -* *方法表达式*:调用带或不带参数的方法。**在调用不带参数的方法时,请确保在方法名称后添加空括号(因为这会将方法表达式与值表达式区分开来)。**传递的参数可以是文本值或自己解析的表达式。例子: - ----- -${printer.print()} -${myBean.addNewOrder('orderName')} -${myBean.doSomething(myVar, planItemInstance)} ----- - -请注意,这些表达式支持解析基础数据类型(包括比较它们)、Bean、列表、数组和集合。 - -除了所有流程变量之外,还有一些可用于表达式的默认对象: - -* ++caseInstance++:+DelegateCaseInstance+ 拥有有关正在进行的案例实例的额外信息。 -* ++planItemInstance++:+DelegatePlanItemInstance+ 拥有有关当前方案条目的额外信息。 - -[[cmmnExpressionsFunctions]] - -=== 函数表达式 - -[实验]表达式函数已在6.4.0版中添加。 - -为了更容易处理案例变量,在 _variables_ 命名空间下可以使用一组开箱即用的函数。 - -* *variables:get(varName)*:检索变量的值。与直接在表达式中写入变量名称的主要区别在于,当变量不存在时,使用此函数不会抛出异常。例如,如果 myVariable 不存在,_${myVariable == "hello"}_ 将会抛出异常,而 _${var:get(myVariable) == 'hello'}_ 将正常工作。 -* *variables:getOrDefault(varName, defaultValue)*:与 _get(varName)_ 类似,但可以选择提供默认值,该值在未设置变量或值为 _null_ 时返回。 -* *variables:exists(varName)*:如果变量具有非 null 值,则返回 _true_ 。 -* *variables:isEmpty(varName)* (别名 _:empty_):检查变量值是否为空。 根据变量类型,行为如下: -** 对于 String 变量,如果变量是空字符串,则该变量被视为空。 -** 对于 +java.util.Collection+ 变量,如果集合没有元素,则返回 _true_。 -** 对于 +ArrayNode+ 变量,如果没有元素,则返回 _true_ -** 如果变量是 _null_,则始终返回 _true_ -* *variables:isNotEmpty(varName)* (别名 _:notEmpty_):_isEmpty(varName)_ 的取反操作。 -* *variables:equals(varName, value)*(别名_ _:eq_):检查变量是否等于给定值。这是表达式的简写函数,否则将写为 _${execution.getVariable("varName") != null && execution.getVariable("varName") == value}_。 -** 如果变量值为 null,则返回 false(除非与 null 比较)。 -* *variables:notEquals(varName, value)*(别名 _:ne_):_equals(varName, value)_ 的取反操作。 -* *variables:contains(varName, value1, value2, ...)*: 检查提供的**所有**值是否包含在变量中。根据变量类型,行为如下: -** 对于 String 变量,传递的值需要全部为变量一部分子字符串 -** 对于 +java.util.Collection+ 变量,所有传递的值都需要是集合的元素(常规 _contains_ 语义)。 -** 对于 +ArrayNode+ 变量,支持检查 ArrayNode 是否包含作为变量类型支持的类型的 JsonNode -** 当变量值为 null 时,在所有情况下都返回 false。如果变量值不为 null,并且实例类型不是上述类型之一,则将返回 false。 -* *variables:containsAny(varName, value1, value2, ...)* :类似于 _contains_ 函数,但如果**存在**(不需要全部存在)传递的值包含在变量中,则返回 _true_。 -* 比较函数: -** *variables:lowerThan(varName, value)*(别名 _:lessThan_ 或 _:lt_):_${execution.getVariable("varName") != null && execution.getVariable("varName") < value}_ 的简写函数。 -** *variables:lowerThanOrEquals(varName, value)*(别名 _:lessThanOrEquals_ 或 _:lte_):与上面的类似,相当于 _< =_ -** *variables:greaterThan(varName, value)* (别名 _:gt_):与上面的类似,相当于 _>_ -** *variables:greaterThanOrEquals(varName, value)* (别名 _:gte_):与上面的类似,相当于 _> =_ - -_variables_ 命名空间的别名为 _vars_ 或 _var_。因此 _variables:get(varName)_ 等同于使用 _vars:get(varName)_ 或 _var:get(varName)_。请注意,不需要再次在变量名称周围加上引号:_var:get(varName)_ 等同于 _var:get(\'varName')_ 或 _var:get("varName")_。 - -另请注意,在上述任何函数中,都不需要将 _planItemInstance_ 或 _caseInstance_ 传递给函数(它们在不使用函数时需要传递)。在调用函数时,引擎将注入适当的变量作用域。这也意味着在 BPMN 流程定义中编写表达式时,可以以完全相同的方式使用这些函数。 - -这些变量函数的使用在 CMMN 中尤其有用,例如在写入 if 部分的哨兵条件时,采用以下 CMMN 案例定义: - -image::images/cmmn.expression-functions.png[align="center"] - -Assume the sentry has an if-part besides the completion event. Right after a case instance is started, this if-part condition will be evaluated (as the stage becomes available). If the condition is of the form _${someVariable == someValue}_, this means the variable needs to be available when starting the case instance. In many cases, this is not possible or the variable comes later (e.g. from a form), which leads to a low-level _PropertyNotFoundException_. Taking the potential nullability in account, the correct expression would have to be: -假设哨兵除了完成事件之外还有一个 if 部分。在启动案例实例后,将评估此 if 部分条件(当此阶段变为可用时)。如果条件的形式为 _${someVariable == someValue}_,则表示该变量在启动案例实例时就将可用。在许多情况下,这是不可能的,或者变量稍后才会出现 (例如来自一个表单),这会导致一个低级的 _PropertyNotFoundException_。考虑到潜在的可空性,正确的表达必须是: - ----- -${planItemInstance.getVariable('someVariable') != null && planItemInstance.getVariable('someVariable') == someValue} ----- - -这很长。但是,使用上述功能可以简化为 - ----- -${var:eq(someVariable, someValue)} ----- - -或者 - ----- -${var:get(someVariable) == someValue} ----- - -函数实现考虑了变量的可空性(并且在变量为 null 的情况下不抛出异常)并且将正确地处理相等性。 - -此外,可以注册自定义函数在表达式中使用。有关更多信息,请参阅 +org.flowable.common.engine.api.delegate.FlowableFunctionDelegate+ 接口。 - - -[[apiUnitTesting]] - - -=== 单元测试 - -案例是软件项目不可或缺的一部分,它们应该以与测试正常应用程序逻辑相同的方式进行测试:使用单元测试。 -由于 Flowable 是一个嵌入式的 Java 引擎,因此为业务案例编写单元测试就像编写常规单元测试一样简单。 - -Flowable 支持 JUnit 4、JUnit 5 做单元测试。 - -在 JUnit 5中,需要使用 +org.flowable.cmmn.engine.test.FlowableCmmnTest+ 注解或手动注册 +org.flowable.cmmn.engine.test.FlowableCmmnExtension+。 -+FlowableCmmnTest+ 注释是一个元注释,实现了对 +FlowableCmmnExtension+ 的注册(即它实现了 +@ExtendWith(FlowableCmmnExtension.class)+)。 -这将使 CmmnEngine 和其服务类可用作测试和生命周期方法的参数(+@BeforeAll+、+@BeforeEach+、+@AfterEach+、+@AfterAll+)。 -在每次测试之前,默认会使用类路径上的 +flowable.cmmn.cfg.xml+ 配置文件初始化 CmmnEngine。 -为了指定不同的配置文件,需要使用 +org.flowable.cmmn.engine.test.CmmnConfigurationResource+ 注解(参见第二个示例)。 -使用相同的配置文件时,CMMN 引擎会在多个单元测试之间静态缓存。 - -通过使用 +FlowableCmmnExtension+,您可以对测试方法使用 +org.flowable.cmmn.engine.test.CmmnDeployment+ 注解。 -当使用有 +@CmmnDeployment+ 注解的测试方法时,在每次测试之前,将会发布在 +CmmnDeployment#resources+ 下定义的 cmmn 文件。 -如果没有定义资源,将发布与测试类在同一包中的 +testClassName.testMethod.cmmn+ 形式的资源文件。 -在测试结束时,部署文件将会删除,包括所有相关的案例实例、定义等。 -有关更多信息,请参阅 ++CmmnDeployment++ 类。 - -考虑到所有这些,JUnit 5单元测试看起来如下: - -.使用默认配置文件的 Junit 5 单元测试 -[source,java,linenums] ----- -@FlowableCmmnTest -class MyTest { - - private CmmnEngine cmmnEngine; - private CmmnRuntimeService cmmnRuntimeService; - private CmmnTaskService cmmnTaskService; - - @BeforeEach - void setUp(CmmnEngine cmmnEngine) { - this.cmmnEngine = cmmnEngine; - this.cmmnRuntimeService = cmmnEngine.getCmmnRuntimeService(); - this.cmmnTaskService = cmmnEngine.getTaskRuntimeService(); - } - - @Test - @CmmnDeployment - void testSingleHumanTask() { - CaseInstance caseInstance = cmmnRuntimeService.createCaseInstanceBuilder() - .caseDefinitionKey("myCase") - .start(); - assertNotNull(caseInstance); - - Task task = cmmnTaskService.createTaskQuery().caseInstanceId(caseInstance.getId()).singleResult(); - assertEquals("Task 1", task.getName()); - assertEquals("JohnDoe", task.getAssignee()); - - cmmnTaskService.complete(task.getId()); - assertEquals(0, cmmnRuntimeService.createCaseInstanceQuery().count()); - } -} ----- - ------ -使用 JUnit 5,您还可以将部署文件的 ID(使用 org.flowable.cmmn.engine.test.CmmnDeploymentId)注入到测试和生命周期方法中。 ------ - -.使用自定义配置文件的Junit 5单元测试 -[source,java,linenums] ----- -@FlowableCmmnTest -@CmmnConfigurationResource("flowable.custom.cmmn.cfg.xml") -class MyTest { - - private CmmnEngine cmmnEngine; - private CmmnRuntimeService cmmnRuntimeService; - private CmmnTaskService cmmnTaskService; - - @BeforeEach - void setUp(CmmnEngine cmmnEngine) { - this.cmmnEngine = cmmnEngine; - this.cmmnRuntimeService = cmmnEngine.getCmmnRuntimeService(); - this.cmmnTaskService = cmmnEngine.getTaskRuntimeService(); - } - @Test - @CmmnDeployment - void testSingleHumanTask() { - CaseInstance caseInstance = cmmnRuntimeService.createCaseInstanceBuilder() - .caseDefinitionKey("myCase") - .start(); - assertNotNull(caseInstance); - - Task task = cmmnTaskService.createTaskQuery().caseInstanceId(caseInstance.getId()).singleResult(); - assertEquals("Task 1", task.getName()); - assertEquals("JohnDoe", task.getAssignee()); - - cmmnTaskService.complete(task.getId()); - assertEquals(0, cmmnRuntimeService.createCaseInstanceQuery().count()); - } -} ----- - -在 JUnit 4 中,_org.flowable.cmmn.engine.test.FlowableCmmnTestCase_ 可用作父类。它默认使用 _flowable.cmmn.cfg.xml_ 配置文件,如果缺少此类文件,则使用连接 H2 内存数据库的标准 CmmnEngine。 -在后台,CmmnTestRunner 用于初始化 CMMN 引擎。请注意下面的示例中如何使用 _@CmmnDeployment_ 注解自动部署案例定义(它将在与测试类相同的文件夹中查找 .cmmn 文件,并期望文件名为<测试类名>.<测试方法名称>.cmmn)。 - -[source,java,linenums] ----- - -public class MyTest extends FlowableCmmnTestCase { - - @Test - @CmmnDeployment - public void testSingleHumanTask() { - CaseInstance caseInstance = cmmnRuntimeService.createCaseInstanceBuilder() - .caseDefinitionKey("myCase") - .start(); - assertNotNull(caseInstance); - - Task task = cmmnTaskService.createTaskQuery().caseInstanceId(caseInstance.getId()).singleResult(); - assertEquals("Task 1", task.getName()); - assertEquals("JohnDoe", task.getAssignee()); - - cmmnTaskService.complete(task.getId()); - assertEquals(0, cmmnRuntimeService.createCaseInstanceQuery().count()); - } -} ----- - -此外,使用 _FlowableCmmnRule_ 并允许设置自定义配置: - -.JUnit 4 test with a Rule -.规则相关的 JUnit 4 单元测试 -[source,java,linenums] ----- -@Rule -public FlowableCmmnRule cmmnRule = new FlowableCmmnRule("org/flowable/custom.cfg.xml") - -@Test -@CmmnDeployment -public void testSomething() { - // ... - assertThat((String) cmmnRule.getCmmnRuntimeService().getVariable(caseInstance.getId(), "test"), containsString("John")); - // ... -} ----- - diff --git a/docs/userguide/src/zh_CN/cmmn/ch04-Spring.adoc b/docs/userguide/src/zh_CN/cmmn/ch04-Spring.adoc deleted file mode 100755 index 091cd493095..00000000000 --- a/docs/userguide/src/zh_CN/cmmn/ch04-Spring.adoc +++ /dev/null @@ -1,275 +0,0 @@ -[[springintegration]] - -== 整合Spring - -不使用spring也可以很好的使用Flowable,在这一章,我们会介绍一些很有用的整合特性。 - -=== CmmnEngineFactoryBean - - -+CmmnEngine+ 可以配置位一般的spring bean。整合的基点是 +org.flowable.cmmn.spring.CmmnEngineFactoryBean+ 类。这个bean加载CMMN配置文件并创建CMMN引擎。这意味着创建和配置和之前文档 <> 是一致的。整合spring,配置文件和引擎的服务类看上去是这样的: - -[source,xml,linenums] ----- - - ... - - - - - - ----- - -注意 +cmmnEngineConfiguration+ bean现在使用的是 +org.flowable.cmmn.spring.SpringCmmnEngineConfiguration+ 。 - -=== 默认spring配置 - -以下章节包括数据源(dataSource),事务管理(transactionManager),cmmn引擎(cmmnEngine)以及Flowable引擎各服务。 - - -当将数据源(DataSource)装入 +SpringCmmnEngineConfiguration+ (使用字段"dataSource") 里,Flowable将全局使用 +org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy+ 代理,用来包装传入的数据源。目的是让spring事务很好的管理数据库连接。这意味着您在spring配置里,不需要再代理数据源。尽管也可以将一个 +TransactionAwareDataSourceProxy+ 装入 +SpringCmmnEngineConfiguration+ ,但是再这种情况下,CMMN引擎不会再次包装该数据源。 - - -*确保在使用在spring配置中声明 +TransactionAwareDataSourceProxy+ 时,不要使用在spring事务代管下的数据源(比如 DataSourceTransactionManager 需要未被代理的dataSource)。* - -[source,xml,linenums] ----- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -... ----- - - - -首先,application context(spring容器上下文)可以使用任何spring的配置方式(比如:xml,@Configuration等)。这个示例使用的XML配置方式。 - -[source,java,linenums] ----- -ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext( - "org/flowable/cmmn/examples/spring/SpringIntegrationTest-context.xml"); ----- - -测试时这样使用: - -[source,java,linenums] ----- -@ContextConfiguration( - "classpath:org/flowable/cmmn/spring/test/SpringIntegrationTest-context.xml") ----- - - -[[springExpressions]] - -=== 表达式 - - -使用CmmnEngineFactoryBean,所有的spring bean在CMMN流程中的表达式默认都是可见的。可以在配置SpringCmmnEngineConfiguration的beans(类型Map)属性,限制表达式中使用的bean。下面的示例是暴露了单独的名为printer的bean。 -* 如果没有需要暴露给表达式的bean,配置 beans属性位一个空map。当不设置 'beans' 属性时,所有spring容器里的bean都是可用的。 * - -[source,xml,linenums] ----- - - ... - - - - - - - - ----- - -将可以使用的bean暴露给表达式: - -[source,xml,linenums] ----- -... - - - - - - - - - - - complete - - - - - - - - ----- - - +Printer+ 代码: - -[source,java,linenums] ----- -public class Printer { - - public void printMessage(String var) { - System.out.println("hello " + var); - } -} ----- - -Spring配置是这样的(如上所示): - -[source,xml,linenums] ----- - - ... - - - - ----- - - -=== 自动部署资源 - -Spring integration also has a special feature for deploying resources. In the CMMN engine configuration, you can specify a set of resources. When the CMMN engine is created, all those resources will be scanned and deployed. There is filtering in place that prevents duplicate deployments. Only when the resources have actually changed will new deployments be deployed to the Flowable DB. This makes sense in a lot of use cases, where the Spring container is rebooted frequently (for example, testing). - -整合spring,部署资源有一个独有的特性。CMMN引擎配置中可以定义很多资源。当CMMN引擎创建,这些资源将被扫描,发布。这个过程中将过滤重复发布的资源。当资源产生改变,将重新发布对应资源到数据库。这个在频繁重启的时候是很有意义的(比如测试时)。 - -Here's an example: - -请看示例: - -[source,xml,linenums] ----- - - ... - - - - - - ----- - - -以上配置默认将匹配到资源当作同一次发布(deployment)到Flowable引擎。没有更改的资源对整个发布生效。某些情况下,这可能不是所需要的。举个例子,这些发布里仅仅有一个资源文件有改动,那么发布(deployment)包含的所有资源都会被重新发布,导致实际没有变更的事例定义会产生新的版本。 - - -针对以上的问题,可以更改 +SpringCmmnEngineConfiguration+, +deploymentMode+ , 整个属性定义了如何判断资源将被部署。默认情况下该属性有一下三个选项: - - -* ++default++: 默认配置,将所有资源视为一组,当作同一发布. -* ++single-resource++: 单独发布,将所有分开的资源每一个当作一组发布。适用于分开发布所有流程定义,当有所改变时,只有改变的事务定义会产生新的版本号。 -* ++resource-parent-folder++: 目录发布,将同一文件夹下的资源文件视为一组,作为同一文件发布。适用于将不同的部署于大多数资源文件,但是依然会将共享文件夹的资源文件视为一组。下面的示例代码为使用+single-resource+ 配置 ++deploymentMode++: - - -[source,xml,linenums] ----- - - ... - - - ----- - - -除了以上列举的3个值来配置 +deploymentMode+, 您也可以自定义规则去检测发布,创建 +SpringCmmnEngineConfiguration+ 的子类,覆盖 +getAutoDeploymentStrategy(String deploymentMode)+ 方法。该方法确定 +deploymentMode+ 将使用哪种策略。 - -[[springUnitTest]] - - -=== 单元测试 - - -整合spring 使用 <> 可以很容易去测试业务事例。 -以下示例是经典的Spring-based JUnit 4或5的测试用例: - -.JUnit 5 test -[source,java,linenums] ----- -@ExtendWith(FlowableCmmnSpringExtension.class) -@ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = CmmnSpringJunitJupiterTest.TestConfiguration.class) -class MyBusinessCaseTest { - - @Autowired - private CmmnRepositoryService cmmnRepositoryService; - - @Autowired - private CmmnRuntimeService cmmnRuntimeService; - - @Test - @CmmnDeployment - public void simpleCaseTest() { - CaseInstance caseInstance = cmmnRuntimeService.createCaseInstanceBuilder() - .caseDefinitionKey("simpleCase") - .variable("var1", "John Doe") - .start(); - - Assertions.assertNotNull(caseInstance); - } -} ----- - -.JUnit 4 test -[source,java,linenums] ----- -public class MyBusinessCaseTest { - - @Rule - public FlowableCmmnRule cmmnRule = new FlowableCmmnRule("org/flowable/spring/test/el/SpringBeanTest-context.xml"); - - @Test - public void simpleCaseTest() { - cmmnRule.getCmmnRepositoryService().createDeployment().addClasspathResource("org/flowable/spring/test/el/springExpression.cmmn").deploy(); - CmmnRuntimeService cmmnRuntimeService = cmmnRule.getCmmnRuntimeService(); - CaseInstance caseInstance = cmmnRuntimeService.createCaseInstanceBuilder() - .caseDefinitionKey("myCase") - .variable("var1", "John Doe") - .start(); - - Assert.assertNotNull(caseInstance); - } -} ----- diff --git a/docs/userguide/src/zh_CN/cmmn/ch05-Deployment.adoc b/docs/userguide/src/zh_CN/cmmn/ch05-Deployment.adoc deleted file mode 100755 index 54a914d885f..00000000000 --- a/docs/userguide/src/zh_CN/cmmn/ch05-Deployment.adoc +++ /dev/null @@ -1,136 +0,0 @@ -[[chDeployment]] - -== 部署 - - -=== 外部资源 - - - - -案例定义位于Flowable 数据库中。当在Flowable 配置文件使用Service Tasks或Spring Beans时,这些案例定义可以引用委托类来处理。 -这些类和Spring配置文件,必须可以用于所有可能执行案例定义的CMMN引擎。 - -==== JAVA 类 - - - - -在案例定义中使用的所有自定义类(例如,服务任务中使用的PlanItemJavaDelegates)都应该在启动案例实例时,配置在引擎的类路径上。 - - -但是,在部署案例定义期间,这些类不必配置在类路径上。也就是说在部署新的案例定义时,您的委托类不必位于类路径上,例如:当您使用演示安装程序并要添加自定义类时,应该将包含类的JAR添加到“flowable-task”或“flowable-rest” webapp lib中。别忘了还要包括自定义类(如果有的话)的依赖项。或者您也可以将依赖项配置在Tomcat安装的libraries目录中,$tomcat.home/lib(或其他Web容器的类似位置)。 - -==== 从案例实例中使用SpringBeans - - - - -当在表达式或脚本使用SpringBean时,在执行案例定义时,这些bean必须对引擎可用。如果您正在构建自己的webapp,并按照 “Spring集成”章节 中的相关章节描述,在您的应用上下问文中配置CMMN引擎,那这很简单。但请记住,如果您使用"Flowable task"和"Flowable rest" webapps,那么也应该使用该上下文对其进行更新。 - -[[versioningOfCaseDefinitions]] - - -=== 案例定义的版本管理 - - - - -CMMN没有版本控制的概念,这实际上很好,因为可执行CMMN文件可能作为开发项目的一部分存在于版本控制系统库中(如Subversion、Git或Mercurial)。但是,案例定义的版本是作为部署的一部分在引擎中创建的。在部署过程中,flowable将为CaseDefinition分配一个版本,然后将其存储在flowable数据库中 - - -对于部署中的每个案例定义,执行以下步骤初始化属性键、版本、名称和ID: - - -* XML文件中的案例定义+id+属性,用作案例定义+key+属性。 - - -* XML文件中的案例定义+名称+属性用作案例定义+名称+属性。如果未指定名称属性,则使用id属性作为名称。 - - -* 第一次部署具有特定密钥的案例时,将分配版本1。对于具有相同键的案例定义的所有后续部署版本,版本将设置为比当前部署的最高版本高1。key属性用于区分大小写定义。 - - - - - - -以下面的例子为例 - -[source,xml,linenums] ----- - - - ... ----- - - -部署此案例定义时,数据库中的案例定义将看起来像这样 - -[options="header"] -|=============== -|id|key|name|version -|676|myCase|My important case|1 - -|=============== - - -假设我们现在部署相同案例的更新版本(例如,更改一些人工任务),但案例定义的ID保持不变。案例定义表现在将包含以下条目: - -[options="header"] -|=============== -|id|key|name|version -|676|myCase|My important case|1 -|870|myCase|My important case|2 - -|=============== - - -当调用RuntimeService.CreateCaseInstanceBuilder().CaseDefinitionKey(“MyCase”).Start()时,它现在将在版本2中使用案例定义,因为这是案例定义的最新版本。 - - -如果我们像下面定义的那样创建第二个案例并将其部署到Flowable,那么第三行将添加到表中。 - - -[source,xml,linenums] ----- - - - ... ----- - - -这个表看起来像这样: - -[options="header"] -|=============== -|id|key|name|version -|676|myCase|My important case|1 -|870|myCase|My important case|2 -|1033|myNewCase|My important case|1 - -|=============== - - -请注意:新案例的关键与第一个案例有何不同?尽管名称是相同的(我们可能也该更改它),但在区分大小写时,Flowable只考虑ID属性。因此,新案例会与版本1一起部署。 - -[[deploymentCategory]] - - -=== 分类 - - - -部署和案例定义都有用户定义的类别。案例定义类别是用CMMN XML中的“targetNamespace”属性的值初始化的: - - - - - - - - - - - - complete - - - complete - - - - - complete - - - - - - - - - - - - ... - - - ----- - - -=== 程序示例 - - -在这个小节, 我们将会用代码构建并执行一个简单的案例模型, 通过在命令行中调用Flowable CMMN engine的Java API. - - -在这个案例模型中, 我们将构建一个简化的有两个阶段的 _employee onboarding_ 案例: 两个时期分别在的员工入职前后.第一个阶段,HR部门中的某个人将会完成相关任务;第二个阶段,该员工完成它们.同时,在任何时间,该试用员工可以拒绝这份工作并且停止这个实例. - - -注意, 只有 stages and human tasks 被用到. 在真实案例模型中, 很可能会有其他类型的计划项,比如里程碑, 嵌套stage, 自动化任务等等. - -image::images/cmmn.programmatic.example.png[align="center"] - - -这个案例模型的XML如下所示: - -[source,xml,linenums] ----- - - - - - - - - - - - - complete - - - - - complete - - - - - - - - - - - - complete - - - complete - - - complete - - - - - - - - - - - - - - - - - - ----- - - -首先, 创建一个新的工程, 添加 _flowable-cmmn-engine_ 依赖(这里展示了Maven), H2 数据库依赖也要添加, 后续将会使用 H2 作为内嵌的数据库. - -[source,xml,linenums] ----- - - org.flowable - flowable-cmmn-engine - ${flowable.version} - - - com.h2database - h2 - ${h2.version} - ----- - - -The Flowable CMMN API 包括了其他的 Flowable APIs 和相关概念. 同样,熟悉 BPMN 或者 DMN APIs的人很容易上手.和其他引擎一样, 第一行代码是创建一个 Cmmn引擎. 这里,默认的配置将会使用 H2作为内存数据库: - -[source,java,linenums] ----- -public class Main { - public static void main(String[] args) { - CmmnEngine cmmnEngine - = new StandaloneInMemCmmnEngineConfiguration().buildCmmnEngine(); - } -} ----- - - -注意_CmmnEngineConfiguration_ 提供了很多配置项来调整 CMMN引擎的设置. - - -把上述 XML 放入一个文件中, 例如 _my-case.cmmn_ (or .cmmn.xml). 对于Maven工程, 应该放在 _src/main/resources_ 文件夹中. - - -为了使引擎感知当前案例模型, 它首先需要被部署 _deployed_. 这个工作由 the _CmmnRepositoryService_ 完成: - -[source,java,linenums] ----- -CmmnRepositoryService cmmnRepositoryService = cmmnEngine.getCmmnRepositoryService(); -CmmnDeployment cmmnDeployment = cmmnRepositoryService.createDeployment() - .addClasspathResource("my-case.cmmn") - .deploy(); ----- - - -当部署XML时, 会返回一个 *CmmnDeployment*. 一个 deployment 包含多个案例模型和目标. 一个明确的案例模型定义被存储成一个案例定义 *CaseDefinition*. 这可以通过执行 _CaseDefinitionQuery_ 案例定义查询 来验证: - -[source,java,linenums] ----- -List caseDefinitions = cmmnRepositoryService.createCaseDefinitionQuery().list(); -System.out.println("Found " + caseDefinitions.size() + " case definitions"); ----- - - -当在引擎中拥有一个案例定义后, 现在可以启动一个对应 *CaseInstance* 案例实例. 要么使用查询后的结果并传递给下面的代码片段中, 要么直接使用 the case definition的key(如下所示). - - - -注意当启动 *CaseInstance*, 我们也传递了 _potentialEmployee_ 作为一个标记, 这个变量之后会被用作人工任务的指派(see the _assignee="${potentialEmployee}"_ attribute on _human tasks_) - -[source,java,linenums] ----- -CmmnRuntimeService cmmnRuntimeService = cmmnEngine.getCmmnRuntimeService(); -CaseInstance caseInstance = cmmnRuntimeService.createCaseInstanceBuilder() - .caseDefinitionKey("employeeOnboarding") - .variable("potentialEmployee", "johnDoe") - .start(); ----- - - -当 *CaseInstance* 启动后, 引擎将决定哪一个计划项应该被激活: - - -* 第一个阶段没有入口凭证, 所以它会被激活 - - -* 第一个阶段的子人工任务没有入口凭证, 所以它们三个也预计被激活 - - -在运行时, 计划项被当做 *PlanItemInstances*, 可以使用 _CmmnRuntimeService_ 查询获取: - -[source,java,linenums] ----- -List planItemInstances = cmmnRuntimeService.createPlanItemInstanceQuery() - .caseInstanceId(caseInstance.getId()) - .orderByName().asc() - .list(); - -for (PlanItemInstance planItemInstance : planItemInstances) { - System.out.println(planItemInstance.getName()); -} ----- - - -打印如下: - ----- -After starting -Agree start date -Allocate office -Create email address -Prior to starting -Reject job -Send joining letter to candidate ----- - - -上述打印结果中有些事情可能出乎意料: - - -* stages 也是属于 计划项, 同样被当做 *PlanItemInstance*. 注意当调用 _.getStageInstanceId()_ ,子计划项实例也会拥有stage作为父类. - - -* _Send joining letter to candidate_ 也在返回结果集中.原因是因为依据 CMMN 1.1 规范, 这个计划项实例是出于可用状态, 而不是处于活跃状态. - - -进一步, 修改上述代码: - -[source,java,linenums] ----- -for (PlanItemInstance planItemInstance : planItemInstances) { - System.out.println(planItemInstance.getName() - + ", state=" + planItemInstance.getState() - + ", parent stage=" + planItemInstance.getStageInstanceId()); -} ----- - - -现在输出如下: - ----- -After starting, state=available, parent stage=null -Agree start date, state=active, parent stage=fe37ac97-b016-11e7-b3ad-acde48001122 -Allocate office, state=active, parent stage=fe37ac97-b016-11e7-b3ad-acde48001122 -Create email address, state=active, parent stage=fe37ac97-b016-11e7-b3ad-acde48001122 -Prior to starting, state=active, parent stage=null -Reject job, state=active, parent stage=fe37ac97-b016-11e7-b3ad-acde48001122 -Send joining letter to candidate, state=available, parent stage=fe37ac97-b016-11e7-b3ad-acde48001122 ----- - - -为了只显示活跃状态的计划项实例, 查询可以调整并增加 _planItemInstanceStateActive()_ 方法: - -[source,java,linenums] ----- - List planItemInstances = cmmnRuntimeService.createPlanItemInstanceQuery() - .caseInstanceId(caseInstance.getId()) - .planItemInstanceStateActive() - .orderByName().asc() - .list(); ----- - - -现在输出如下: - ----- -Agree start date -Allocate office -Create email address -Prior to starting -Reject job ----- - - -当然, *PlanItemInstance* 是 低级别的表示, 但是每个计划项也拥有一个 _plan item definition_ 明确其类型. 在这个例子中, 我们只有 _human tasks_.通过使用 计划项实例 来影响整个 案例实例, -(比如, _CmmnRuntimeService.triggerPlanItemInstance(String planItemInstanceId)_).然而, 交互最有可能通过实际计划项定义的结果发生: 比如这里的人工任务. - - -任务的查询方法和BPMN 引擎一样, (实际上, 任务服务是一个共享的组件, BPMN或者CMMN创建的任务都可以通过各自引擎查询得到): - -[source,java,linenums] ----- -CmmnTaskService cmmnTaskService = cmmnEngine.getCmmnTaskService(); -List hrTasks = cmmnTaskService.createTaskQuery() - .taskCandidateGroup("hr") - .caseInstanceId(caseInstance.getId()) - .orderByTaskName().asc() - .list(); -for (Task task : hrTasks) { - System.out.println("Task for HR : " + task.getName()); -} - -List employeeTasks = cmmnTaskService.createTaskQuery() - .taskAssignee("johndoe") - .orderByTaskName().asc() - .list(); -for (Task task : employeeTasks) { - System.out.println("Task for employee: " + task); -} ----- - - -上述输出: - ----- -Task for HR : Agree start date -Task for HR : Allocate office -Task for HR : Create email address - -Task for employee: Reject job ----- - - -当HR的三个任务都完成, 给求职者发送入职信的任务应该是可用的: - -[source,java,linenums] ----- -for (Task task : hrTasks) { - cmmnTaskService.complete(task.getId()); -} - -hrTasks = cmmnTaskService.createTaskQuery() - .taskCandidateGroup("hr") - .caseInstanceId(caseInstance.getId()) - .orderByTaskName().asc() - .list(); - -for (Task task : hrTasks) { - System.out.println("Task for HR : " + task.getName()); -} ----- - - -事实上, 预期的任务现在被创建了: - ----- -Task for HR : Send joining letter to candidate ----- - - -完成这个任务,案例实例将进入第二个阶段, 同时第一阶段的哨兵的条件得到满足. 'Reject job'任务被程序自动创建, 并且指派给员工的两个任务也被创建: - -[source,java,linenums] ----- -Task for employee: Fill in paperwork -Task for employee: New starter training -Task for employee: Reject job ----- - - -完成所有任务将结束整个案例实例: - ----- -List tasks = cmmnTaskService.createTaskQuery().caseInstanceId(caseInstance.getId()).listPage(0, 1); -while (!tasks.isEmpty()) { - cmmnTaskService.complete(tasks.get(0).getId()); - tasks = cmmnTaskService.createTaskQuery() - .caseInstanceId(caseInstance.getId()) - .listPage(0, 1); -} ----- - - -当执行案例实例时, 引擎也会保存历史信息, 这可以通过查询API获取: - -[source,java,linenums] ----- -CmmnHistoryService cmmnHistoryService = cmmnEngine.getCmmnHistoryService(); -HistoricCaseInstance historicCaseInstance = cmmnHistoryService.createHistoricCaseInstanceQuery() - .caseInstanceId(caseInstance.getId()) - .singleResult(); - -System.out.println("Case instance execution took " - + (historicCaseInstance.getEndTime().getTime() - historicCaseInstance.getStartTime().getTime()) + " ms"); - -List historicTaskInstances = cmmnHistoryService.createHistoricTaskInstanceQuery() - .caseInstanceId(caseInstance.getId()) - .orderByTaskCreateTime().asc() - .list(); - -for (HistoricTaskInstance historicTaskInstance : historicTaskInstances) { - System.out.println("Task completed: " + historicTaskInstance.getName()); -} ----- - - -输出如下: - ----- -Case instance execution took 149 ms -Task completed: Reject job -Task completed: Agree start date -Task completed: Allocate office -Task completed: Create email address -Task completed: Send joining letter to candidate -Task completed: New starter training -Task completed: Fill in paperwork ----- - - -案例执行相关的历史数据以特殊的结构被收集, 比如 Tasks (上面所见的), milestones, cases, variables and 一般的 plan items. -这个数据作为运行时数据被持久化, 但是不会在实例结束后被删除.访问历史数据可以通过 _CmmnHistoryService_ 的相关API - - - -当然, 这只是Flowable CMMN Engine所有可用的APIs中的一小部分,请查阅其他章节了解更多详情 - -=== CMMN 1.1 Constructs - - -这个小节 覆盖了 Flowable支持的 CMMN 1.1设计, 同时也是对 CMMN 1.1 标准的拓展 - - -下述设计, 除了哨兵和item 控制, 都是依据 CMMN规范中的计划项作为参考.它们实例执行的历史数据可用通过 _CmmnHistoryService_ 使用 _org.flowable.cmmn.api.history.HistoricPlanItemInstanceQuery_ 方法获取. - - -==== 阶段 - - -一个 stage 被看作一组计划项的集合, 它通常用于在案例实例中定义"阶段" - - -一个 stage 本事也是计划项, 也拥有进入和退出凭证. 计划项以及它包含的计划项只有在计入活跃状态才可用, stage 可以内嵌在其他stage中. -A stage is visualized as a rectangle with angled corners: - -a stage 可以看作是一个有尖角的矩形 - -image::images/cmmn.stage.png[align="center"] - - -==== 任务 - - -一个手动任务, 意味着它将在引擎外部发生. - -Properties: - - -* *name*: 表达式将会在运行时被解析当做任务名称 - - -* *blocking*: 布尔值决定是否任务被阻塞 - - -* *blockingExpression*: 表达式 计算成布尔值决定该任务是否被阻塞 - - -如果一个任务是 非阻塞non-blocking, 引擎将在执行时自动完成它. 如果一个任务被阻塞blocking, 这个任务对应的计划项实例会被保持活跃状态active state, -直到以编程方式触发( _CmmnRuntimeService.triggerPlanItemInstance(String planItemInstanceId)_ 方法). - - -一个任务看作一个圆角矩形: - -image::images/cmmn.task.png[align="center"] - - -==== 人工任务 - - -一个人工任务用作模型化需要人完成的工作, 比如表单. 当引擎抵达一个人工任务, 被指派的人工或组对应的任务列表就会新增加一项. - - -一个人工任务也是一个计划项, 这意味着除了人工任务本身之外,还创建了一个 _PlanItemInstance_,并且可以通过 _PlanItemInstanceQuery_ 查询它. - - -人工任务可以通过 _org.flowable.task.api.TaskQuery_ API 查询.历史数据可以通过 _org.flowable.task.api.history.HistoricTaskInstanceQuery_ 查询. - -Properties: - -属性: - -* *name*: 被用作该人工任务的名称 - -* *blocking*: 布尔值决定该任务是否被阻塞 - -* *blockingExpression*: 表达式计算得到布尔值决定任务是否被阻塞 - -* *assignee* : 表达式(可以是静态文本) 决定该任务的指派人 - -* *owner* : 表达式(可以是静态文本)决定该任务的拥有者 - -* *candidateUsers* : 表达式(可以是静态文本)解析成以逗号分隔的字符串,被用作决定该人工任务的候选人列表 - -* *candidateGroups* : 表达式(可以是静态文本)解析成以逗号分隔的字符串,被用作决定该人工任务的候选组列表 - -* *form key*: 表达式决定使用表单的key, 后续通过API访问 - -* *Due date* 过期时间 解析为 java.util.Date or a ISO-8601 date string - -* *Priority*: 优先级 解析为整型, 可以用来在 TaskQuery API中筛选任务 - - -一个人工任务看作一个圆角矩形, 左上角有一个用户图标 - -image::images/cmmn.humantask.png[align="center"] - - -==== Java 服务任务 - - -服务任务被用作执行自定义逻辑. - - -自定义逻辑要放在一个实现 _org.flowable.cmmn.api.delegate.PlanItemJavaDelegate_ 接口的类中. - -[source,java,linenums] ----- -public class MyJavaDelegate implements PlanItemJavaDelegate { - - public void execute(DelegatePlanItemInstance planItemInstance) { - String value = (String) planItemInstance.getVariable("someVariable"); - ... - } - -} ----- - - -对于一些高级实现,使用 _PlanItemJavaDelegate_ 可能不能覆盖到, _CmmnActivityBehavior_可以被使用(类似于 BPMN 引擎中的 _JavaDelegate_ vs _ActivityBehavior_) - - -Properties: - -属性: - -* *name*: 服务任务service task的名称 - -* *class*: 自定义逻辑的Java实现类 - -* *class fields*: 调用自定义逻辑时的传递参数 - -* *Delegate expression*: 表达式解析为一个实现_PlanItemJavaDelegate_接口的类 - - -一个 服务任务service task 看作一个圆角矩形, 左上角有个齿轮图标 - -image::images/cmmn.servicetask.png[align="center"] - - -====决策任务 - - -一个决策任务调用外部 DMN 决策表,并在case实例中存储结果变量 - -Properties: - -属性: - -* *Decision table reference*: 相关的需要被执行 DMN 决策表. - - -通过设置'_Throw error if no rules were hit_'属性, 当在 DMN 决策表计算过程中没有命中任何规则时, 可能会抛出错误. - - -一个 服务任务service task 看作一个圆角矩形, 左上角有个表格图标 - -image::images/cmmn.decisiontask.png[align="center"] - - -==== http请求任务 - - -Http Task http请求任务是 _service task_ 一个开箱即用的实现,被用作调用一个http REST 服务. - - -Http Task http请求任务包含多个参数来自定义请求和响应. 查阅 BPMN http task documentation 了解更多参数设置的细节 - - -一个 服务任务service task 看作一个圆角矩形, 左上角有个火箭图标 - -image::images/cmmn.httptask.png[align="center"] - - -==== 脚本任务 - - -脚本任务类似 BPMN 中脚本任务, 当一个计划项变成活跃状态, 用来执行一个脚本. - -Properties: - -属性: - -* *name*: 表示任务名称 - -* *type*: 任务属性, 必须是"script", 表示该任务类型 - -* *scriptFormat*: 拓展属性 表示脚本语言(例如, javascript, groovy) - -* *script*: 执行的脚本, 在"script"元素中作为一个string - -* *autoStoreVariables*: 可选的任务属性标记 (默认: false) 表示脚本中定义的变量是否保存到计划项实例上下文中 (查看下面注意事项note) - -* *resultVariableName*: 可选的任务属性 明确脚本执行结果保存到计划项实例上下文中对应的名称 (查看下面注意事项note) - - -一个 服务任务service task 看作一个圆角矩形, 左上角有个脚本图标 - -image::images/cmmn.scripttask.png[align="center"] - -[source,xml,linenums] ----- - - - Optional documentation - - - - sum = 0; - for ( i in inputArray ) { - sum += i; - } - - - - ----- - - -*Note*: *scriptFormat* 属性值必须符合 link:$$http://jcp.org/en/jsr/detail?id=223$$[JSR-223] (scripting for the Java platform). -默认, JavaScript 包含在每个JDK里, 不需要额外的JAR文件. 如果你想使用另外 (JSR-223 兼容) 脚本引擎, 在classpath中添加对应的Jar文件并使用合适的名称. -例如, Flowable 单元测试 经常使用 Groovy, 因为其语法和 JAVA 相像. - - -注意Groovy脚本引擎是绑定在groovy-jsr223 JAR, 这样, 必须添加下面的依赖: - -[source,xml,linenums] ----- - - org.apache.groovy - groovy-jsr223 - 4.x.x - ----- - - -在脚本任务中, 所有案例变量 variables 都可以通过 PlanItem 实例在脚本中访问.在下面的例子中, 脚本变量 _'inputArray'_ 实际上是一个案例变量variable(一个整型数组) - -[source,xml,linenums] ----- - - - sum = 0 - for ( i in inputArray ) { - sum += i - } - - ----- - - -*Note*: 通过在脚本中调用 _planItemInstance.setVariable("variableName", variableValue)_, 可以设置计划项实例的变量值.默认不会保存任务变量. -通过设置 _autoStoreVariables_属性值为true, 也可以自动保存在脚本中定义的变量(例如, 上述实例中的sum).然而, 最好是不要显示调用 _planItemInstance.setVariable("variableName", variableValue)_ -,在某些版本的JDK中, 一些脚本语言自动保存变量会不起作用. 查阅 link:$$http://www.jorambarrez.be/blog/2013/03/25/bug-on-jdk-1-7-0_17-when-using-scripttask-in-activiti/$$[链接] 了解更多细节 - - -[source,xml,linenums] ----- - ----- - -The default for this parameter is +false+, meaning that if the parameter is omitted from the script task definition, all the declared variables will only exist during the duration of the script. - -该参数默认是false, 意味着在脚本定义中省略, 所有脚本中声明的变量只会存在于脚本执行过程中. - - -这是一个在脚本中如何设置变量的例子: - -[source,xml,linenums] ----- - - - def scriptVar = "test123" - planItemInstance.setVariable("myVar", scriptVar) - - ----- - - -以下名称是预留的, 不能被使用: *out, out:print, lang:import, context, elcontext*. - - -*Note* 脚本任务的返回值可以被分配给一个已经存在或者新的计划项实例变量, 通过在脚本任务定义中设置_'flowable:resultVariable'_ 属性值.任何已经存在的相同名称变量的值会被脚本返回值覆盖.当未明确设置返回结果变量名, 脚本的返回值会被忽略. - -[source,xml,linenums] ----- - - - #{echo} - - ----- - - -在上述实例中, 当脚本执行结束后, 脚本的返回值( __'#{echo}'__的解析值)会被设置成名称为 __'myVar'__ 的流程变量值. - - -==== 里程碑 - - -里程碑被用作标记到达案例实例中的某个点. 在运行时, 它们被称为 *MilestoneInstances* , 可以通过调用 _CmmnRuntimeService_ 的 *MilestoneInstanceQuery* 查询. 也可以通过 _CmmnHistoryService_ 获取一个历史副本. - - -里程碑也是计划项, 这意味着除了里程碑条目外, _PlanItemInstance_ 同样会被创建, 通过_PlanItemInstanceQuery_ 可以查询到. - -Properties: - -属性: - -* *name*: 一个表达式或者静态文本, 决定里程碑名称 - - -里程碑被看作一个圆角矩形(比任务更圆一些) - -image::images/cmmn.milestone.png[align="center"] - - -==== 案例任务 - - -用例任务用作在一个案例上下文中启动一个子案例. _CaseInstanceQuery_ 有一些选项查询父类案例. - - -当一个案例任务被阻塞, _PlanItemInstance_ 将会处于活跃状态, 直到子案例全部完成.如果案例任务是非阻塞, 子案例启动后, 计划项实例自动完成.当子案例实例结束对父类没有影响. - -Properties: - -属性: - -* *name*: 表达式或静态文本, 决定名称 - -* *blocking*: 布尔值决定任务是否被阻塞 - -* *blockingExpression*: 表达式计算得到布尔值决定任务是否被阻塞 - -* *Case reference*: 案例定义的key, 用来启动一个子实例.可以是一个表达式 - - -一个案例任务看作一个圆角矩形, 左上角有一个case 图标 - -image::images/cmmn.casetask.png[align="center"] - - -==== 流程任务 - - -流程任务被用作在案例上下文中启动一个流程实例 - - -当流程任务被阻塞, _PlanItemInstance_ 将会一直 活跃_active_状态, 直到 流程实例全部完成. 如果流程任务非阻塞, 流程实例任务启动并且计划项实例自动完成, 当流程实例结束对父类没有任何影响. - -Properties: - -属性: - -* *name*: 表达式或静态文本, 决定名称 - -* *blocking*: 布尔值决定任务是否被阻塞 - -* *blockingExpression*: 表达式计算得到布尔值决定任务是否被阻塞 - -* *Process reference*: 案例定义的key, 用来启动一个子实例.可以是一个表达式 - - -一个流程任务看作一个圆角矩形, 左上角有个箭头图标 - -image::images/cmmn.processtask.png[align="center"] - - -流程任务可以配置为具有内部和外部参数,这些参数的形式是_source/sourceExpression_ and _target/targetExpression_. - - -内部参数在当前案例实例上下文内被解析. - -* _source_ value 将把一个case实例变量, 映射成一个流程变量 - -* 或者, the _sourceExpression_ 允许创建任意值,其中表达式根据case实例解析. - -* _target_ 是流程变量的名称, 是被_source_映射 - -* 或者, _targetExpression_将被解析成一个 *string*, 用作流程实例的变量名称.表达式根据case实例上下文解析. - - -内部参数在当前流程实例(全局)上下文内被解析. - -* The _source_ value will be the process instance variable which value will be mapped to a case variable -* _source_ value 将把一个流程变量值, 映射成一个case变量 - -* 或者, the _sourceExpression_ 允许创建任意值,其中表达式根据流程实例解析. - -* _target_ 是流程变量的名称, 是被_source_映射 - -* 或者, _targetExpression_将被解析成一个 *string*, 用作case实例的变量名称.表达式根据流程实例(全局)上下文解析. - - -==== 凭证 - - -===== 入口凭证 (入口哨兵) - - -进入凭证构成一个计划项实例的哨兵, 它们由两部分组成: - -* One or more parts that depend on other plan items: these define dependencies on state transitions of other plan items. For example, one human task can depend on the state transition 'complete' of three other human tasks to become active itself -* 一个或者多个部分依赖其他计划项: 它们依赖其他计划项状态的转变.例如一个人工任务取决于另外三个人工任务的完成,才能变成活跃状态. - -* One optional _if part_ or _condition_: this is an expression that allows the definition of a complex condition -*一个可选的如果部分或条件: 允许定义一个复杂条件的表达式 - -A sentry is satisfied when all its criteria are resolved to _true_. When a criterion evaluates to true, this is stored and remembered for future evaluations. Note that entry criteria of all plan item instances in the _available_ state are evaluated whenever something changes in the case instance. -Multiple sentries are possible on a plan item. However, when one is satisfied, the plan item moves from state _available_ to _active_. - -一个哨兵只有所有凭证解析为 _true_, 才会满足条件. 当一个凭证被解析为true, 将会被存储以便后续计算. 注意当case实例中发生更改时,将计算处于可用状态的所有计划项实例的入口条件. -多个哨兵可能会用在一个计划项, 然而当一个哨兵满足条件, 该计划项状态会从可用 _available_ 变成活跃 _active_. - -See <> for more information. - -查阅 <>, 了解更多详情. - -An entry criterion is visualized as a diamond shape (white color inside) on the border of a plan item: - -入口哨兵被看作一个菱形(内部白色),位于计划项边界上: - -image::images/cmmn.entrycriteria.png[align="center"] - -===== Exit criterion (exit sentry) - -===== Exit criterion (exit sentry) 出口凭证 (出口哨兵) - -Exit criteria form a sentry for a given plan item instance. They consist of two parts: - -进入凭证构成一个计划项实例的哨兵, 它们由两部分组成: - -* One or more parts that depend on other plan items: these define dependencies on state transitions of other plan items. For example, one human task can depend on reaching a certain milestone to be automatically terminated -* 一个或者多个部分依赖其他计划项: 它们依赖其他计划项状态的转变.例如一个人工任务取决于另外三个人工任务的完成,才能变成活跃状态. - -* One optional _if part_ or _condition_: this is an expression that allows a complex condition to be defined -*一个可选的如果部分或条件: 允许定义一个复杂条件的表达式 - -A sentry is satisfied when all its criteria are resolved to _true_. When a criterion evaluates to true, this is stored and remembered for future evaluations. Note that exit criteria of all plan item instances in the _active_ state are evaluated whenever something changes in the case instance. -Multiple sentries are possible on a plan item. However, when one is satisfied, the plan item moves from state _active_ to _exit_. - -一个哨兵只有所有凭证解析为 _true_, 才会满足条件. 当一个凭证被解析为true, 将会被存储以便后续计算. 注意当case实例中发生更改时,将计算处于可用状态的所有计划项实例的入口条件. -多个哨兵可能会用在一个计划项, 然而当一个哨兵满足条件, 该计划项状态会从活跃 _active_ 变成退出 _exit_. - -See <> for more information. - -查阅 <> 了解更多. - -An exit criterion is visualized as a diamond shape (white color inside) on the border of a plan item: - -出口哨兵被看作一个菱形(内部黑色),位于计划项边界上: - -image::images/cmmn.exitcriteria.png[align="center"] - -==== Event Listeners - -==== Event Listeners 事件监听器 - -===== Timer Event Listener - -===== Timer Event Listener 计时器事件监听器 - -A timer event listener is used when the passing of time needs to be captured in a case model. - -计时器事件监听器在一个case模型中被用作捕获时间的传递. - - -A timer event listener is not a task and has a simpler plan item lifecycle compared to a _task_: the timer will simply move from _available_ to _completed_ when the event (in this case, the time passing) occurs. - -计时器事件监听器不是一个任务, 相比于任务, 拥有更简单的生命周期: 当一个事件(比如, 时间传递)发生时, 计时器简单从可用 _available_ 状态变成完成 _completed_ 状态. - - -Properties: - -属性: - -* *Timer expression*: an expression that defines when the timer should occur. The following options are possible: -* *Timer expression*: 表达式定义计时器何时发生. 以下是可能的使用配置: - -** An expression resolving to a java.util.Date or org.joda.time.DateTime instance (for example, _${someBean.calculateNextDate(someCaseInstanceVariable)}) -** 表达式被解析成 a java.util.Date or org.joda.time.DateTime instance (例如, _${someBean.calculateNextDate(someCaseInstanceVariable)}_) - -** An ISO8601 date -** ISO8601 格式日期 - -** An ISO8601 duration String (for example, _PT5H_, indicating the timer should fire in 5 hours from instantiation) -** ISO8601 格式 持续String (例如, _PT5H_, 表示计时器应在实例化后5小时启动) - -** AN ISO8601 repetition String (for example, R5/PT2H, indicating the timer should fire 5 times, each time waiting 2 hours) -** ISO8601 循环时间周期 (例如, R5/PT2H, 表示总共触发5次, 每次间隔2小时) - -** A String containing a cron expression -** cron表达式指定 - -* *Start trigger plan item/event*: reference to a plan item in the case model that triggers the start of the timer event listener -* *Start trigger plan item/event*: 引用case模型中计划项, 用来触发计时器事件监听器的开始. - -Note that setting a _start trigger_ for the timer event listener does not have a visual indicator in the case model, unlike entry/exit criteria on sentries. - -注意 设置计时器事件监听器的 _start trigger_ 属性在case 模型中没有可视化指示, 不像入口/出口哨兵的凭证. - -A timer event listener is visualized as circle with a clock icon inside: - -计时器事件监听器看作一个圆, 里面有一个钟表图标: - - -image::images/cmmn.timereventlistener.png[align="center"] - -===== User Event Listener - -===== User Event Listener 用户事件监听器 - -A user event listener can be used when needing to capture a user interaction that directly influences a case state, -instead of indirectly via impacting variables or information in the case. -A typical use case for a user event listener are buttons in a UI that a user can click to drive the state of the case instance. -When the event is triggered an _Occur_ event is thrown to which sentries can listener to. -Like timer event listeners, it has a much simpler lifecycle that a _task_. - -一个用户事件监听器被用作捕获一个直接影响案例状态而不是间接影响变量或者案例信息的用户交互. 一个典型的例子就是界面的按钮,用户点击后改变case实例的状态. -当 事件被触发, _Occur_ event会被抛出, 并且被哨兵所捕获. 类似计时器事件监听器, 相比任务,它也有一个更为简单的生命周期. - - -image::images/cmmn.usereventlistener.png[align="center"] - -User event listeners can be queried using the _org.flowable.cmmn.api.runtime.UserEventListenerInstanceQuery_. Such a query can be created by calling the _cmmnRuntimeService.createUserEventListenerInstanceQuery()_ method. Note that a user event listener is also a plan item instance, which means it can also be queried through the _org.flowable.cmmn.api.runtime.PlanItemInstanceQuery_ API. - -用户事件监听器可以使用 _org.flowable.cmmn.api.runtime.UserEventListenerInstanceQuery_ 查询. 类似调用 the _cmmnRuntimeService.createUserEventListenerInstanceQuery()_ 方法. -注意:也是一个计划项实例, 意味着也可以通过 the _org.flowable.cmmn.api.runtime.PlanItemInstanceQuery_ API 查询. - -A user event listener can be completed by calling the _cmmnRuntimeService.completeUserEventListenerInstance(id)_ method. - -用户事件监听器可以通过调用 _cmmnRuntimeService.completeUserEventListenerInstance(id)_ 方法来完成. - -===== Generic Event Listener - -===== Generic Event Listener 一般事件监听器 - -A generic event listener is used to typically model a programmatic interaction (e.g. a external system that calls out to change something in a case instance). - -一般事件监听器通常被用作编程交互建模(例如, 一个外部系统在一个case实例中调用来更改某些东西) - -image::images/cmmn.generic-event-listener.png[align="center"] - -The API to retrieve and complete these event listeners is on the _CmmnRuntimeService_: - -通过 _CmmnRuntimeService_ 来获取和完成这些事件监听器 - - -[source,java,linenums] ----- -GenericEventListenerInstanceQuery createGenericEventListenerInstanceQuery(); -void completeGenericEventListenerInstance(String genericEventListenerInstanceId); ----- - -Similar to _user event listeners_, this API is a wrapper on top of the _PlanItemInstance_ queries and operations. This means that the data can also be retrieved through the regular _PlanItemInstanceQuery_ - -和 _user event listeners_ 类似, 这个 API 是 _PlanItemInstance_ 查询和操作顶部的包装. 这意味着数据也可以从 _PlanItemInstanceQuery_ 获取. - -Note that generic event listeners are not part of the CMMN specification, but are a Flowable-specific addition. - -注意 一般事件监听器不是 CMMN 规范的内容, 而是 Flowable-规范 的补充 - - -===== Automatic removal of event listeners - -===== Automatic removal of event listeners 自动移除事件监听器 - -The engine will automatically detect when event listeners (user or timer) are not useful anymore. -Take for example the following case definition: - -引擎会自动监测不再使用的事件监听器(用户或者定时器), 例如下面的case定义: - -image::images/cmmn.user-event-listener-removal-1.png[align="center"] - -Here, the _First stage_ contains two human tasks (A and B) and it can be exited by a user when the _Stop first stage_ user event is triggered. -However, when both tasks A and B are completed, the stage will also complete. If now the user event listener would be triggered, there is nothing that listens to this event anymore. -The engine will detect this and terminate the user event automatically. - -这里, 第一个阶段,包含两个人工任务(A 和 B), 并且当停止第一个阶段事件被触发, 该阶段会被终止. 然而, 当 A 和 B 都完成后, 该阶段stage 也会完成. -如果这个时候触发用户事件监听器, 将会不起任何作用. 此时引擎将会检测到,并自动决定该用户事件. - -The same mechanism also works for event listeners that are referenced by entry sentries: - -相同的原理, 适用于两个入口哨兵的监听器场景: - -image::images/cmmn.user-event-listener-removal-2.png[align="center"] - -In this case, in the case that _EventListenerA_ would be triggered, _EventListenerB_ is terminated (as nothing is listening to its occurrence anymore). - -在这种场景, 如果 _EventListenerA_ 被触发, _EventListenerB_ 会终止(因为没有任何在监听B的发生) - -Or, when timer and user event listeners are mixed, the one that is triggered first will also cause the removal of others (when they are not referenced somewhere else): - -或者, 当定时器和用户事件监听器被混合使用, 首先被触发的一个会造成其他的移除(当他们没有被别的地方引用) - -image::images/cmmn.user-event-listener-removal-3.png[align="center"] - -Here, the timer will be removed in case the user event is triggered first (and vice versa). - -这里, 定时器会被移除, 如果用户件事监听首先被触发.(反之亦然) - -The detection also takes in account plan items that have not yet been created. Take for example the following case definition: - -检测还考虑到尚未创建的计划项.如下图所示: - -image::images/cmmn.user-event-listener-removal-4.png[align="center"] - -Here, human task _C_ is not yet created when a case instance is started for this case definition. The user event listener will not be removed as long that _C_ has a parent stage that is in a non-terminal state, as this means that the event could still be listened to in the future. - -这里, 当case 实例启动后, 人工任务C还未被创建. 只要C具有处于非终止 non-terminal 状态的父级,就不会删除用户事件监听器.这意味着该事件可以在未来依然被监听 - -===== Available condition -===== Available condition 可用条件 - -All types of event listeners can be configured to have a *available condition*: an expressions that will guard the available state of the event listener. To explain the use case, take the following case definition: - -所有类型的事件监听器都拥有一个 *available condition*: 一个表达式用来维护事件监听器的可用状态. - -image::images/cmmn.create-condition.png[align="center"] - -When the case instance is started, Stage 1 (as it has no entry criteria) will be moving immediately from _available_ to _active_. Similar story for human task A. Human task B will move from _available_ to _enabled_ as it's manually activated. - -当 case实例启动后, stage 1 (没有入口凭证)将立即从可用状态变成活跃状态. 人工任务A类似. 手动激活人工任务B, 它的状态从 _available_ to _enabled_. - -Normally, also the event listener would become _available_. The life cycle of event listeners is simpler than that of plan items such as human tasks: an event listener stays in the _available_ state until the event happens. There's no _active_ state like for other plan items. -This means that a user could trigger it after start and the stage would be exited. - -正常来讲, 事件监听器状态也会变成 _available_. 事件监听器的生命周期比其他计划项(比如人工任务)简单: 事件监听器保持可用状态, 直到事件发生. 这里没有类似其他计划项一样拥有活跃状态, -这意味着 一个用户可以在开始之后触发它, 然后stage将会退出. - -In some use case however, the event listener shouldn't be _available_ for the user to interact with (or a timer shouldn't start, when using a timer event listener) unless a certain condition is true. - -在一些场景中,除非一个明确满足true的条件, 否则事件监听器不应该可供用户交互(或者当使用定时器监听时, 一个定时器不应该开始) . - -In the example above, we want to only create it when the stage doesn't have any active children (or required) anymore. Setting the *availableCondition* to *${cmmn:isStageCompletable()}* will allow the event listener to be created which makes it move immediately to _available_. Concretely in this model, when human task A is completed Stage 1 becomes _completable_ (as human task B is manually activated and non-required). This makes the _availableCondition_ of the event listener _true_ and the event listener is now available for a user to decide to exit the stage. - -在上述例子中, 我们想要只在该阶段没有任何活跃元素时创建它. 设置 *availableCondition* to *${cmmn:isStageCompletable()}* 将允许事件监听器被创建, 使得它状态立即变成可用. -在这个模型中具体讲, 当人工任务 A 完成, stage 1 变成可完成(因为人工任务B是手动激活的,并且不是必需的)。这使得事件监听器的可用条件变为true, 同时用户也可以决定是否退出该阶段. - -Note: this is a Flowable specific addition to the CMMN specification. Without this addition, the event listener would have to be nested within a substage which is protected with entry criteria that listens to the completion of task A. - -注意: 这是一个 Flowable 规范对CMMN规范的特定添加.如果没有此添加,则事件监听器将必须嵌套在子阶段中,该子阶段受入口凭证监听任务 A 完成的保护。 - -Note: if this were an autocompletable stage, the engine would complete the stage automatically when A completes. - -注意: 如果是一个可以自动完成的阶段stage, 引擎在A完成时, 自动完成该阶段stage. - -==== Item control: Repetition Rule - -==== Item control: Repetition Rule 条目控制: 重复规则 - -Plan items on the case model can have a _repetition rule_: an expression that can be used to indicate a certain plan item needs to be repeated. -When no expression is set, but the repetition is enabled (for example, the checkbox is checked in the Flowable Modeler) or the expression is empty, a _true_ value is assumed by default. - -案例模型中的计划项可以具有重复规则 _repetition rule_ :一个表达式,可用于指示某个计划项目需要重复。 -如果未设置表达式,但启用了重复(例如,在 _Flowable Modeler_ 模型设计器中勾选了复选框)或表达式为空,则默认为 _true_。 - -An optional _repetition counter variable_ can be set, which holds the index (one-based) of the instance. If not set, the default variable name is _repeitionCounter_. - -可以设置一个可选的 _repetition counter variable_属性,它将保存一个实例对应的索引(从1开始). 如果未设置,默认的变量名为 _repeitionCounter_. - -If the plan item does not have any entry criteria, the repetition rule expression is evaluated when the plan item is completed or terminated. If the expression resolved to _true_, a new instance is created. For example, a human task with a repetition rule expression _${repetitionCounter < 3}_, will create three sequential human tasks. - -如果一个计划项没有设置入口凭证, 当它完成或则停止时,重复准则表达式都会计算. 如果解析为true, 则创建一个新的实例. 例如, 一个人工人有表达式 _${repetitionCounter < 3}_, 将会创建3个有序的人工任务. - -If the plan item has entry criteria, the behavior is different. The repetition rule is not evaluated on completion or termination, but when a sentry of the plan item is satisfied. If both the sentry is satisfied and the repetition rule evaluates to true, a new instance is created. - -如果计划项有设置入口凭证, 表现是不同的. 当完成或中止时, 重复规则不会计算. 只有满足哨兵的条件才会计算.如果同时满足哨兵条件并且重复准则计算为true, 一个新的实例才会被创建. - -Take, for example, the following timer event listener followed by a human task. The sentry has one entry criterion for the _occur_ event of the timer event listener. Note that enabling and setting the repetition rule on the task has a visual indicator at the bottom of the rectangle. - -例如,下面的计时器事件监听器后面跟着一个人工任务。哨兵对于计时器事件监听器的发生事件有一个入口凭证。注意,在任务上启用和设置重复规则都会在矩形底部有一个可视指示器。 - -image::images/cmmn.repeatingtimereventlistener.png[align="center"] - -If the timer event listener is repeating (for example, _R/PT1H_), the _occur_ event will be fired every hour. When the repetition rule expression of the human task evaluates to true, a new human task instance will be created each hour. - -如果定时器事件监听器是可重复的(例如, _R/PT1H_), 每间隔1小时,发生事件 _occur_ event 会被触发. 当人工任务的重复准则计算为true, 每隔1小时,一个新的人工任务实例会被创建. - -Note that Flowable allows to have repeating user and generic event listeners. This is contrary to the CMMN specification (which disallows it), but we believe it is needed for having a more flexible way of using event listeners (for example to model a case where a user might multiple times trigger an action that leads to the creation of tasks). - -注意, Flowable 允许拥有可重复的用户和一般事件监听器. 这和 CMMN 准则是相反的. 但是我们相信拥有一个更加灵活的方式使用时间监听器是需要的(例如在一个用户需要多次触发一个动作来创建人物的案例模型) - -==== Item control: Manual Activation Rule - -==== Item control: Manual Activation Rule 条目控制: 手动激活准则 - -Plan items on the case model can have a _manual activation rule_: an expression that can be used to indicate a certain plan item needs to be _manually activated by an end-user_. -When no expression is set, but the manual activation is enabled (for example, the checkbox is checked in the Flowable Modeler) or the expression is empty, a _true_ value is assumed by default. - -案例模型中的计划项可以拥有一个手动激活准则: 一个表达式被提供给终端用户手动激活一个确定的计划项. 当未设置任何表达式, 但是启用了手动激活(例如, Flowable Modeler 中的复选框被选中) -或者表达式为空, 默认值为true. - -Stages and all task types can be marked for manual activation. Visually, the task or stage will get a 'play' icon (small triangle pointing to the right) to indicate an end-user will have to manually activate it: - -阶段stage 和所有类型任务都可以设置手动激活. 可视化地, 任务或者阶段stage 将会有一个 播放图标 'play' icon(一个指向右侧的小三角形),指明用户需要手动去激活它. - -image::images/cmmn.manual-activation.png[align="center"] - -Normally, when a sentry for a plan item is satisfied (or the plan item doesn't have any sentries) the plan item instance is automatically moved to the _ACTIVE_ state. When a manual activation is set though, and it evaluates to true, the plan item instance now becomes _ENABLED_ instead of _ACTIVE_. As the name implies, the idea behind this is that end-users manually have to activate the plan item instance. A typical use case is showing a list of buttons of potential plan item instances that can currently be started by the end user. - -正常来讲, 当一个计划项的哨兵条件得到满足(或者没有任何哨兵), 计划项将自动转为活跃状态 _ACTIVE_. 当设置了手动激活,并且计算结果为true,计划项从活跃状态 _ACTIVE_ 变为已启用状态 _ENABLED_. 正如名称所示, 背后的想法就是指终端用户需要手动激活计划项. -一个典型的用例就是一个潜在计划项实例的按钮列表.而这些按钮目前可以由最终用户启动. - - -为了启动一个可启动的计划项实例, 可以使用 _CmmnRuntimeService_ 的 _startPlanItemInstance_ 方法: - -[source,java,linenums] ----- -List enabledPlanItemInstances = cmmnRuntimeService.createPlanItemInstanceQuery() - .caseInstanceId(caseInstance.getId()) - .planItemInstanceStateEnabled() - .list(); - -// ... - -cmmnRuntimeService.startPlanItemInstance(planItemInstance.getId()); ----- - - -注意,任务的行为只在计划项实例进入活动状态时被执行。例如,对于人工任务,只有在调用 _startPlanItemInstance_ 方法之后才会创建用户任务。 - - -已启动的计划项实例可以转变为 禁用状态 _DISABLED_: - -[source,java,linenums] ----- -cmmnRuntimeService.disablePlanItemInstance(planItemInstance.getId()); ----- - -Disabled plan item instances can be enabled again: - -禁用的计划项也可以重新被启动: - -[source,java,linenums] ----- -cmmnRuntimeService.enablePlanItemInstance(planItemInstance.getId()); ----- - - -注意, 在决定阶段或案例实例终止时,禁用状态 _DISABLED_ 被视为“终端”状态. 这意味着当只有禁用的计划项实例存在,案例实例将终止. - -==== Item control: Required Rule - - - -案例模型中的计划项可以拥有一个要求准则 _required rule_: 一个表达式被用作被外部stage 或者案例模型要求执行的一个计划项.这可以用来表明案例模型中的计划项哪些是必须的,哪些是可选的. - - -当未设置任何表达式, 但是启用了 _required rule_ (例如, Flowable Modeler 中的复选框被选中)或者表达式为空, 默认值为true. - - -_required rule_ 与 父类 stage的 _autoComplete_ 属性一起使用: -* 如果 _autoComplete_ 为 _false_, 这个也是默认值, *all* 所有子计划项实例必须处于最终状态(完成、终止,等等), 以便由引擎完成阶段计划项实例. - -* 如果 _autoComplete_ 为 _true_, 需要所有要求准则计算为true的子计划项实例进入最终状态. 如果这没有其他处于活跃状态的子元素, 父类阶段 stage 将自动完成. - - -阶段stage 拥有一个 *completeable* 属性来用作表示当前条件是否得到满足来完成该stage. 例如, 下面的简单阶段stage, 假设一个哨兵的条件为true, 另一个为false, 则意味着 -左边的计划项实例将进入活跃状态, 右侧的将进入可用状态. - -image::images/cmmn.completeable-stage.png[align="center"] - - -调用 _cmmnRuntimeService.completeStagePlanItemInstance(String stagePlanItemInstanceId)_ 完成当前stage是不可能的(抛出异常), -因为有一个活跃状态的子元素存在. 当左侧的用户任务完成, 因为当前没有子元素活跃, _completeStagePlanItemInstance_ 会被调用. -但是对于它自身, 阶段stage 不会自动完成, 因为右边的用户任务还处于可用状态. - - -如果上面的阶段stage 设置为 *autoCompleteable* (在底部有一个黑色的小矩形), 右边的计划项设置为必须的(有一个可见的感叹号标记), 表现会不同: - -image::images/cmmn.completeable-stage02.png[align="center"] - -* 如果左边计划项实例是活跃(哨兵为true), 右边不是(哨兵为false). 这种情况下, 当左边任务完成后, stage 实例将会自动完成并且所有必须的计划项实例进入最终状态. - -* 如果左右俩个任务都是活跃状态(哨兵都为true) - -** 当左边任务完成后, 因为右边实例还处于活跃zhuangt, 当前阶段stage 不会自动完成. - -** 当右边任务完成后, 因为左边必须的任务不是出于最终状态(活跃), 当前阶段 stage不会自动完成. - -* 如果左边任务不是活跃状态, 右边出于活跃. 这种情况下, 当右边任务完成后, 当前阶段stage 不会自动完成, 因为左边必须的任务不是出于一个最终状态. 只有左边任务出于活跃并且完成后, 才能完成当前阶段 stage. - - -注意, 手动激活规则独立于要求准则. 例如, 以下阶段stage: - -image::images/cmmn.completeable-stage03.png[align="center"] - - -这里, 用户任务D是必须的, 任务B是需要手动激活. - -* 如果D完成, 当前stage将自动完成. 因为B不是必须的并且不是活跃状态. - -* 如果B也是必须的, 即使D已经完成, 还是需要手动激活B(调用 _cmmnRuntimeService.startPlanItemInstance(String planItemInstanceId)_), 然后当前阶段stage 才能自动完成. - -==== Item control: Completion Neutral Rule - - - -案例模型中的计划项可以拥有一个中立完成准则 _completion neutral rule_: 一个表达式被用作对于完成父类stage 或者案例模型, 一个计划项是中立的(非必须). -这可以用来表明案例模型中的计划项哪些是必须的,哪些是可选的. 相比在某些时候使用 required rule 和 autoComplete, 会更加灵活. - - -注意, 中立完成准则 _Completion Neutral Rule_ 不是 CMMN 1.1规范, 是 Flowable 规范的补充. - - -依照规范, 出于 *AVAILABLE* 可用状态的阶段 stage 不能被完成, 除非 _autoComplete_ 属性为true, 并且计划项不是必须的. 例如, 一个计划项保持可用 *AVAILABLE* 状态, 哨兵条件未满足. 这意味 -除非计划项被标记为非必须,并且 父类 stage 设置 _autoComplete_, 否则 父类stage 不会完成. 缺点是, 一旦一个阶段被标记为自动完成,所有子计划项目都需要为所需的规则进行配置, 这在某些用例中是冗长和繁重的工作 - - -中立完成准则 _Completion Neutral Rule_, 与 autoComplete-required 机制相反,完成中立规则从“自底向上”工作:一个计划项目可以单独标记为中立,而无需标记任何其他计划项目. - - -当计划项都计算为true, _Required Rule_ 优先. - -To summarize: -总结: - -* 一个计划项设置为 _"completion neutral"_, 如果他出于活跃 *AVAILABLE* 状态(等待一个入口哨兵凭证), 将允许 父类stage 自动完成. 这意味着一个计划项目相对于它的父阶段完成评估是中立的. - -* 在以下条件中, 一个 stage 会保持活跃 *ACTIVE* 状态: - - 1. 它拥有至少一个出于活跃状态的计划项 - 2. 它拥有至少一个带有 _requiredRule_ , 处于可用 *AVAILABLE* 或者 启用 *ENABLE* 状态的计划项. - 3. 它没有被标记为 _autoComplete_, 拥有至少一个 计划项处于 启用 *ENABLED* 状态 (不管 必须准则 _requiredRule_) - 4. 它没有被标记为 _autoComplete_, 拥有至少一个 计划项处于 可用 *AVAILABLE* 状态并且 不是 完成中立 _completionNeutral_ - -* 一个阶段 将会完成: - - 1. 它不包含子元素, 或者所有子计划项 都是处于 一个 终止 _Terminal_ 或者 半终止 _Semi-terminal_ 状态 (关闭, 完成, 禁用, 失败) - 2. 它没有标记为 _autoComplete_ 且所有存在的子计划项处于 可用 *AVAILABLE* 状态, 并且是 完成中立 _completionNeutral_ ,而不是必须的 - 3. 它标记为 _autoComplete_ 且所有子计划项非必须 _not required_, 处于 已启用 *ENABLED* 或者 可用 *AVAILABLE* 状态. (不管 完成中立 _completionNeutral_, 要求准则优先) - -[[cmmn_sentry_evaluation]] -=== Sentry evaluation - -=== 哨兵计算 - - -在任何案例定义中, 哨兵扮演一个重要的角色. 它们提供了一个强大的声明式配置方式来激活正确的计划项或者自动停止.因此,Flowable CMMN 引擎核心逻辑最重要的部分之一是计算哨兵,以查看在一个案例实例中发生了什么状态更改。 - - -==== 什么时候计算哨兵? - - -在任何状态发生改变或者新事件发生,具体地说,这意味着: - -* 当一个案例实例启动. - -* 当一个等待状态的计划项被触发继续.(比如人工任务) - -* 当案例实例相关变量发生改变(新增, 修改, 或删除) - -*当计划项实例状态改变(比如 通过 RuntimeService 停止, 一个手动计划项启动,等等) - -* 当RuntimeService#evaluateCriteria 方法手动触发. - - -伴随着状态改变的进行, 引擎会有计划地一直对当前活跃的哨兵进行计算.例如,假设一个人工任务的完成满足另一个人工任务的出口哨兵。第二个人工任务的状态更改将再次使用此新信息对所有活动哨兵进行新的评估。当最后一次评估没有发生变化时,引擎认为状态稳定,停止计算. - - -==== Concepts 概念 - - -哨兵包含两部分: - -- 与其他计划项生命周期相关的一个或者多个 _onParts_ -- 零个或者一个 if条件 - - -注意以下案例定义: - -image::images/cmmn.sentry-eval-01.png[align="center"] - -假设(上图中未展示出来) - -* 任务C的入口哨兵监听任务 A和B的完成 _complete_ 事件 -* 出口哨兵监听 用户事件监听器的发生 _occur_ 事件 _'Stop C'_ -* 入口哨兵有个表达式设置为 _${var:eq(myVar, 'hello world')}_ - -在这个简单例子中, 入口哨兵 有两个 onParts 和 一个 ifPart. 退出哨兵只有一个 onPart. - - -当案例实例启动后, 人工任务A和B被创建(他们没有入口哨兵), 很快进入活跃 _active_ 状态. C因为入口哨兵条件不满足, 处于可用 _available_ 状态. 用户事件监听器“Stop C”从一开始就可用,因此可以被触发. - - -当任务A和B都完成并且变量 _myVar_ 设置为 _'hello world'_, 入口哨兵条件满足并且触发. C后面的计划项实例被移动到active状态, 同时,人工任务C被创建(例如,现在可以通过 _TaskService_ 查询它). -当'Stop C'被触发(通过 _CmmnRuntimeService#completeUserEventListenerInstance_ 方法),出口哨兵条件满足, C被中止. - - -如果 _'Stop C'_ 在 C变成活跃 _active_ 状态前被触发, 它的计划项实例将被中止, 出口哨兵也将不再监听任何. - - -==== 默认行为 - - -当一个案例实例启动后 - ----- -CaseInstance caseInstance = cmmnRuntimeService.createCaseInstanceBuilder() - .caseDefinitionKey("myCase") - .start(); ----- - - -入口哨兵条件会立即被计算, 因此当案例实例启动会有一个有序的循环计算. - - -注意, 如果使用像_${myVar == 'hello world'}_ 条件表达式不会起作用. 引擎会抛出 PropertyNotFound 异常, 因为它不知道 变量myVar. - -为了解决上述问题: - - * 在启动时传一个 _myVar_ 变量 - * 做一个非空校验, 类似 _${planItemInstance.getVariable('myVar') != null && planItemInstance.getVariable('myVar') == 'hello world'}_ - * 或者更简单地, 使用 表达式函数 <> , 类似 _${var:eq(myVar, 'hello world')}_ 考虑到变量可能不存在的情况 - - -*默认的计算逻辑有“缓存”,这意味着当哨兵的一部分条件得到满足时,引擎将存储并在随后的计算中并"记住"这个值.* - - -这意味着, 从某一部分(onPart或ifPart of the sentry)得到满足的那一刻起, 该特定部分在下一次评估中不再被评估, 而是被认为是正确的. - - -在上述例子中,这是任务A相对于B通常会在另一个时间点完成。例如,如果任务A完成后,任务C哨兵的一部分说“我监听任务A完成“得到满意,这事实上为将来被缓存。如果现在B完成了, -它也被存储。如果 _myVar_ 变量得到正确的值,ifPart也会触发,整个岗兵和任务C也会被激活。当然,也可以先满足变量值,然后再满足任务. 关键是这并不重要,因为引擎会保存之前满足的部分条件 - - -这是流程引擎的默认行为, 可以设置 哨兵 _triggerMode_ 为 *default* 覆盖. 在Flowable Modeler 中增加一个新计划项时自动被设置. -当不设置(例如从另一个工具导入模型)时, _triggerMode_ 默认是 *default*. - - -==== Trigger mode "onEvent" 事件触发模式 - - -默认行为(查看前面部分)是保存先前被满足的部分. 这是最常用和最安全的方法(也是对哨兵进行推理时通常期望的方法). - - -另一种哨兵触发模式称为“onEvent”。在这种模式下,引擎将有关于哨兵的部分保存,不会保存*not remember*过去满足的任何部分。这在高级用例中有时是需要的。以下面的例子为例: - -image::images/cmmn.sentry-eval-02.png[align="center"] - - -这里, 案例模型是一个有三个子阶段stage. 所有子阶段都可以重复. 子阶段B和C有一个入口哨兵用来等待阶段A的完成. 同理(未展示出来), 两个哨兵都有一个变量的依赖条件. - - -在高级用例中, 可能想要或需要哨兵部分(特别是包含条件的ifPart)仅在相关计划项的生命周期事件发生时才进行计算。在本例中,正是Stage A的完成事件。 -对于这些用例,可以将哨兵的 _triggerMode_ 设置为onEvent。顾名思义,这意味着哨兵的计算只在引用事件发生时发生,而不考虑对过去事件的缓存。 - - -具体地说, 在这里的例子中,只有在阶段A完成时(而不是在其他时刻)才会计算入口哨兵的情况. 这与一般的评价规则有很大的不同. -在这个特殊的例子中,它确实使管理变量变得更容易, 因为条件只在一个精确的时刻进行评估,并且不需要担心由于某个变量在某个时间点的具体值而触发某个哨兵的部分. -特别是在本例中,所有子阶段都在重复,这需要做很多工作。这是一种功能强大的机制,但对于高级建模人员来说,这意味着他们对案例模型和这种 _triggerMode_ 的语义具有内在的知识. - - -注意,在计算哨兵时,引擎认为所有的事件都是同时发生的。以下面的案例定义为例: - -image::images/cmmn.sentry-eval-03.png[align="center"] - - -假设所有的哨兵使用 _triggerMode onEvent_ 的设置. 如果任务A完成, 这会使任务B退出, 任务C也会退出. 所以,即使有两种截然不同的生命周期事件(A被完成和B被退出),人们可能会认为 _onEvent_ 的字面意思是, -有两种截然不同的计算发生, 而另一部分C的退出哨兵的缓存被忘记.引擎足够聪明地看到,他们是相同的计算周期且任务C也将退出. - - -从技术上讲: _onEvent_ 哨兵存在缓存,更具体地说,是用于在同一API调用(或事务,简单地说)期间发生的计算. - - -*Important* onEvent是一种功能强大的机制,只有当很好地理解语义时才应该使用它。如果不仔细检查用例,可能会创建由于没有正确的配置哨兵而卡住的用例模型。 - - -(例如, 假设一个哨兵有一个onPart监听一个计划项的完成情况,还有一个带有条件的ifPart。如果计划项完成, 从而触发onPart, 但是由于某种原因缺少了条件中使用的变量…… ifPart将永远不会触发,case实例可能会陷在一个不想要的状态). \ No newline at end of file diff --git a/docs/userguide/src/zh_CN/cmmn/ch07-architecture.adoc b/docs/userguide/src/zh_CN/cmmn/ch07-architecture.adoc deleted file mode 100755 index 4b159a79245..00000000000 --- a/docs/userguide/src/zh_CN/cmmn/ch07-architecture.adoc +++ /dev/null @@ -1,80 +0,0 @@ - -== 体系结构 - -[[architecture]] - -本章从高层次的角度简要介绍了CMMN引擎的内部结构。当然,由于CMMN引擎代码是开源的,因此可以通过深入了解源代码来找到实际的实现细节。 - -如下图所示,CMMN引擎是Flowable引擎生态系统的一部分,其设计方式与其他引擎类似。CMMN引擎基于CMMN特定服务和共享服务构建:任务,变量,身份和作业服务,它们独立于引擎。 在较低级别,实体和数据管理器层负责低级别持久性,相当于其他引擎。 - -image::images/cmmn.architecture.png[align="center"] - -通过使用共享服务,这也意味着例如来自BPMN和CMMN引擎的任务将最终结合在一起,并且可以通过相同的API查询和管理。类似地,对于异步执行器:定时器和异步作业使用相同的逻辑,甚至可以由中央执行器管理。 - -共享服务架构有第二个好处。通常情况下,当引擎一起使用时,引擎将尽可能共享资源,数据库事务将跨越多个引擎操作的调用,查找缓存是常见的,并且持久性是独立于引擎本身处理的。 - -CMMN引擎的设计原理与Flowable项目的其他引擎相同。下图给出了使用CMMN引擎时涉及的不同组件的高级概述: - -image::images/cmmn.api-call-flow.png[align="center"] - -从高层次来看: - -一个**CmmnEngine**实例是从**CmmnEngineConfiguration**创建的。可以从配置文件或以编程方式创建配置实例。 - -__CmmnEngine__以服务的形式提供对Flowable CMMN API的访问:**CmmnRepositoryService**、**CmmnRuntimeService**、**CmmnTaskService**、**CmmnHistoryService**、**CmmnManagementService**。服务的命名及其职责与其他引擎类似。 - -每个API方法都转换为**Command**实例,此__Command__实例传递给**CommandExecutor**,其中包括使一些**CommandInterceptors**。这些拦截器具有各种职责,包括处理事务。 - -最终,__Command__通常(除非是纯数据修改__Command__)在**CmmnEngineAgenda**上计划**CmmnOperation**。 - -操作将从__CmmnEngineAgenda__中获取,直到不再进行操作为止。通常,操作将计划新操作作为其逻辑的一部分。 - -操作中的逻辑将调用较低级别的服务和/或实体管理器。 - -BPMN和CMMN引擎之间的一个很大区别是BPMN引擎通常是“本地的”:引擎查看当前状态,检查进程中的前面的信息并继续(当然这是一个简化,这有很多不适用的操作,但从概念上做出区分,这是正确的)。CMMN引擎的工作方式不同:在CMMN中,数据起着重要作用,数据的更改可以在案例定义中的各个位置触发很多事情。因此,只要发生更改,就会经常计划和执行**EvaluateCriteriaOperation**。当检测到重复或无用的评估时,引擎会对这些评估进行优化。 - -CMMN引擎工作的核心是计划项目实例的概念,表示当前在案例中存在哪些**计划实例项**以及它们具有哪种状态。与BPMN完全不同,CMMN为__计划项__定义了严格的状态__生命周期__。这在__CmmnRuntimeService__方法,查询API和**PlanItemInstance**对象的数据字段部分中表示。 - -可以通过将日志记录设置为议程包的调试来检查议程的工作,操作以及如何处理计划项实例。例如,使用log4j时: - -``` -log4j.logger.org.flowable.cmmn.engine.impl.agenda=DEBUG -``` - -这样记录的信息如下: - -``` -Planned [Init Plan Model] initializing plan model for case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 -Planned [Change PlanItem state] Task A (id: planItemTaskA), new state: [available] with transition [create] -Planned [Change PlanItem state] PlanItem Milestone One (id: planItemMileStoneOne), new state: [available] with transition [create] -Planned [Change PlanItem state] Task B (id: planItemTaskB), new state: [available] with transition [create] -Planned [Change PlanItem state] PlanItem Milestone Two (id: planItemMileStoneTwo), new state: [available] with transition [create] -Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 -Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 with transition 'create' having fired for plan item planItemTaskA (Task A) -Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 with transition 'create' having fired for plan item planItemMileStoneOne (PlanItem Milestone One) -Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 with transition 'create' having fired for plan item planItemTaskB (Task B) -Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 with transition 'create' having fired for plan item planItemMileStoneTwo (PlanItem Milestone Two) -Planned [Activate PlanItem] Task A (planItemTaskA) -Planned [Change PlanItem state] Task A (id: planItemTaskA), new state: [active] with transition [start] -Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 with transition 'start' having fired for plan item planItemTaskA (Task A) -Planned [Change PlanItem state] Task A (id: planItemTaskA), new state: [completed] with transition [complete] -Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 with transition 'complete' having fired for plan item planItemTaskA (Task A) -Planned [Activate PlanItem] PlanItem Milestone One (planItemMileStoneOne) -Planned [Change PlanItem state] PlanItem Milestone One (id: planItemMileStoneOne), new state: [active] with transition [start] -Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 with transition 'start' having fired for plan item planItemMileStoneOne (PlanItem Milestone One) -Planned [Change PlanItem state] PlanItem Milestone One (id: planItemMileStoneOne), new state: [completed] with transition [occur] -Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 with transition 'occur' having fired for plan item planItemMileStoneOne (PlanItem Milestone One) -Planned [Activate PlanItem] Task B (planItemTaskB) -Planned [Change PlanItem state] Task B (id: planItemTaskB), new state: [active] with transition [start] -Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 with transition 'start' having fired for plan item planItemTaskB (Task B) -Planned [Change PlanItem state] Task B (id: planItemTaskB), new state: [completed] with transition [complete] -Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 with transition 'complete' having fired for plan item planItemTaskB (Task B) -Planned [Activate PlanItem] PlanItem Milestone Two (planItemMileStoneTwo) -Planned [Change PlanItem state] PlanItem Milestone Two (id: planItemMileStoneTwo), new state: [active] with transition [start] -Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 with transition 'start' having fired for plan item planItemMileStoneTwo (PlanItem Milestone Two) -Planned [Change PlanItem state] PlanItem Milestone Two (id: planItemMileStoneTwo), new state: [completed] with transition [occur] -Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 with transition 'occur' having fired for plan item planItemMileStoneTwo (PlanItem Milestone Two) -Planned [Evaluate Criteria] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 -No active plan items found for plan model, completing case instance -Planned [Complete case instance] case instance bfaf0e64-eaf4-11e7-b9d0-acde48001122 -``` diff --git a/docs/userguide/src/zh_CN/cmmn/generate-html.sh b/docs/userguide/src/zh_CN/cmmn/generate-html.sh deleted file mode 100755 index 51dc2ce7d04..00000000000 --- a/docs/userguide/src/zh_CN/cmmn/generate-html.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -asciidoctor -a stylesheet=../base/flowable.css -o output/index.html index-html.adoc - -rm -rf output/images -mkdir output/images -cp -r images output - -## Copy Base Images -cp -r ../base/images output \ No newline at end of file diff --git a/docs/userguide/src/zh_CN/cmmn/generate-pdf.sh b/docs/userguide/src/zh_CN/cmmn/generate-pdf.sh deleted file mode 100755 index 4f222a0d514..00000000000 --- a/docs/userguide/src/zh_CN/cmmn/generate-pdf.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -rm -rf output/flowable-cmmn-userguide.pdf -asciidoctor-pdf -o output/flowable-cmmn-userguide.pdf index-pdf.adoc diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn-basic-concepts.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn-basic-concepts.png deleted file mode 100755 index ff47c010a32..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn-basic-concepts.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.api-call-flow.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.api-call-flow.png deleted file mode 100755 index 358b291b828..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.api-call-flow.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.architecture.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.architecture.png deleted file mode 100755 index 88dab4e1db4..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.architecture.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.casetask.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.casetask.png deleted file mode 100755 index f28aeb90be9..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.casetask.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.completeable-stage.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.completeable-stage.png deleted file mode 100755 index 82eefd02135..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.completeable-stage.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.completeable-stage02.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.completeable-stage02.png deleted file mode 100755 index 7b931953bd8..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.completeable-stage02.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.completeable-stage03.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.completeable-stage03.png deleted file mode 100755 index 649b7ff3bc1..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.completeable-stage03.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.create-condition.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.create-condition.png deleted file mode 100644 index f2b4553e205..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.create-condition.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.decisiontask.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.decisiontask.png deleted file mode 100755 index 5f9dd2b3781..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.decisiontask.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.entrycriteria.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.entrycriteria.png deleted file mode 100755 index 40d5aa8b84d..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.entrycriteria.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.exitcriteria.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.exitcriteria.png deleted file mode 100755 index 2f70f743387..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.exitcriteria.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.expression-functions.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.expression-functions.png deleted file mode 100644 index 426b40c3a1a..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.expression-functions.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.generic-event-listener.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.generic-event-listener.png deleted file mode 100644 index 9f655a838f0..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.generic-event-listener.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.httptask.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.httptask.png deleted file mode 100755 index 739391dee57..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.httptask.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.humantask.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.humantask.png deleted file mode 100755 index 147345b68ca..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.humantask.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.manual-activation.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.manual-activation.png deleted file mode 100755 index 009beeba06f..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.manual-activation.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.milestone.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.milestone.png deleted file mode 100755 index 879ef725a3b..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.milestone.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.processtask.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.processtask.png deleted file mode 100755 index 5e5a8440816..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.processtask.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.programmatic.example.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.programmatic.example.png deleted file mode 100755 index 17c15d32d87..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.programmatic.example.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.repeatingtimereventlistener.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.repeatingtimereventlistener.png deleted file mode 100755 index a2361dc20a7..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.repeatingtimereventlistener.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.sentry-eval-01.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.sentry-eval-01.png deleted file mode 100644 index f46d3cf1956..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.sentry-eval-01.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.sentry-eval-02.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.sentry-eval-02.png deleted file mode 100644 index d3e9e515f63..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.sentry-eval-02.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.sentry-eval-03.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.sentry-eval-03.png deleted file mode 100644 index e3261fb250f..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.sentry-eval-03.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.servicetask.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.servicetask.png deleted file mode 100755 index 1b188335d79..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.servicetask.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.stage.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.stage.png deleted file mode 100755 index e6824e3d917..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.stage.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.task.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.task.png deleted file mode 100755 index 0de1e8c1516..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.task.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.timereventlistener.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.timereventlistener.png deleted file mode 100755 index ef59cc774d4..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.timereventlistener.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.user-event-listener-removal-1.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.user-event-listener-removal-1.png deleted file mode 100644 index 4fef6105731..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.user-event-listener-removal-1.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.user-event-listener-removal-2.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.user-event-listener-removal-2.png deleted file mode 100644 index a0e339cbe54..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.user-event-listener-removal-2.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.user-event-listener-removal-3.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.user-event-listener-removal-3.png deleted file mode 100644 index bae13eb0380..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.user-event-listener-removal-3.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.user-event-listener-removal-4.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.user-event-listener-removal-4.png deleted file mode 100644 index 87199c3000e..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.user-event-listener-removal-4.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/images/cmmn.usereventlistener.png b/docs/userguide/src/zh_CN/cmmn/images/cmmn.usereventlistener.png deleted file mode 100755 index b1b93a247bd..00000000000 Binary files a/docs/userguide/src/zh_CN/cmmn/images/cmmn.usereventlistener.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/cmmn/index-common.adoc b/docs/userguide/src/zh_CN/cmmn/index-common.adoc deleted file mode 100755 index 5b0bda8fee3..00000000000 --- a/docs/userguide/src/zh_CN/cmmn/index-common.adoc +++ /dev/null @@ -1,7 +0,0 @@ -include::ch01-Introduction.adoc[] -include::ch02-Configuration.adoc[] -include::ch03-API.adoc[] -include::ch04-Spring.adoc[] -include::ch05-Deployment.adoc[] -include::ch06-cmmn.adoc[] -include::ch07-architecture.adoc[] \ No newline at end of file diff --git a/docs/userguide/src/zh_CN/cmmn/index-html.adoc b/docs/userguide/src/zh_CN/cmmn/index-html.adoc deleted file mode 100755 index bbef008f8cd..00000000000 --- a/docs/userguide/src/zh_CN/cmmn/index-html.adoc +++ /dev/null @@ -1,15 +0,0 @@ -= Flowable CMMN 用户手册 (v 6.5.0.event-SNAPSHOT) -:doctype: book -:docinfodir: ../base -:docinfo1: header -:icons: font -:numbered: -:source-highlighter: pygments -:pygments-css: class -:pygments-linenums-mode: table -:compat-mode: -:pdf-page-size: A4 -:nofooter: - - -include::index-common.adoc[] diff --git a/docs/userguide/src/zh_CN/cmmn/index-pdf.adoc b/docs/userguide/src/zh_CN/cmmn/index-pdf.adoc deleted file mode 100755 index 752b6c45204..00000000000 --- a/docs/userguide/src/zh_CN/cmmn/index-pdf.adoc +++ /dev/null @@ -1,14 +0,0 @@ -= Flowable CMMN 用户手册 (v 6.5.0.event-SNAPSHOT) -:doctype: book -:toc: left -:toclevels: 4 -:icons: font -:numbered: -:source-highlighter: pygments -:pygments-css: class -:pygments-linenums-mode: table -:compat-mode: -:pdf-page-size: A4 -:nofooter: - -include::index-common.adoc[] diff --git a/docs/userguide/src/zh_CN/dmn/ch02-Configuration.adoc b/docs/userguide/src/zh_CN/dmn/ch02-Configuration.adoc deleted file mode 100755 index 93d2d1d3b02..00000000000 --- a/docs/userguide/src/zh_CN/dmn/ch02-Configuration.adoc +++ /dev/null @@ -1,403 +0,0 @@ - -== 配置 - -[[configuration]] - -=== 创建 DMN 引擎 - -_Flowable DMN 引擎的构造方式和 Flowable 工作流引擎非常相似。因此,部分文档非常类似流程引擎的相应内容。_ - -Flowable DMN 引擎是通过名为 +flowable.dmn.cfg.xml+ 的XML文件进行配置的。请注意,如果你使用 <>,则不适用。 - -获取一个 +DmnEngine+ 的最简单的方式是使用 +org.flowable.dmn.engine.DmnEngines+ 类: - -[source,java,linenums] ----- -DmnEngine dmnEngine = DMNEngines.getDefaultDmnEngine() ----- - -上述代码将会从classpath寻找 +flowable.dmn.cfg.xml+ 文件,并根据文件中的配置构造引擎。下面的代码片段展示了实例配置。后续章节将详细介绍配置属性。 - -[source,xml,linenums] ----- - - - - - - - - - - - - - - - - ----- - -可以注意到这个 XML 配置实际上是个 Spring 配置。 *这并不代表 Flowable DMN 只能在 Spring 环境中使用!* 我们只是在内部借助 Spring 的解析和依赖注入能力来构建引擎。 - -也可以通过编程的方式使用配置文件创建 DMNEngineConfiguration 对象。也可以使用不同的 bean ID(比如第三行)。 - -[source,java,linenums] ----- -DmnEngineConfiguration. - createDmnEngineConfigurationFromResourceDefault(); - createDmnEngineConfigurationFromResource(String resource); - createDmnEngineConfigurationFromResource(String resource, String beanName); - createDmnEngineConfigurationFromInputStream(InputStream inputStream); - createDmnEngineConfigurationFromInputStream(InputStream inputStream, String beanName); ----- - - -不使用配置文件也是可行的,这将基于默认值创建配置(更多信息请参阅 <> )。 - -[source,java,linenums] ----- -DmnEngineConfiguration.createStandaloneDmnEngineConfiguration(); -DmnEngineConfiguration.createStandaloneInMemDmnEngineConfiguration(); ----- - -所有的 +DmnEngineConfiguration.createXXX()+ 方法返回一个可做进一步调整的 +DmnEngineConfiguration+ 。调用 +buildDmnEngine()+ 方法之后将创建一个 +DmnEngine+ : - -[source,java,linenums] ----- -DmnEngine dmnEngine = DmnEngineConfiguration.createStandaloneInMemDmnEngineConfiguration() - .setDatabaseSchemaUpdate(DmnEngineConfiguration.DB_SCHEMA_UPDATE_FALSE) - .setJdbcUrl("jdbc:h2:mem:my-own-db;DB_CLOSE_DELAY=1000") - .buildDmnEngine(); ----- - -[[configurationRoot]] - - -=== DmnEngineConfiguration bean - -+flowable.dmn.cfg.xml+ 必须包含一个 ID 为 +$$'dmnEngineConfiguration'$$+ 的 bean。 - -[source,xml,linenums] ----- - ----- - - -这个 bean 将被用于构造 +DmnEngine+。有多个可选的类可以用来定义 +dmnEngineConfiguration+。这些类代表了不同的环境,并根据环境设置相应的默认值。最佳方式是选择最符合你的环境的类,尽可能地减少配置引擎所需要的属性。目前有下面这些类可供使用: [[configurationClasses]] - -* *org.flowable.dmn.engine.impl.cfg.StandaloneDmnEngineConfiguration*: 引擎以单机方式运行。Flowable 将自行处理事务。默认情况下,仅在引擎启动时检查数据库(如果 Flowable DMN 相关表不存在,或者版本不正确,将抛出异常)。 -* *org.flowable.dmn.engine.impl.cfg.StandaloneInMemDmnEngineConfiguration*: 这是一个方便进行单元测试的类。Flowable DMN 将自行处理事务。默认使用 H2 内存数据库。数据库将随着引擎的启动和关闭进行创建和销毁。使用此类时一般无需进行额外配置。 -* *org.flowable.dmn.spring.SpringDmnEngineConfiguration*: 在 Spring 环境中使用 DMN 引擎时使用此类。详见 <>。 - -=== 植入到流程引擎 - -除了以独立方式运行,DMN 引擎还可以植入到流程引擎中。这使得流程引擎能够识别它和其他引擎。例如,除了 BPMN 模型,还可以将 DMN 模型部署到流程引擎部署服务 API。 - -要让流程引擎能够识别出 DMN 引擎,需要在流程引擎配置中将 *org.flowable.dmn.engine.configurator.DmnEngineConfigurator* 添加到流程引擎配置 bean 的 configurators list 中 - -[source,xml,linenums] ----- - - - - - - ... - - - - - - - - - - - - - ... - ----- - - -[[databaseConfiguration]] - -=== 数据库配置 - -Flowable DMN 引擎有两种方式进行数据库配置。第一种方式是定义数据库的 JDBC 属性: - -* *jdbcUrl*: 数据库的 JDBC Url。 -* *jdbcDriver*: 特定类型数据库的驱动。 -* *jdbcUsername*: 连接数据库所使用的用户名。 -* *jdbcPassword*: 连接数据库所使用的密码。 - -基于所提供的 JDBC 属性构造的数据源将使用默认的 link:$$http://www.mybatis.org/$$[MyBatis] 连接池设置。下面这些可选属性可以用来对连接池进行调整(引自 Mybatis 文档): - -* *jdbcMaxActiveConnections*: 连接池在任意时间可以持有的最大活动连接数。 -* *jdbcMaxIdleConnections*: 连接池在任意时间可以持有的最大空闲连接数。 -* *jdbcMaxCheckoutTime*: 在被强制返回之前,连接池中的连接可被“借用”的时长(以毫秒为单位)。默认值是20000(20秒)。 -* *jdbcMaxWaitTime*: 这是一个低级别设置,使池有机会打印日志状态,并在获取连接耗时太久时进行重新尝试(以避免池配置错误时永远静默地失败)。默认值是20000(20秒)。 - -示例数据库配置: - -[source,xml,linenums] ----- - - - - ----- - -我们的跑分显示 MyBatis 的连接池在处理大量并发请求时不是最高效的。因此,建议使用 javax.sql.DataSource 的实现(比如 HikariCP、Tomcat JDBC 连接池、等等),并将其注入到引擎配置中: - -[source,xml,linenums] ----- - - - - - - - - - - - - ... - ----- - -要注意的是 Flowable DMN 并不自带定义这种数据源所需要的类库,所以你要确保这些类库在你的classpath中。 - -无论你使用 JDBC 或数据源方式,都可以设置以下属性: - -* *databaseType*:一般情况下能从数据库连接中自动识别出来,没必要手工指定。应该仅当自动识别失败时指定。可选的值有:{h2、mysql、oracle、postgres、mssql、db2}。这项设置将决定使用哪些 create/drop 脚本。参见 <> 了解已支持哪些类型的数据库。 -* *databaseSchemaUpdate*:用来设置引擎启动和关闭时数据库表的操作策略。 -** +false+ (默认):在创建引擎时检查数据库表的版本,如果不匹配则抛出异常。 -** ++true++:在构建引擎时进行检查,并在必要时更新数据库表。如果表不存在,则创建。 -** ++create-drop++:引擎创建时创建表,引擎关闭时删除表。 - - -[[jndiDatasourceConfig]] - -=== JNDI 数据源配置 - -默认情况下,Flowable DMN 的数据库配置包含在每个 web 应用的 WEB-INF/classes 下的 db.properties 文件中。但是这样并不理想,因为它使得用户要么修改 Flowable 代码中的 db.properties 并重新编译 WAR 文件,要么在每一次项目部署时解压 WAR 并修改 db.properties。 - -通过 JNDI (Java Naming and Directory Interface)获取数据库连接,这个连接将完全由 Servlet 容器管理,且配置可以在 war 包外部进行管理。而且相比 db.properties 文件,这种方式还能对连接参数进行更多的控制。 - -[[jndi_configuration]] - -==== 配置 - -JNDI 数据源的配置将视你所使用的 servlet 容器而有所不同。下面的说明适用于 Tomcat,至于其他的容器,请参阅各容器的文档。 - -如果使用 Tomcat,JNDI 资源配置在 $CATALINA_BASE/conf/[enginename]/[hostname]/[warname].xml 中(Flowable UI 的配置通常在 $CATALINA_BASE/conf/Catalina/localhost/flowable-app.xml)。默认的 context 是在应用初次部署时从 Flowable WAR 文件中复制过来的,所以如果已经存在的话你需要进行替换。比如,要使用 MySql 而不是 H2,可如下修改 JNDI 资源: - -[source,xml,linenums] ----- - - - - ----- - - -==== JNDI 属性 - -要配置 JNDI 数据源,使用下面这些 Flowable UI 的 properties 文件中的属性: - -* spring.datasource.jndi-name=:数据源的 JNDI 名称。 -* datasource.jndi.resourceRef:设置查询是否发生在 J2EE 容器中,换句话说,JNDI 名称中不包含前缀“java:comp/env/”时是否要把它加上。默认“true”。 - - -[[supporteddatabases]] - - -=== 支持的数据库 - -下面列出了 Flowable 所使用的数据库的类型(区分大小写!)。 - -[[databaseTypes]] -[options="header"] -|=============== -|Flowable DMN 数据库类型| JDBC URL 示例|备注 -|h2|jdbc:h2:tcp://localhost/flowable_dmn|默认数据库 -|mysql|jdbc:mysql://localhost:3306/flowable_dmn?autoReconnect=true|已使用 mysql-connector-java 数据库驱动进行测试 -|oracle|jdbc:oracle:thin:@localhost:1521:xe| -|postgres|jdbc:postgresql://localhost:5432/flowable_dmn| -|db2|jdbc:db2://localhost:50000/flowable_dmn| -|mssql|jdbc:sqlserver://localhost:1433;databaseName=flowable_dmn (jdbc.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver) _OR_ jdbc:jtds:sqlserver://localhost:1433/flowable_dmn (jdbc.driver=net.sourceforge.jtds.jdbc.Driver)|已使用 Microsoft JDBC Driver 4.0(sqljdbc4.jar)和 JTDS 驱动进行测试 -|=============== - - -[[creatingDatabaseTable]] - -=== 创建数据库表 - -Flowable DMN 使用 link:$$http://www.liquibase.org$$[Liquibase] 跟踪、管理和应用数据库表的变更。 - -创建数据库表的最简单的方式是: - -* 将 flowable-dmn-engine 相关JAR包添加到 classpath -* 添加合适的数据库驱动 -* 添加 Flowable 配置文件(__flowable.dmn.cfg.xml__)到 classpath,指向你的数据库(参阅 <>) -* 执行 _DbSchemaCreate_ 类的 main 方法 - -[[database.tables.explained]] - - -=== 数据库表名称说明 - -Flowable DMN 的表名全部以 *ACT_DMN_* 开头。 - -* ACT_DMN_DATABASECHANGELOG:此表用于 Liquibase 对已运行的变更进行追踪。 -* ACT_DMN_DATABASECHANGELOGLOCK:此表用于 Liquibase 确保同时只有一个 Liquibase 实例在运行。 -* ACT_DMN_DECISION_TABLE:此表包含了已部署的决策表的元数据。 -* ACT_DMN_DEPLOYMENT:此表包含了每次部署行为的元数据。 -* ACT_DMN_DEPLOYMENT_RESOURCE:此表包含了 DMN 定义的资源和元数据。 - -[[databaseUpgrade]] - - -=== 数据库升级 - -请确保在升级前已对数据库进行备份。 - -每当引擎被创建时默认都会进行版本检查。版本检查通常在你的应用程序或者 Flowable web 应用启动时发生。如果 Flowable 库发现库版本和数据库表版本不同,则抛出异常。 - -要进行升级,你首先需要在 flowable.dmn.cfg.xml 配置文件中加入如下配置属性: - -[source,xml,linenums] ----- - - - - - - - - - ----- - -*另外,在classpath中引入适合你数据库的驱动。* 升级应用程序中的 Flowable DMN 类库,或者启动一个新版本的 Flowable DMN 并将其指向旧版本的数据库。当 databaseSchemaUpdate 设置为 true 时,Flowable DMN 将会在首次发现类库版本和数据库表版本不同时升级到新版本。 - -[[processDefinitionCacheConfiguration]] - - -=== 部署缓存配置 - -为了避免每次需要决策表时都去访问数据库,同时也因为决策表不会改变,所有的决策都是被缓存的(在它们经过解析之后)。缓存默认是没有限制的。可添加如下属性对决策缓存进行限制: - -[source,xml,linenums] ----- - ----- - -这项设置将使用给定了硬性限制的 LRU 缓存替代默认的 hashmap 缓存。当然,最合适的取值取决于决策总数以及运行时实际使用到的决策数。 - -你还可以注入你自己的缓存实现。必须是一个实现了 org.flowable.dmn.engine.impl.persistence.deploy.DeploymentCache 接口的 bean: - -[source,xml,linenums] ----- - - - ----- - -[[strictMode]] - -=== 严格模式 - -严格模式是默认 *启用* 的。就是说命中策略(hit policies)将按照 DMN 1.1 标准执行。也可以禁用严格模式。 - -[source,xml,linenums] ----- - - - - - - - - - ----- - -这样做的影响是违反了命中策略约束时,结果不会作废。可能的违规将被作为验证信息记录到审核日志中。 - -=== 自定义 Flowable 函数委托(Function Delegates) - -Flowable DMN 内置了一些 JUEL 函数委托。通过设置 dmnEngineConfiguration bean 的 *customFlowableFunctionDelegates* 属性,你可以使用自己的实现。这些(函数委托)可以在表达式(expressions)中执行你自己的逻辑。 - -[source,xml,linenums] ----- - - - - - - - - - - - - - - - - - ----- - -请注意,自定义函数委托必须继承自 org.flowable.engine.common.impl.el.AbstractFlowableFunctionDelegate。 - -[[loggingConfiguration]] - - -=== 日志 - -所有日志(flowable、spring、mybatis、...)都通过 slf4j 门面进行记录,所以你可以自行选择日志框架。 - -*flowable 引擎依赖项中默认没有包含具体的日志实现框架;你应该将你选择的日志框架添加到你的项目中。* 如果没有引入日志实现框架的 jar 包,slf4j 不会记录任何日志,只会给出一个不会记录任何内容的警告。 - -举个例子,使用 maven 时,像这样添加依赖(以使用 log4j 为例),请注意这里省略了版本: - -[source,xml,linenums] ----- - - org.slf4j - slf4j-log4j12 - ----- - -flowable-ui 和 flowable-rest webapps 使用 log4j。运行所有的 flowable-* mudules 测试时同样使用 log4j。 - -*所用容器的 classpath 中带有 commons-logging 时的重要注意事项:* 为了能通过 slf4j 能调用到 spring-logging,使用了一个桥(a bridge is used)(详见 link:$$http://www.slf4j.org/legacy.html#jclOverSLF4J$$[http://www.slf4j.org/legacy.html#jclOverSLF4J])。如果你的容器提供了 commons-logging 实现,请按此页面的说明进行操作,以确保稳定:link:$$http://www.slf4j.org/codes.html#release$$[http://www.slf4j.org/codes.html#release]。 - -Maven 示例(忽略了版本): - -[source,xml,linenums] ----- - - org.slf4j - jcl-over-slf4j - ----- diff --git a/docs/userguide/src/zh_CN/dmn/ch03-API.adoc b/docs/userguide/src/zh_CN/dmn/ch03-API.adoc deleted file mode 100755 index 350835c5d0b..00000000000 --- a/docs/userguide/src/zh_CN/dmn/ch03-API.adoc +++ /dev/null @@ -1,258 +0,0 @@ -[[chapterApi]] - -== Flowable DMN API - -[[apiEngine]] - - -=== DMN引擎API和服务 - -DMN引擎API是与Flowable DMN交互的最常见方式。中心起点是++DmnEngine++,可以通过<>部分中描述的多种方式创建。从DmnEngine中,您可以获得各种其他服务。 - -DmnEngine和服务对象是线程安全的。因此,您可以为整个服务器保留对其中一个的引用。 - -[source,java,linenums] ----- -DmnEngine dmnEngine = DmnEngines.getDefaultDmnEngine(); -DmnRuleService dmnRuleService = dmnEngine.getDmnRuleService(); -DmnRepositoryService dmnRepositoryService = dmnEngine.getDmnRepositoryService(); -DmnManagementService dmnManagementService = dmnEngine.getDmnManagementService(); ----- - -+DmnEngines.getDefaultDmnEngine()+ 将在第一次调用时初始化并构建DMN引擎,之后始终返回相同的DMN引擎。 可以使用适当的DMNEngines.init()创建和DMNEngines.destroy()关闭所有DMN引擎。 - -DmnEngines类将扫描所有 +flowable.dmn.cfg.xml+ 和 +flowable-dmn-context.xml+ 文件。对所有 +flowable.dmn.cfg.xml+ 文件, DMN引擎将以典型的Flowable方式构建:+DmnEngineConfiguration.createDmnEngineConfigurationFromInputStream(inputStream).buildDmnEngine()+. 对所有 +flowable-dmn-context.xml+ 文件,DMN引擎将以Spring方式构建: 首先创建Spring应用程序上下文,然后从该应用程序上下文中获取DMN引擎。 - -所有服务都是无状态的。这意味着您可以在群集中的多个节点上轻松运行Flowable DMN,每个都进入同一个数据库,而不必担心哪台机器实际执行了以前的调用。对任何服务的任何调用都是幂等的,无论它在何处执行。 - -DmnRepositoryService可能是使用Flowable DMN引擎时所需的第一个服务。此服务提供用于管理、操作部署和DMN定义的操作。 DMN定义是DMN模型的根本概念(DMN的主要概念在中有解释). 它包含决策的定义(及其决策表)。 - 部署是Flowable DMN引擎中的打包的单位。部署可以包含多个DMN XML文件。 发布部署意味着将其部署到引擎表,在存储到数据库中之前检查和解析所有DMN定义。从那时起,系统就知道部署,现在可以执行部署中包含的任何决策。 - -此外,此服务允许您: - -* 查询引擎已知的部署,DMN定义和决策表。 -* 检索可用于使用Java而不是XML进行内省的DMN定义或决策表的POJO版本。 - -*DmnRuleService* 提供了执行决策的方法。通过提供参数和输入数据,可以开始评估决策。 - -使用Flowable DMN编写自定义应用程序时,通常不需要 *DmnManagementService* 。 它允许您检索有关引擎版本,数据库表和表元数据的信息。 - -有关服务操作和DMN引擎API的更多详细信息,查看链接:$$http://www.flowable.org/docs/javadocs/index.html$$[the javadocs]. - - -=== 异常策略 - -Flowable中的基本异常是 +org.flowable.engine.FlowableException+,一个 unchecked 异常。 API可以随时抛出此异常,但在特定方法中发生的“预期”异常将记录在链接:$$http://www.flowable.org/docs/javadocs/index.html$$[ the javadocs]. 例如, 来自 ++DmnRuleService++ 的提取物: - -[source,java,linenums] ----- -/** - * Execute a decision identified by it's key. - * - * @param decisionKey the decision key, cannot be null - * @param inputVariables map with input variables - * @return the {@link RuleEngineExecutionResult} for this execution - * @throws FlowableObjectNotFoundException - * when the decision with given key does not exist. - * @throws FlowableException - * when an error occurs while executing the decision. - */ -RuleEngineExecutionResult executeDecisionByKey(String decisionKey, Map inputVariables); ----- - -在上面的示例中,当传递的密钥没有任何决策时,将抛出异常。此外,由于javadoc *明确声明decisionKey不能为null,当传递null时,将抛出 FlowableIllegalArgumentException* 。 - -即使我们想要避免一个大的异常层次结构,在特定情况下会抛出以下子类。在流程执行或API调用期间发生的所有其他错误都不符合以下可能的异常,这些错误将作为常规++ FlowableExceptions ++ 抛出。 - -* ++FlowableOptimisticLockingException++: 在由同一数据条目的并发访问引起的数据存储中发生乐观锁定时抛出。 - * ++FlowableClassLoadingException++: 未找到请求加载的类或加载时发生错误时抛出。 - * ++FlowableObjectNotFoundException++: 当请求或操作的对象不存在时抛出。 - * ++FlowableIllegalArgumentException++: 指示在Flowable DMN API调用中提供了非法参数的异常,在引擎的配置中配置了非法值,或者提供了非法值。 - - -[[queryAPI]] - - -=== 查询 API - -有两种方法可以从引擎查询数据:查询API和本机查询。 Query API允许使用流畅的API对完全类型安全的查询进行编程。您可以为查询添加各种条件(所有这些条件作为逻辑AND一起应用)并且恰好是一个排序。以下代码显示了一个示例: - -[source,java,linenums] ----- -List dmnDeployments = dmnRepositoryService.createDeploymentQuery() - .deploymentNameLike("deployment%") - .orderByDeployTime() - .list(); ----- - -有时您需要更强大的查询,例如,使用OR运算符的查询或使用Query API无法表达的限制。对于这些情况,我们引入了本机查询,允许您编写自己的SQL查询。返回类型由您使用的Query对象定义,数据映射到正确的对象,例如Deployment,ProcessInstance,Execution等。由于查询将在数据库中触发,因此必须使用在数据库中定义的表名和列名;这需要一些有关内部数据结构的知识,建议您谨慎使用本机查询。可以通过API检索表名,以使依赖性尽可能小。 - -[source,java,linenums] ----- - -long count = dmnRepositoryService.createNativeDeploymentQuery() - .sql("SELECT count(*) FROM " + dmnManagementService.getTableName(DmnDeploymentEntity.class) + " D1, " - + dmnManagementService.getTableName(DecisionTableEntity.class) + " D2 " - + "WHERE D1.ID_ = D2.DEPLOYMENT_ID_ " - + "AND D1.ID_ = #{deploymentId}") - .parameter("deploymentId", deployment.getId()) - .count(); ----- - -[[apiVariables]] - - -[[apiUnitTesting]] - - -=== 单元测试 - -由于Flowable DMN是一个可嵌入的Java引擎,因此编写DMN定义的单元测试就像编写常规单元测试一样简单。 - -Flowable支持JUnit版本4和5样式的单元测试。 - - -在JUnit 5样式中,需要使用 org.flowable.dmn.engine.test.FlowableDmnTest 注解 - 或手动注册 org.flowable.dmn.engine.test.FlowableDmnExtension 。 - FlowableDmnTest 注解只是一个元注解,并且注册了 FlowableDmnExtension - (即 +@ExtendWith(FlowableDmnExtension.class)+). - 这将使DmnEngine和服务可用作测试和生命周期方法的参数 - (+@BeforeAll+, +@BeforeEach+, +@AfterEach+, +@AfterAll+). - 在每次测试之前,默认情况下将使用类路径上的 flowable.dmn.cfg.xml 资源初始化dmnEngine。 - 为了指定不同的配置文件需要使用org.flowable.dmn.engine.test.DmnConfigurationResource 注解(参见第二个例子)。 - 当配置资源相同时,Dmn引擎将在多个单元测试中静态缓存。 - - -通过使用 FlowableDmnExtension ,您可以在测试方法上使用 org.flowable.dmn.engine.test.DmnDeployment 注解或 org.flowable.dmn.engine.test.DmnDeploymentAnnotation 注解。 - 如果同时使用 @DmnDeployment 和 @DmnDeploymentAnnotatio 那么 @DmnDeployment 优先,@DmnDeploymentAnnotation 将被忽略。 - 在测试方法上使用 @DmnDeployment 注解时,在每次测试之前,将部署 DmnDeployment#resources 中定义的dmn文件。 - 如果没有定义资源,则为 testClassName.testMethod.dmn 形式的资源文件,将在与测试类相同的包中进行部署。 - 在测试结束时,部署将被删除,包括所有相关的dmn定义,执行等。 - 有关更多信息,请参阅 DmnDeployment 类。 - -考虑到所有这些,JUnit 5测试看起来如下: - -.使用默认资源进行JUnit 5测试 -[source,java,linenums] ----- -@FlowableDmnTest -class MyDecisionTableTest { - - @Test - @DmnDeploymentAnnotation - void simpleDmnTest(DmnEngine dmnEngine) { - DmnRuleService dmnRuleService = dmnEngine.getDmnRuleService(); - - Map executionResult = ruleService.createExecuteDecisionBuilder() - .decisionKey("extensionUsage") - .variable("inputVariable1", 2) - .variable("inputVariable2", "test2") - .executeWithSingleResult(); - - Assertions.assertThat(executionResult).containsEntry("output1", "test1"); - } -} ----- - -[TIP] ------ -使用JUnit 5,您还可以将部署的ID(带有org.flowable.dmn.engine.test.DmnDeploymentId_)注入到测试和生命周期方法中。 ------ - -.使用自定义资源进行JUnit 5测试 -[source,java,linenums] ----- -@FlowableDmnTest -@DmnConfigurationResource("flowable.custom.dmn.cfg.xml") -class MyDecisionTableTest { - - @Test - @DmnDeploymentAnnotation - void simpleDmnTest(DmnEngine dmnEngine) { - DmnRuleService dmnRuleService = dmnEngine.getDmnRuleService(); - - Map executionResult = ruleService.createExecuteDecisionBuilder() - .decisionKey("extensionUsage") - .variable("inputVariable1", 2) - .variable("inputVariable2", "test2") - .executeWithSingleResult(); - - Assertions.assertThat(executionResult).containsEntry("output1", "test1"); - } -} ----- - - -在编写JUnit 4单元测试时,可以使用 org.flowable.dmn.engine.test.FlowableDmnRule 规则。通过此规则,DMN引擎和服务可通过getter获得。包含此 Rule 将启用注解 org.flowable.dmn.engine.test.DmnDeploymentAnnotation (请参阅上文,了解其使用和配置) 它将在类路径中查找默认配置文件。 当使用相同的配置资源时,DMN引擎可以在多个单元测试中静态缓存。 -也可以为规则提供自定义引擎配置。 - -以下代码片段显示了使用JUnit 4测试样式和 FlowableDmnRule 的用法的示例(并传递可选的自定义配置): - -.JUnit 4 test -[source,java,linenums] ----- -public class MyDecisionTableTest { - - @Rule - public FlowableDmnRule flowableDmnRule = new FlowableDmnRule("custom1.flowable.dmn.cfg.xml"); - - @Test - @DmnDeploymentAnnotation - public void ruleUsageExample() { - DmnEngine dmnEngine = flowableDmnRule.getDmnEngine(); - DmnRuleService dmnRuleService = dmnEngine.getDmnRuleService(); - - Map executionResult = ruleService.createExecuteDecisionBuilder() - .decisionKey("extensionUsage") - .variable("inputVariable1", 2) - .variable("inputVariable2", "test2") - .executeWithSingleResult(); - - Assertions.assertThat(executionResult).containsEntry("output1", "test1"); - } -} ----- - - -[[apiProcessEngineInWebApp]] - - -=== Web应用程序中的DMN引擎 - -DmnEngine是一个线程安全的类,可以在多个线程之间轻松共享。 在Web应用程序中,这意味着可以在容器启动时创建DMN引擎,并在容器停机时关闭引擎。 - -以下代码片段显示了如何编写一个简单的 ServletContextListener 来初始化和销毁​​普通Servlet环境中的流程引擎: - -[source,java,linenums] ----- -public class DmnEnginesServletContextListener implements ServletContextListener { - - public void contextInitialized(ServletContextEvent servletContextEvent) { - DmnEngines.init(); - } - - public void contextDestroyed(ServletContextEvent servletContextEvent) { - DmnEngines.destroy(); - } - -} ----- - -contextInitialized 方法将调用 DmnEngines.init()。 这将寻找类路径上的 +flowable.dmn.cfg.xml+ 资源文件,并对于给定的配置创建一个 +DmnEngine+ (例如,带有配置文件的多个JAR).如果类路径上有多个此类资源文件,请确保它们都具有不同的名称。 当需要DMN引擎时,可以使用以下方式获取它: - -[source,java,linenums] ----- -DmnEngines.getDefaultDmnEngine() ----- - -或者: - -[source,java,linenums] ----- -DmnEngines.getDmnEngine("myName"); ----- - -当然,也可以使用任何创建DMN引擎的变体,如<>中描述的那样。 - - -context-listener的 contextDestroyed方法会调用 DmnEngines.destroy()。 它会妥善关闭所有初始化的DMN引擎。 \ No newline at end of file diff --git a/docs/userguide/src/zh_CN/dmn/ch04-Spring.adoc b/docs/userguide/src/zh_CN/dmn/ch04-Spring.adoc deleted file mode 100755 index e42156719b5..00000000000 --- a/docs/userguide/src/zh_CN/dmn/ch04-Spring.adoc +++ /dev/null @@ -1,156 +0,0 @@ -[[springintegration]] - -== Spring集成 - - -虽然我们可以在没有Spring的情况下使用 Flowable DMN,但我们还是有必要提供了一些非常好的集成特性,本章我们将对此进行说明。 - -=== DmnEngineFactoryBean - -我们可以将++DMN引擎++配置为普通的Spring Bean。配置的入口是++org.flowable.dmn.spring.DmnEngineFactoryBean++类。这个bean采用DMN引擎配置并同时创建DMN引擎。 这意味着Spring属性的创建和配置与<>中记录的是一致的。Spring集成所用的配置与引擎Bean如下所示: - -[source,xml,linenums] ----- - - ... - - - - - - ----- - - -注意:DmnEngine Bean的配置现在使用的是++org.flowable.dmn.spring.SpringDmnEngineConfiguration++类。 - - - -=== 自动资源部署 - - -Spring集成还有一个自动部署资源的特殊功能。在DMN引擎配置中,我们可以指定一组资源。一旦创建DMN引擎,所有指定的资源都会被扫描和部署。适当的过滤可以防止重复的部署。只有当资源确实发生变化时,才会重新部署至Flowable DMN数据库中。这在Spring容器经常重启(例如:测试)的时候非常有用。 - - -以下是一个例子: - -[source,xml,linenums] ----- - - ... - - - - - - ----- - - -默认情况下,上面的配置方式会将符合这个过滤器的所有资源组织在一起,作为Flowable DMN引擎的一个部署。为避免未改变资源导致重复部署,重复检测过滤将作用于整个部署操作。有时候,这并不是你想要的。例如,如果我们以这种方式部署了一组DMN资源,即使这些资源中只有的一个DMN流程定义发生了改变,整个部署都被视为新的部署,这个部署中的所有流程定义都将被重新部署,这将导致每个流程定义都会刷新版本,即使实际上只有一个流程定义发生了变化。 - - -要想定制部署的方式,我们可以在++SpringProcessEngineConfiguration++中指定一个额外属性++deploymentMode++,这个属性定义了部署一组符合过滤器的资源的策略。这个属性默认支持3个值: - - -* ++default++: 将所有资源组织在一个部署中,整体用于重复检测过滤。这是默认值,在不指定属性值的时候也使用这个。 - - -* ++single-resource++: 为每个资源创建一个单独的部署,并用于重复检测过滤。如果希望单独部署每一个DMN流程定义,并且只有在它发生变化时才创建新的DMN流程定义版本,就应该使用这个值。 - - -* ++resource-parent-folder++: 为同一个目录下的资源创建一个单独的部署,并用于重复检测过滤。这个属性值可以为大多数资源创建独立的部署。同时仍可以通过将部分资源放在同一个目录下,将它们组织在一起。以下是一个将++deploymentMode++设置为++single-resource++的例子: - -[source,xml,linenums] ----- - - ... - - - ----- - - -除了使用上面列出的++deploymentMode++几个枚举值之外,我们还可以自定义自动部署的行为。如果是这样做,我们可以创建++SpringDmnEngineConfiguration++的子类并覆盖++getAutoDeploymentStrategy(String deploymentMode)++方法。 这个方法用来设置++deploymentMode++属性值。 - - -[[springUnitTest]] - - - -=== 单元测试 - - -集成Spring后,我们可以很轻松使用标准的<>测试业务流程。下面的例子我们来展示如何使用典型的Spring单元测试工具测试业务流程: - -.JUnit 5 测试 -[source,java,linenums] ----- -@ExtendWith(FlowableDmnSpringExtension.class) -@ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = DmnSpringJunitJupiterTest.TestConfiguration.class) -public class SpringJunit4Test { - - @Autowired - private DmnEngine dmnEngine; - - @Autowired - private DmnRuleService ruleService; - - @Test - @DmnDeploymentAnnotation - public void simpleDecisionTest() { - Map executionResult = ruleService.createExecuteDecisionBuilder() - .decisionKey("extensionUsage") - .variable("inputVariable1", 2) - .variable("inputVariable2", "test2") - .executeWithSingleResult(); - - Assertions.assertThat(executionResult).containsEntry("output1", "test1"); - } -} ----- - -.JUnit 4 测试 -[source,java,linenums] ----- -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration("classpath:org/flowable/spring/test/junit4/springTypicalUsageTest-context.xml") -public class SpringJunit4Test { - - @Autowired - private DmnEngine dmnEngine; - - @Autowired - private DmnRuleService ruleService; - - @Autowired - @Rule - public FlowableDmnRule flowableSpringRule; - - @Test - @DmnDeploymentAnnotation - public void simpleDecisionTest() { - Map executionResult = ruleService.createExecuteDecisionBuilder() - .decisionKey("extensionUsage") - .variable("inputVariable1", 2) - .variable("inputVariable2", "test2") - .executeWithSingleResult(); - - Assertions.assertThat(executionResult).containsEntry("output1", "test1"); - } -} ----- - - -注意:这个例子正常运行的条件是,需要在Spring配置中定义一个 _org.flowable.dmn.engine.test.FlowableDmnRule_ Bean(在上面的例子中通过@Autowire自动注入) - -[source,xml,linenums] ----- - - - - ----- diff --git a/docs/userguide/src/zh_CN/dmn/ch05-Deployment.adoc b/docs/userguide/src/zh_CN/dmn/ch05-Deployment.adoc deleted file mode 100755 index 7709d276944..00000000000 --- a/docs/userguide/src/zh_CN/dmn/ch05-Deployment.adoc +++ /dev/null @@ -1,157 +0,0 @@ -[[chDeployment]] - -== 部署 - - -=== DMN定义 - -文件名后缀符合 +.dmn+的文件,可以部署到DMN引擎中。 - -当DMN引擎嵌入到流程引擎中,DMN定义文件可以和其他流程相关资源一起,打包到流程包(business archive BAR)里。流程引擎的部署服务会识别DMN资源,将其引入到DMN引擎中。 - -[NOTE] -==== -流程包中包含的自定义表达式函数的Java class文件*不会添加到classpath中*。这些自定义的决策表达式class文件应该添加到DMN引擎的classpath,这样引擎才能发现并使用这些决策表达式。 -==== - - -==== DMN定义文件,决策 和决策表 -一个DMN定义包含(不仅仅是)许多决策。一个决策一个表达式。DMN规范定义(描述)了多种类型的表达式。目前在Flowable DMN中,我们支持决策表类型的表达式。 -部署一个DMN定义是,定义中的每个*包含决策表*的决策定义,会分开插入到ACT_DMN_DECISION表里。 - - -==== 编程方式部署 - -可以这样部署一个DMN定义: - -[source,java,linenums] ----- -String dmnDefinition = "path/to/definition-one.dmn"; //Don't forget the .dmn extension! - -repositoryService.createDeployment() - .name("Deployment of DMN definition-one") - .addClasspathResource(dmnDefinition) - .deploy(); - ----- - -也可以使用诸如`addInputStream`的其他方式部署DMN定义。以下是一个使用外部文件部署DMN定义的例子: - -[source,java,linenums] ----- -File dmnFile = new File("/path/to/definition-two.dmn"); //Don't forget the .dmn extension! - -repositoryService.createDeployment() - .name("Deployment of DMN definition-two") - .addInputStream(dmnFile.getName(), new FileInputStream(dmnFile)) - .deploy(); - ----- - -部署的文件,名称可以是任意文本,但是作为有效的DMN定义文件,定义文件名后缀应该是(".dmn")。 - -==== Java 类 - -当决策执行时,使用的自定义Java class文件,需要放在引擎的classpath中。 - -在部署DMN定义时,这些class文件可以没有放到引擎的classpath下。 - -在测试时需要添加自定义Java类。需要把包含这些class文件的jar包放到flowable-ui-app或flowable-app-rest工程的lib下(${webserver}/${appname}/WEB-INF/lib/)。千万不要忘记这些依赖。另外,也可以将这些依赖放到tomcat中,+${tomcat.home}/lib+。 - - -==== 创建单应用 - -不用确保所有DMN引擎classpath中包含所有代理类,并且使用了正确的spring配置,你可以考虑在自己的webapp里引入flowable-rest,这样就只有一个+Dmn引擎+. - -[[versioningOfDMNDefinitions]] - -=== DMB决策版本控制 - -DMN没有版本控制的概念。这实际上很好,因为作为开发项目的一部分,可执行DMN定义文件可能位于版本控制系统存储库(例如Subversion、Git或Mercurial)中。部署期间创建DMN决策的版本。在部署过程中,flowable将为+decision+分配一个版本,然后将其存储在flowable db中。 - -因为DMN定义中的每个DMN决策都是一个DMN定义,将执行以下步骤来初始化属性+key+、+version+、+name+和+id+: - -* 定义文件中 decision +id+ 属性在决策表中是 +key+. -* 定义文件中 decision +name+ 属性在决策表中是 +name+. -* 一个有特定的key的决策在首次部署时,版本标记为1。对于之后所有拥有相同key的发布,版本号相对于之前最高版本号+1。所以key属性是用来区分不同的决策。 -* id属性时在集群环境中,保证决策表的唯一的[数字]标识。 - - -以下面的流程为例: - -[source,xml,linenums] ----- - - - - ... ----- - -当部署了该决策,决策表在数据库中是这样的: - -[options="header"] -|=============== -|id|key|name|version -|e29d4126-ed4d-11e6-9e00-7282cbd6ce64|myDecision|My important decision|1 - -|=============== - - -当我们再发布这个流程的更新版本(比如:更改了用户任务),流程定义的++id++ 和之前是一样的。 -流程定义表会包含一下信息: - -[options="header"] -|=============== -|id|key|name|version -|e29d4126-ed4d-11e6-9e00-7282cbd6ce64|myDecision|My important decision|1 -|e9c2a6c0-c085-11e6-9096-6ab56fad108a|myDecision|My important decision|2 - -|=============== - -当调用了 ++dmnRuleService.executeDecisionByKey("myDecision")++ , 之后会调用版本号 ++2++ 的决策定义,因为这个是决策定义的最新版本。 - -如果我们创建第二个决策,定义如下所示,然后发布到flowable DMN中,数据库表中会增加第三行。 - -[source,xml,linenums] ----- - - - - ... ----- - -表中数据是这样的: - -[options="header"] -|=============== -|id|key|name|version -|e29d4126-ed4d-11e6-9e00-7282cbd6ce64|myDecision|My important decision|1 -|e9c2a6c0-c085-11e6-9096-6ab56fad108a|myDecision|My important decision|2 -|d317d3f7-e948-11e6-9ce6-b28c070b517d|myNewDecision|My important decision|1 - -|=============== - -注意:新的决策的key和第一个决策的key是不一样的。尽管name属性是一样的(正常情况下,表意清晰的话,我们需要把name属性也改掉),FlowableDMN引擎通过 ++id++ 属性来区分不同的决策。新增的决策将会以版本1部署。 - -[[deploymentCategory]] - -=== 分类 - -DMN部署和决策表都可以自定义分类。 -DMN部署分类可以这样定义: - -[source,java,linenums] ----- -dmnRepository - .createDeployment() - .category("yourCategory") - ... - .deploy(); ----- - -决策表分类可以这样定义: - -[source,java,linenums] ----- -dmnRepository.setDecisionTableCategory("e9c2a6c0-c085-11e6-9096-6ab56fad108a", "yourCategory"); ----- \ No newline at end of file diff --git a/docs/userguide/src/zh_CN/dmn/ch06-DMN-Introduction.adoc b/docs/userguide/src/zh_CN/dmn/ch06-DMN-Introduction.adoc deleted file mode 100755 index e339dde4875..00000000000 --- a/docs/userguide/src/zh_CN/dmn/ch06-DMN-Introduction.adoc +++ /dev/null @@ -1,229 +0,0 @@ -[[bpmn20]] - - -== DMN 1.1 入门 - -[[whatIsDmn]] - - -=== 什么是DMN? - - -Decision Model & Notation(DMN)是由link:$$http://www.omg.org/spec/DMN/1.1$$[对象管理组(OMG)]发布的标准。它是描述和构建组织内可重复决策的标准方法,以确保决策模型在各组织之间是通用的。 - -[[dmnDefiningDecision]] - - -=== 什么是DMN定义? - - -DMN 1.1模式的根元素是**definitions**。在这个项目中可以定义多个决策定义(尽管我们建议每个文件中只有一个决策定义,这可以简化开发过程的后期维护)。每个决策可以定义一个表达式。目前,Flowable支持几种表达式类型中的**决策表**。 - -[source,xml,linenums] ----- - - - - - - .. - - - - - ----- - - -=== 创建DMN定义 - - -虽然使用纯文本编辑器创建DMN定义是可行的,但是对于此示例,我们将首先使用Flowable建模器的决策表编辑器。 - - -接下来,我们将实现一个非常简单的用例:根据客户类别确定折扣百分比。 - - -首先打开Flowable建模器中的决策表部分。 - -image::images/decision_tables_1.png[align="center"] - - -选择**Create Decision Table**。 - -image::images/decision_tables_2.png[align="center"] - - -填写决策表名称和决策表唯一键,然后选择**Create new decision table**。 - -image::images/decision_tables_3.png[align="center"] - - -现在就可以定义决策表了。接下来我们对编辑器做个说明。 - - -==== Hit Policy 命中策略 - - -我们可以在左上角选择**hit policy**。 - - -可以看到,有7个命中策略可用。 - - -*单一命中* - -* **F**IRST: 可以匹配多个(重叠)具有不同输出条目的规则。返回规则顺序中的第一次命中(返回后停止评估)。 - - -* **U**NIQUE: 没有重叠的可能,所有规则都是互斥的。只能匹配到一条规则。 - - -* **A**NY: 可能会有重叠,但如果所有匹配规则显示每个输出的输出条目相等,就可以使用任何匹配。如果输出条目不相等,则命中策略不正确,结果将为空并标记为failed。当禁用link:$$#strictMode$$[strict mode]时,结果是最后一个有效规则。(违规将以验证消息的形式出现) - - -* **P**RIORITY: 具有不同的输出条目的多个规则可以匹配。此策略返回具有最高输出优先级的匹配规则。输出优先级在输出值的有序列表中按优先级递减的顺序指定。当禁用link:$$#strictMode$$[strict mode]且未定义输出值时,结果是最后一个有效规则。(违规将以验证消息的形式出现) - - - -*多重命中* - - -* **O**UTPUT ORDER: 按输出优先级递减的顺序返回所有命中规则。输出优先级在输出值的有序列表中按优先级递减的顺序指定。 - - -* **R**ULE ORDER: 按规则顺序返回所有命中。 - - -* **C**OLLECT: 以任意顺序返回所有命中。我们可以添加运算符('+','<','>','#')来将一个简单函数应用于输出。如果没有运算符,则结果是所有输出条目的列表。 - -** + (sum): 决策表的结果是所有不同输出的总和。 -** < (min): 决策表的结果是所有输出的最小值。 -** > (max): 决策表的结果是所有输出的最大值。 -** # (count): 决策表的结果是所有不同输出的总数。 - - -==== 输入和输出表达式 - - -决策表本身的表头分为两部分;蓝色和绿色。蓝色部分是**input expressions**(输入表达式);绿色的是**output expressions**(输出表达式)。 - -image::images/decision_tables_4.png[align="center"] - - -在输入表达式中,我们可以定义将在规则输入条目的表达式中使用的变量(下面解释)。还可以通过选择**Add Input**(右键单击option菜单或单击plus图标)来定义多个输入表达式。 - -image::images/decision_tables_5.png[align="center"] - - -在输出表达式中,我们可以定义将创建什么变量来构成决策表执行的结果(变量的值将由输出条目表达式决定,下面解释)。还可以通过选择**Add Output**(右键单击option菜单或单击plus图标)来定义多个输出表达式。 - - -==== 规则 - - -每个规则由一个或多个输入项和一个或多个输出项组成。输入项是一个表达式,它将根据输入的变量(该“列”的值)求值。当所有输入项都为true时,就认为整个规则是true,开始计算输出项。 - -[NOTE] -==== - -DMN规范定义了一种表达式语言:(S)-FEEL。目前,我们不支持这部分规范。 在Flowable DMN中,我们使用JUEL作为表达式语言。 -==== - -image::images/decision_tables_6.png[align="center"] - -我们可以双击相应的单元格输入表达式。在此示例中,输入表达式== BRONZE。结合相应输入表达式(列标题)中定义的变量,将在运行时生成完整的表达式customerCat == "BRONZE"。 - -image::images/decision_tables_7.png[align="center"] - -然后双击相应的单元格输出表达式。这实际上更像是一个隐式赋值。 -在此示例中,输入表达式5。 - -然后,我们可以通过添加更多规则(通过选择添加规则)继续完成决策表。 - -image::images/decision_tables_8.png[align="center"] - - -在我们的示例中,规则4有一个空的输入条目,引擎将会把这个空输入条目评估为true。那么如果其他规则都无效,则规则4的结果将是该决策表的输出。在这种情况下,变量**discountPerc**的值为**0**。 - -image::images/decision_tables_9.png[align="center"] - - -现在我们可以保存决策表。填入决策表唯一键。 - - -=== BPMN2.0流程中的应用 - - -通过包含**Decision task**并选择**Decision table reference**,可以在BPMN2.0流程中使用新创建的决策表。 - -image::images/decision_tables_10.png[align="center"] - - -上面定义的流程中,该流程有一个启动表单,它将**customer category**(客户类别)提供给流程实例(从而提供给决策表)。**Display Discount**(显示折扣)用户任务使用表达式表单字段显示决策表的结果;${discountperc}。 - - -=== DMN 1.1 xml文件 - - -上面示例的完整DMN 1.1 xml文件。 - -[source,xml,linenums] ----- - - - - - - customerCat - - - "BRONZE","SILVER","GOLD" - - - - - "0","5","10","20" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ----- - - -* 此处需要重点强调的是,在Flowable中使用的决策表键是DMN xml文件中的决策ID。 \ No newline at end of file diff --git a/docs/userguide/src/zh_CN/dmn/ch07-REST.adoc b/docs/userguide/src/zh_CN/dmn/ch07-REST.adoc deleted file mode 100755 index 6199719b0e9..00000000000 --- a/docs/userguide/src/zh_CN/dmn/ch07-REST.adoc +++ /dev/null @@ -1,603 +0,0 @@ - -=== 部署 - -*当使用tomcat时,请阅读 <>.* - - -==== 获取多个DMN部署 ----- -GET dmn-repository/deployments ----- - -.URL 查询参数 - -[options="header"] -|=============== -|参数|必需|类型|描述 -|name|No|String|返回指定名称的部署. -|nameLike|No|String|模糊查询指定名称. -|category|No|String|返回指定类别. -|categoryNotEquals|No|String|返回指定类别以外的部署. -|tenantId|No|String|返回指定tenantId的部署. -|tenantIdLike|No|String|模糊查询指定tenantId的部署. -|withoutTenantId|No|Boolean|如果为true 则返回指定tenantId以外的部署,如果为false 则忽略掉该参数. -|sort|No|'id' (default), 'name', 'deploytime' or 'tenantId'|属性进行排序,与“order”一起使用. -|可以使用<>. -|=============== - - -.REST 返回编码 -[options="header"] -|=============== -|Response code|Description -|200|Indicates the request was successful. - -|=============== - -[options="header"] -|=============== -|返回编码|描述 -|200|请求成功. -|=============== - - -*Success response body:* -*成功返回示例:* - -[source,json,linenums] ----- -{ - "data": [ - { - "id": "03ab310d-c1de-11e6-a4f4-62ce84ef239e", - "name": null, - "deploymentTime": "2016-12-14T10:16:37.000+01:00", - "category": null, - "url": "http://localhost:8080/flowable-rest/dmn-api/dmn-repository/deployments/03ab310d-c1de-11e6-a4f4-62ce84ef239e", - "parentDeploymentId": "17510", - "tenantId": "" - } - ], - "total": 1, - "start": 0, - "sort": "id", - "order": "asc", - "size": 1 -} ----- - - -==== 获取一个DMN部署 - ----- -GET dmn-repository/deployments/{deploymentId} ----- - -.获取一个部署- URL 参数 - -[options="header"] -|=============== -|参数|必需|类型|描述 -|deploymentId|Yes|String|部署唯一id. - -|=============== - - -.获取一个部署- 返回编码 -[options="header"] - -[options="header"] -|=============== -|返回编码|描述 -|200|找到并返回指定部署. -|404|为找到指定的部署. - -|=============== - -*成功示例:* -[source,json,linenums] ----- -{ - "id": "03ab310d-c1de-11e6-a4f4-62ce84ef239e", - "name": null, - "deploymentTime": "2016-12-14T10:16:37.000+01:00", - "category": null, - "url": "http://localhost:8080/flowable-rest/dmn-api/dmn-repository/deployments/03ab310d-c1de-11e6-a4f4-62ce84ef239e", - "parentDeploymentId": "17510", - "tenantId": "" -} ----- - - -==== Create a new DMN deployment -(创建一个DMN部署) - ----- -POST dmn-repository/deployments ----- - -*Request body:* -*请求消息体:* - -The request body should contain data of type _multipart/form-data_. There should be exactly one file in the request: any additional files will be ignored. The deployment name is the name of the file-field passed in. -(请求消息体应该包含 _multipart/form-data_ 类型。请求中应该只有一个文件:任何额外的文件都将被忽略。file-field 的名称作为部署的名称) -An additional parameter (form-field) can be passed in the request body with name +tenantId+. The value of this field will be used as the identifier of the tenant in which this deployment is done. -(可以在请求体中通过name +tenantId+传递附加参数(表单字段)。此字段的值将用作执行此部署的租户的标识符。) -.Create a new DMN deployment - Response codes -(创建一个DMN部署-返回编码) - -[options="header"] -|=============== -|Response code|Description -|201|Indicates the deployment was created. -|400|Indicates there was no content present in the request body or the content mime-type is not supported for deployment. The status-description contains additional information. - -|=============== - -[options="header"] -|=============== -|返回编码|描述 -|201|指定的部署已经存在. -|400|请求主体中不存在内容,或部署不支持该内容的mime-type。状态描述包含附加信息。 - -|=============== - -*Success response body:* -(*成功示例:*) - -[source,json,linenums] ----- -{ - "id": "03ab310d-c1de-11e6-a4f4-62ce84ef239e", - "name": "newDeployment1", - "deploymentTime": "2016-12-14T10:16:37.000+01:00", - "category": null, - "url": "http://localhost:8080/flowable-rest/dmn-api/dmn-repository/deployments/03ab310d-c1de-11e6-a4f4-62ce84ef239e", - "tenantId" : "myTenant" -} ----- - - -==== Delete a DMN deployment -(删除一个部署) - ----- -DELETE dmn-repository/deployments/{deploymentId} ----- - -.Delete a DMN deployment - URL parameters -(删除一个部署- URL 参数) -[options="header"] -|=============== -|Parameter|Required|Value|Description -|deploymentId|Yes|String|The identifier of the deployment to delete. - -|=============== - -[options="header"] -|=============== -|参数|必需|类型|描述 -|deploymentId|Yes|String|需要删除的部署的编号. - -|=============== - - -.Delete a DMN deployment - Response codes -(删除一个部署 - 返回编码) -[options="header"] -|=============== -|Response code|Description -|204|Indicates the deployment was found and has been deleted. Response-body is intentionally empty. -|404|Indicates the requested deployment was not found. - -|=============== - -[options="header"] -|=============== -|返回编码|描述 -|204|指定的部署已经被删除。返回内容特意为空。 -|404|未找到指定的部署。 - -|=============== - - -==== Get a DMN deployment resource content -(获取DMN部署资源内容) ----- -GET dmn-repository/deployments/{deploymentId}/resourcedata/{resourceId} ----- - -.Get a deployment resource content - URL parameters -(获取DMN部署资源内容 - URL 参数) -[options="header"] -|=============== -|Parameter|Required|Value|Description -|deploymentId|Yes|String|The identifier of the deployment the requested resource is part of. -|resourceId|Yes|String|The identifier of the resource to get the data for. *Make sure you URL-encode the resourceId in case it contains forward slashes. For example, use 'decisions%2Fmy-decision.dmn' instead of 'decisions/my-decision.dmn'.* - -|=============== - -[options="header"] -|=============== -|参数|必需|类型|描述 -|deploymentId|Yes|String|指定部署编号。 -|resourceId|Yes|String|指定资源编号。确保resourceId的URL编码,以防它包含前斜杠。例如,使用 'decisions%2Fmy-decision.dmn'。而不是'decisions/my-decision.dmn' - -|=============== - - - -.Get a deployment resource content - Response codes -(.获取DMN部署资源内容 - 返回编码) -[options="header"] -|=============== -|Response code|Description -|200|Indicates both deployment and resource have been found and the resource data has been returned. -|404|Indicates the requested deployment was not found or there is no resource with the given identifier present in the deployment. The status-description contains additional information. - -|=============== - -[options="header"] -|=============== -|Response code|Description -|200|已找到指定的部署和资源,并返回资源数据。 -|404|未找到所请求的部署,或部署中不存在指定的资源。状态描述包含附加信息。 - -|=============== - -*Success response body:* -(*成功示例:*) - - -The response body will contain the binary resource-content for the requested resource. The response content-type will be the same as the type returned in the resources 'mimeType' property. Also, a content-disposition header is set, allowing browsers to download the file instead of displaying it. -(响应体将包含请求资源的二进制资源内容。响应内容类型将与资源“mimeType”属性中返回的类型相同。此外,header还设置了一个content-disposition ,允许浏览器下载文件而不是显示它。) - -=== Decision Tables -(决策表) - -==== List of decision tables -(获取决策表列表) - - ----- -GET dmn-repository/decision-tables ----- - -.List of process definitions - URL parameters -(获取流程定义列表- URL 参数) -[options="header"] -|=============== -|Parameter|Required|Value|Description -|version|No|integer|Only return process definitions with the given version. -|name|No|String|Only return process definitions with the given name. -|nameLike|No|String|Only return process definitions with a name like the given name. -|key|No|String|Only return process definitions with the given key. -|keyLike|No|String|Only return process definitions with a name like the given key. -|resourceName|No|String|Only return process definitions with the given resource name. -|resourceNameLike|No|String|Only return process definitions with a name like the given resource name. -|category|No|String|Only return process definitions with the given category. -|categoryLike|No|String|Only return process definitions with a category like the given name. -|categoryNotEquals|No|String|Only return process definitions which don't have the given category. -|deploymentId|No|String|Only return process definitions which are part of a deployment with the given identifier. -|latest|No|Boolean|Only return the latest process definition versions. Can only be used together with 'key' and 'keyLike' parameters, using any other parameter will result in a 400-response. -|sort|No|'name' (default), 'id', 'key', 'category', 'deploymentId' and 'version'|Property to sort on, to be used together with the 'order'. -|The general <> can be used for this URL. - -|=============== - -[options="header"] -|=============== -|参数|必需|类型|描述 -|version|No|integer|返回指定版本的流程定义。 -|name|No|String|返回指定名称的流程定义。 -|nameLike|No|String|模糊查询指定名称的流程定义。 -|key|No|String|返回指定key的流程定义。 -|keyLike|No|String|模糊查询指定key的流程定义。 -|resourceName|No|String|返回指定资源名称的流程定义。 -|resourceNameLike|No|String|模糊查询指定资源名称的流程定义。 -|category|No|String|返回指定类别的流程定义。 -|categoryLike|No|String|模糊查询指定名称的流程定义。 -|categoryNotEquals|No|String|返回指定类型以外的流程定义。 -|deploymentId|No|String|返回指定部署编号的流程定义。 -|latest|No|Boolean|返回最新版本的流程定义。只能与“key”和“keyLike”参数一起使用,使用任何其他参数都会得到400个响应。 -|sort|No|'name' (default), 'id', 'key', 'category', 'deploymentId' and 'version'|排序,与“order”一起使用。 -|可以使用<>. - -|=============== - - -.获取流程定义列表 - 返回编码 - -[options="header"] -|=============== -|返回编码|描述 -|200|请求成功,并返回决策表 -|400|参数以错误的格式传递,或'latest' 与'key' 和 'keyLike'以外的其他参数一起使用。状态消息包含其他信息。 - -|=============== - - -*成功示例:* - -[source,json,linenums] ----- -{ - "data": [ - { - "id": "46b0379c-c0a1-11e6-bc93-6ab56fad108a", - "url": "http://localhost:8080/flowable-rest/dmn-api/dmn-repository/decision-tables/46b0379c-c0a1-11e6-bc93-6ab56fad108a", - "category": null, - "name": "Decision Table One", - "key": "DecisionTableOne", - "description": null, - "version": 3, - "resourceName": "dmn-DecisionTableOne.dmn", - "deploymentId": "46aa6b3a-c0a1-11e6-bc93-6ab56fad108a", - "parentDeploymentId": "5001", - "tenantId": "" - } - ], - "total": 1, - "start": 0, - "sort": "name", - "order": "asc", - "size": 1 -} ----- - - -==== 获取一个决策表 - ----- -GET dmn-repository/decision-tables/{decisionTableId} ----- - -.获取一个决策表 - URL 参数 -[options="header"] - -[options="header"] -|=============== -|参数|必需|类型|描述 -|decisionTableId|Yes|String|决策表编号。 - -|=============== - - -.获取一个决策表 - 返回编码 -[options="header"] - -[options="header"] -|=============== -|Response code|Description -|200|找到指定编号决策表并返回 -|404|未找到指定编号决策表 - -|=============== - - -*成功示例:* - -[source,json,linenums] ----- -{ - "id": "46b0379c-c0a1-11e6-bc93-6ab56fad108a", - "url": "http://localhost:8080/flowable-rest/dmn-api/dmn-repository/decision-tables/46b0379c-c0a1-11e6-bc93-6ab56fad108a", - "category": null, - "name": "Decision Table One", - "key": "DecisionTableOne", - "description": null, - "version": 3, - "resourceName": "dmn-DecisionTableOne.dmn", - "deploymentId": "46aa6b3a-c0a1-11e6-bc93-6ab56fad108a", - "parentDeploymentId": "5001", - "tenantId": "" -} ----- - - -==== 获取一个决策表资源内容 ----- -GET dmn-repository/decision-tables/{decisionTableId}/resourcedata ----- - -.获取一个决策表资源内容 - URL 参数 - -[options="header"] -|=============== -|参数|必需|类型|描述 -|decisionTableId|Yes|String|决策表编号。 - -|=============== - -*返回:* - -与 +GET dmn-repository/deployment/{deploymentId}/resourcedata/{resourceId}+ 相同. - - -==== 获取一个决策表DMN模型 - ----- -GET dmn-repository/decision-tables/{decisionTableId}/model ----- - -.获取一个决策表DMN模型- URL 参数 -[options="header"] - - -[options="header"] -|=============== -|参数|必需|类型|描述 -|decisionTableId|Yes|String|决策表编号。 - -|=============== - - -.获取一个决策表DMN模型- 返回编码 -[options="header"] - - -[options="header"] -|=============== -|返回编码|描述 -|200|找到指定决策表并返回模型。 -|404|未找到指定决策表。 - -|=============== - - -*返回内容:* -返回内容是+org.flowable.dmn.model.DmnDefinition+的JSON。并包含完整的DMN定义模型。 - -[source,json,linenums] ----- -{ - "processes":[ - { - "id":"oneTaskProcess", - "xmlRowNumber":7, - "xmlColumnNumber":60, - "extensionElements":{ - - }, - "name":"The One Task Process", - "executable":true, - "documentation":"One task process description", - - ] -} ----- - - -=== DMN规则服务 - -==== 执行一个决策 - ----- -POST dmn-rule/execute ----- - -*Request body:* - -请求体应该包含_multipart/form-data_类型的数据。需要decisionKey。tenantId、parentdeploymentd和inputVariables (restVariables)映射是可选的。 - -*Response body:* - -[source,json,linenums] ----- -{ - "resultVariables": [ - [ - { - "name": "output1", - "type": "string", - "value": "result 1" - } - ], - [ - { - "name": "output1", - "type": "string", - "value": "result 2" - } - ], - [ - { - "name": "output1", - "type": "string", - "value": "result 3" - } - ] - ], - "url": "http://localhost:8080/flowable-rest/dmn-api/dmn-rule/execute" -} ----- -.执行一个决策 - 返回编码 -[options="header"] - - -[options="header"] -|=============== -|返回编码|描述 -|201|已执行该决策。 - -|=============== - -==== 执行一个单结果决策 ----- -POST dmn-rule/execute/single-result ----- - -*Request body:* - -请求体应该包含_multipart/form-data_类型的数据。需要decisionKey。tenantId、parentdeploymentd和inputVariables (restVariables)映射是可选的。 - -当多个规则有效时,返回500。 - -*注意:使用复合输出的单个命中是有效的(参见下面的响应)* - -*Response body:* - -[source,json,linenums] ----- -{ - "resultVariables": [ - { - "name": "output1", - "type": "string", - "value": "compound 1" - }, - { - "name": "output2", - "type": "string", - "value": "compound 2" - } - ], - "url": "http://localhost:8080/flowable-rest/dmn-api/dmn-rule/execute/single-result" -} ----- -.执行一个单结果决策 - 返回编码 -[options="header"] - - -[options="header"] -|=============== -|返回编码|描述 -|201|已执行指定决策。 -|500|指定决策返回多个结果。 - -|=============== - - - -=== 引擎 - -==== 获取一个DMN引擎信息 - ----- -GET dmn-management/engine ----- - -返回此rest服务中使用的DMN引擎的只读视图。 - - -*响应成功:* - -[source,json,linenums] ----- -{ - "name":"default", - "version":"6.5.0.event-SNAPSHOT", - "resourceUrl":"file://flowable-dmn/flowable.dmn.cfg.xml", - "exception":null -} ----- - -.获取引擎信息 - 返回编码 -[options="header"] - -[options="header"] -|=============== -|返回编码|描述 -|200|返回指定引擎信息。 - -|=============== diff --git a/docs/userguide/src/zh_CN/dmn/generate-html.sh b/docs/userguide/src/zh_CN/dmn/generate-html.sh deleted file mode 100755 index 51dc2ce7d04..00000000000 --- a/docs/userguide/src/zh_CN/dmn/generate-html.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -asciidoctor -a stylesheet=../base/flowable.css -o output/index.html index-html.adoc - -rm -rf output/images -mkdir output/images -cp -r images output - -## Copy Base Images -cp -r ../base/images output \ No newline at end of file diff --git a/docs/userguide/src/zh_CN/dmn/generate-pdf.sh b/docs/userguide/src/zh_CN/dmn/generate-pdf.sh deleted file mode 100755 index 44b4417f5b6..00000000000 --- a/docs/userguide/src/zh_CN/dmn/generate-pdf.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -rm -rf output/flowable-dmn-userguide.pdf -asciidoctor-pdf -o output/flowable-dmn-userguide.pdf index-pdf.adoc diff --git a/docs/userguide/src/zh_CN/dmn/images/decision_tables_1.png b/docs/userguide/src/zh_CN/dmn/images/decision_tables_1.png deleted file mode 100755 index 94c486dccab..00000000000 Binary files a/docs/userguide/src/zh_CN/dmn/images/decision_tables_1.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/dmn/images/decision_tables_10.png b/docs/userguide/src/zh_CN/dmn/images/decision_tables_10.png deleted file mode 100755 index 5129539da47..00000000000 Binary files a/docs/userguide/src/zh_CN/dmn/images/decision_tables_10.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/dmn/images/decision_tables_2.png b/docs/userguide/src/zh_CN/dmn/images/decision_tables_2.png deleted file mode 100755 index d62d1325229..00000000000 Binary files a/docs/userguide/src/zh_CN/dmn/images/decision_tables_2.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/dmn/images/decision_tables_3.png b/docs/userguide/src/zh_CN/dmn/images/decision_tables_3.png deleted file mode 100755 index 4c721c160e9..00000000000 Binary files a/docs/userguide/src/zh_CN/dmn/images/decision_tables_3.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/dmn/images/decision_tables_4.png b/docs/userguide/src/zh_CN/dmn/images/decision_tables_4.png deleted file mode 100755 index 97b9bf89c61..00000000000 Binary files a/docs/userguide/src/zh_CN/dmn/images/decision_tables_4.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/dmn/images/decision_tables_5.png b/docs/userguide/src/zh_CN/dmn/images/decision_tables_5.png deleted file mode 100755 index 7de7a2770ff..00000000000 Binary files a/docs/userguide/src/zh_CN/dmn/images/decision_tables_5.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/dmn/images/decision_tables_6.png b/docs/userguide/src/zh_CN/dmn/images/decision_tables_6.png deleted file mode 100755 index 6b3bca7ab37..00000000000 Binary files a/docs/userguide/src/zh_CN/dmn/images/decision_tables_6.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/dmn/images/decision_tables_7.png b/docs/userguide/src/zh_CN/dmn/images/decision_tables_7.png deleted file mode 100755 index 06109f7e735..00000000000 Binary files a/docs/userguide/src/zh_CN/dmn/images/decision_tables_7.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/dmn/images/decision_tables_8.png b/docs/userguide/src/zh_CN/dmn/images/decision_tables_8.png deleted file mode 100755 index c9761c8146f..00000000000 Binary files a/docs/userguide/src/zh_CN/dmn/images/decision_tables_8.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/dmn/images/decision_tables_9.png b/docs/userguide/src/zh_CN/dmn/images/decision_tables_9.png deleted file mode 100755 index 8d3c9de2676..00000000000 Binary files a/docs/userguide/src/zh_CN/dmn/images/decision_tables_9.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/dmn/index-common.adoc b/docs/userguide/src/zh_CN/dmn/index-common.adoc deleted file mode 100755 index b07d62c8b6e..00000000000 --- a/docs/userguide/src/zh_CN/dmn/index-common.adoc +++ /dev/null @@ -1,22 +0,0 @@ -== Introduction - -include::../base/header-Introduction.adoc[] - -include::ch02-Configuration.adoc[] - -include::ch03-API.adoc[] - -include::ch04-Spring.adoc[] - -include::ch05-Deployment.adoc[] - -include::ch06-DMN-Introduction.adoc[] - - -[[restApiChapter]] - -== DMN REST API - -include::../base/header-REST.adoc[] - -include::ch07-REST.adoc[] diff --git a/docs/userguide/src/zh_CN/dmn/index-html.adoc b/docs/userguide/src/zh_CN/dmn/index-html.adoc deleted file mode 100755 index da54da89682..00000000000 --- a/docs/userguide/src/zh_CN/dmn/index-html.adoc +++ /dev/null @@ -1,15 +0,0 @@ -= Flowable DMN 用户手册 (v 6.5.0.event-SNAPSHOT) -:doctype: book -:docinfodir: ../base -:docinfo1: header -:icons: font -:numbered: -:source-highlighter: pygments -:pygments-css: class -:pygments-linenums-mode: table -:compat-mode: -:pdf-page-size: A4 -:nofooter: - - -include::index-common.adoc[] diff --git a/docs/userguide/src/zh_CN/dmn/index-pdf.adoc b/docs/userguide/src/zh_CN/dmn/index-pdf.adoc deleted file mode 100755 index 6f66763c8ec..00000000000 --- a/docs/userguide/src/zh_CN/dmn/index-pdf.adoc +++ /dev/null @@ -1,14 +0,0 @@ -= Flowable DMN 用户手册 (v 6.5.0.event-SNAPSHOT) -:doctype: book -:toc: left -:toclevels: 4 -:icons: font -:numbered: -:source-highlighter: pygments -:pygments-css: class -:pygments-linenums-mode: table -:compat-mode: -:pdf-page-size: A4 -:nofooter: - -include::index-common.adoc[] diff --git a/docs/userguide/src/zh_CN/form/ch02-Configuration.adoc b/docs/userguide/src/zh_CN/form/ch02-Configuration.adoc deleted file mode 100755 index ddf2eba19ab..00000000000 --- a/docs/userguide/src/zh_CN/form/ch02-Configuration.adoc +++ /dev/null @@ -1,362 +0,0 @@ - -== 配置 - -[[configuration]] - - -=== 创建表单引擎 - -_Flowable 表单引擎的结构与Flowable流程引擎非常相似。 因此,文档的某些部分与其流程引擎对应部分相似._ - -Flowable Form引擎通过名为flowable.form.cfg.xml的XML文件进行配置。 请注意,如果您使用的是“springintegration,构建表单引擎的Spring样式”,则这不适用*。 - -获取FormEngine的最简单方法是使用org.flowable.form.engine.FormEngines类: - - -[source,java,linenums] ----- -FormEngine formEngine = FormEngines.getDefaultFormEngine() ----- - -这将在类路径上查找flowable.form.cfg.xml文件,并根据该文件中的配置构造引擎。 以下代码段显示了示例配置。 以下部分将详细介绍配置属性。 - -[source,xml,linenums] ----- - - - - - - - - - - - - - - ----- -请注意,配置XML实际上是Spring配置。 这并不意味着Flowable Form只能在Spring环境中使用! 我们只是在内部利用Spring的解析和依赖注入功能来构建引擎。 - -也可以使用配置文件以编程方式创建FormEngineConfiguration对象。 也可以使用不同的bean id(例如,参见第3行)。 - - -[source,java,linenums] ----- -FormEngineConfiguration. - createFormEngineConfigurationFromResourceDefault(); - createFormEngineConfigurationFromResource(String resource); - createFormEngineConfigurationFromResource(String resource, String beanName); - createFormEngineConfigurationFromInputStream(InputStream inputStream); - createFormEngineConfigurationFromInputStream(InputStream inputStream, String beanName); ----- -也可以不使用配置文件,并基于创建配置 -默认值(有关更多信息,请参阅<< configurationClasses类>>)。 - - -[source,java,linenums] ----- -FormEngineConfiguration.createStandaloneFormEngineConfiguration(); -FormEngineConfiguration.createStandaloneInMemFormEngineConfiguration(); ----- - -所有这些FormEngineConfiguration.createXXX()方法返回一个FormEngineConfiguration,如果需要可以进一步调整。 调用buildFormEngine()操作后,创建一个FormEngine: - -[source,java,linenums] ----- -FormEngine formEngine = FormEngineConfiguration.createStandaloneInMemFormEngineConfiguration() - .setDatabaseSchemaUpdate(FormEngineConfiguration.DB_SCHEMA_UPDATE_FALSE) - .setJdbcUrl("jdbc:h2:mem:my-own-db;DB_CLOSE_DELAY=1000") - .buildFormEngine(); ----- - -[[configurationRoot]] - - -=== 表单引擎配置类 - - - -flowable.form.cfg.xml文件必须包含一个具有id值为 'formEngineConfiguration' 的bean。 -[source,xml,linenums] ----- - ----- -然后使用该bean构造FormEngine。 - - -* *org.flowable.form.engine.impl.cfg.StandaloneFormEngineConfiguration*: the process engine is used in a standalone way. Flowable will take care of the transactions. By default, the database will only be checked when the engine boots (and an exception is thrown if there is no Flowable Form schema or the schema version is incorrect). -* *org.flowable.form.engine.impl.cfg.StandaloneInMemFormEngineConfiguration*: this is a convenience class for unit testing purposes. Flowable Form will take care of the transactions. An H2 in-memory database is used by default. The database will be created and dropped when the engine boots and shuts down. When using this, probably no additional configuration is needed). -* *org.flowable.form.spring.SpringFormEngineConfiguration*: To be used when the Form engine is used in a Spring environment. See <> for more information. - - -=== 插件方式集成流程引擎 - -除了在独立模式下运行外,还可以将表单引擎插入流程引擎。 这使得流程引擎可以识别它和其他引擎。 例如,这可以将包含BPMN模型和DMN模型的工件部署到流程引擎的部署服务API。 - -要使流程引擎知道表单引擎,需要将org.flowable.dmn.engine.configurator.FormEngineConfigurator添加到流程引擎配置中的配置程序列表中。 此配置程序是flowable-form-engine-configurator模块的一部分。 - - -[source,xml,linenums] ----- - - - - - - - - ... - - - - - - - - - - - - - ----- - - -[[databaseConfiguration]] - -=== 数据源配置 - -有两种方法可以配置Flowable 表单引擎将使用的数据库。 第一个选项是定义数据库的JDBC属性: -* *jdbcUrl*: 数据库的JDBC URL. -* *jdbcDriver*: 为特定数据库类型实现驱动程序. -* *jdbcUsername*: 用于连接数据库的用户名. -* *jdbcPassword*: 用于连接数据库的密码. - -基于提供的JDBC属性构造的数据源将具有默认链接:$$ http://www.mybatis.org/$$ [MyBatis]连接池设置。 可以选择设置以下属性来调整该连接池(取自MyBatis文档): - -* *jdbcMaxActiveConnections*: 连接池中处于被使用状态的连接的最大值。默认为10。 -* *jdbcMaxIdleConnections*: 连接池中处于空闲状态的连接的最大值。 -* *jdbcMaxCheckoutTime*: 连接被取出使用的最长时间,超过时间会被强制回收。 默认为20000(20秒)。 -* *jdbcMaxWaitTime*:这是一个底层配置,让连接池可以在长时间无法获得连接时, 打印一条日志,并重新尝试获取一个连接。(避免因为错误配置导致沉默的操作失败)。 默认为20000(20秒)。 - -示例数据库配置: - -[source,xml,linenums] ----- - - - - ----- - -我们的基准测试表明,在处理大量并发请求时,MyBatis连接池可能扛不住。 因此,我们建议使用javax.sql.DataSource实现并将其注入流程引擎配置(例如HikariCP,Tomcat JDBC连接池等): -[source,xml,linenums] ----- - - - - - - - - - - - - ... - ----- - - -请注意,Flowable 表单不附带允许您定义此类数据源的库。 所以你必须确保库在你的类路径上。 - -无论您使用的是JDBC还是数据源方法,都可以设置以下属性: - -* *databaseType*: 数据库类型,可以是如下的值(h2, mysql, oracle, postgres, mssql, db2). -* *databaseSchemaUpdate*:允许您设置策略以在表单引擎启动和关闭时如何处理数据库表. -** +false+ (default): 在创建表单引擎时检查库模式的版本,如果版本不匹配则抛出异常. -** ++true++: 在构建表单引擎时,执行检查并在必要时执行模式的更新。 如果schema不存在,则创建它. -** ++create-drop++: 在创建表单引擎时创建schema,并在关闭流程引擎时删除schema. - - -[[jndiDatasourceConfig]] - - -=== JNDI方式数据源配置 - -默认情况下,Flowable Form的数据库配置包含在每个Web应用程序的WEB-INF/classes中的db.properties文件中。 这并不总是理想的,因为它 -要求用户修改Flowable源中的db.properties并重新编译WAR文件,或者在每次部署时分解WAR并修改db.properties。 -通过使用JNDI(Java命名和目录接口)获取数据库连接,连接完全由Servlet容器管理,并且可以在WAR部署之外管理配置。 这也允许对db.properties文件提供的连接参数进行更多控制。 - -[[jndi_configuration]] - - -==== 配置 - -JNDI数据源的配置将根据您使用的servlet容器应用程序而有所不同。 以下说明适用于Tomcat,但对于其他容器应用程序,请参阅容器应用程序的文档。 - -如果使用Tomcat,则在$CATALINA_BASE/conf/[enginename]/[hostname]/[warname].xml中配置JNDI资源(对于Flowable UI,这通常是$CATALINA_BASE/conf/Catalina/localhost/flowable-app。XML)。 首次部署应用程序时,将从Flowable WAR文件复制默认上下文,因此如果已存在,则需要替换它。 例如,要更改JNDI资源以便应用程序连接到MySQL而不是H2,请将文件更改为以下内容: - -[source,xml,linenums] ----- - - - - ----- - -==== JNDI 属性 - -要配置JNDI数据源,请在Flowable UI的属性文件中使用以下属性: - -* spring.datasource.jndi-name=: 数据源的JNDI名称. -* datasource.jndi.resourceRef: 设置查询是否发生在J2EE容器中,换句话说,如果JNDI名称尚未包含它,则需要添加前缀“java:comp/env/”。 默认为“true”. - - -[[supporteddatabases]] - - -=== 支持的数据库厂商 - -下面列出了Flowable用于引用数据库的类型(区分大小写!)。 - -[[databaseTypes]] -[options="header"] -|=============== -|数据库类型|连接URL|Notes -|h2|jdbc:h2:tcp://localhost/flowable_form|Default configured database -|mysql|jdbc:mysql://localhost:3306/flowable_form?autoReconnect=true|Tested using mysql-connector-java database driver -|oracle|jdbc:oracle:thin:@localhost:1521:xe| -|postgres|jdbc:postgresql://localhost:5432/flowable_form| -|db2|jdbc:db2://localhost:50000/flowable_form| -|mssql|jdbc:sqlserver://localhost:1433;databaseName=flowable_form (jdbc.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver) _OR_ jdbc:jtds:sqlserver://localhost:1433/flowable_form (jdbc.driver=net.sourceforge.jtds.jdbc.Driver)|Tested using Microsoft JDBC Driver 4.0 (sqljdbc4.jar) and JTDS Driver -|=============== - - -[[creatingDatabaseTable]] - - -=== 创建表 - -Flowable表单使用链接:$$http://www.liquibase.org$$[Liquibase]来跟踪,管理和应用数据库架构更改。 -为数据库创建数据库表的最简单方法是: - -* 在classpath中添加flowable-form-engine JARS包 -* 添加合适的数据库驱动 -* 将Flowable配置文件(flowable.form.cfg.xml)添加到类路径中,指向您的数据库(请参阅<< databaseConfiguration,数据库配置部分>>) -* 执行DbSchemaCreate类的main方法 - -[[database.tables.explained]] - - -=== 数据库表名称解释 - -Flowable表单的数据库名称都以ACT_FO_开头。 - - -* ACT_FO_DATABASECHANGELOG: Liquibase使用此表来跟踪已运行的changesets. -* ACT_FO_DATABASECHANGELOGLOCK: Liquibase使用此表来确保一次只运行一个Liquibase实例. -* ACT_FO_FORM_DEFINITION: 此表包含已部署的表单定义的定义信息. -* ACT_FO_FORM_INSTANCE: 此表包含具有已由用户填写的值的表单实例. -* ACT_FO_FORM_DEPLOYMENT: 该表包含部署元数据. -* ACT_FO_FORM_RESOURCE: 此表包含表单定义资源. - -[[databaseUpgrade]] - - -=== 数据库升级 - -在运行升级之前,请确保备份数据库(使用数据库备份功能)。 - - -默认情况下,每次创建流程引擎时都会执行版本检查。 这通常在应用程序或Flowable Web应用程序的引导时发生一次。 如果Flowable库注意到库版本与Flowable数据库表的版本之间的差异,则抛出异常。 - -要升级,必须首先将以下配置属性放在flowable.form.cfg.xml配置文件中: -[source,xml,linenums] ----- - - - - - - - - - ----- - - 使用databaseSchemaUpdate设置为true即可。 - -[[formDefinitionCacheConfiguration]] - - -=== 部署缓存配置 - - -所有定义都被缓存(在解析之后),以避免每次需要表单时都访问数据库,并且表单数据不会更改。 默认情况下,此缓存没有限制。 要限制表单缓存使用的容器大小,请添加以下属性: -[source,xml,linenums] ----- - ----- - -设置此属性将使默认的LRU算法。 当然,此属性的“最佳”值取决于存储的表单总量和运行时实际使用的表单数。 - -您也可以注入自己的缓存实现。 自定义类必须实现org.flowable.form.engine.impl.persistence.deploy.DeploymentCache接口的bean: -[source,xml,linenums] ----- - - - ----- - - -[[loggingConfiguration]] - - -=== 日志 - -所有日志记录(flowable,spring,mybatis,...)都通过SLF4J进行路由,并允许选择您选择的日志记录实现。 - -*默认情况下,flowable-dmn-engine依赖项中不存在SFL4J-binding jar,这应该在项目中添加,以便使用您选择的日志框架。 -*如果没有添加实现jar,SLF4J将使用NOP-logger,不记录任何内容,除了警告不会记录任何内容。 有关这些绑定链接的更多信息,请访问:$$http://www.slf4j.org/codes.html#StaticLoggerBinder$$[http://www.slf4j.org/codes.html#StaticLoggerBinder]。 -使用Maven,添加例如这样的依赖(这里使用log4j),请注意您仍然需要添加一个版本: - -[source,xml,linenums] ----- - - org.slf4j - slf4j-log4j12 - ----- - -flowable-ui和flowable-rest webapps配置了使用Log4j binding.。 在运行所有flowable-*模块的测试时也使用Log4j。 - -在类路径中使用带有commons-logging的容器时的重要注意事项: -为了通过SLF4J路由spring-logging,使用了一个桥接器(参见链接:$$http://www.slf4j.org/legacy.html#jclOverSLF4J$$[http://www.slf4j.org/legacy.html#jclOverSLF4J])。 -如果您的容器提供了commons-logging实现,请按照此页面上的说明进行操作:$$http://www.slf4j.org/codes.html#release$$[http://www.slf4j.org/codes.html#release]确保稳定性。 - -使用Maven时的示例(省略版本): - -[source,xml,linenums] ----- - - org.slf4j - jcl-over-slf4j - ----- diff --git a/docs/userguide/src/zh_CN/form/ch03-API.adoc b/docs/userguide/src/zh_CN/form/ch03-API.adoc deleted file mode 100755 index a23f3520b11..00000000000 --- a/docs/userguide/src/zh_CN/form/ch03-API.adoc +++ /dev/null @@ -1,203 +0,0 @@ -[[chapterApi]] - -== Flowable 表单 API - -[[apiEngine]] - -=== 表单引擎 API 与服务类 - -表单引擎 API 是与 Flowable 表单交互的最常用方式。核心起点是可以通过 <> 中描述的几种方式创建的++表单引擎++。从表单引擎中,您能够获得各种其他服务类。 - -表单引擎和其服务类对象是线程安全的,因此您可以为整个服务保留其中一个引用。 - -image::images/api.services.png[align="center"] - -[source,java,linenums] ----- -FormEngine formEngine = FormEngines.getDefaultFormEngine(); -FormRuleService formRuleService = formEngine.getFormRuleService(); -FormRepositoryService formRepositoryService = formEngine.getFormRepositoryService(); -FormService formService = formEngine.getFormService(); -FormManagementService formManagementService = formEngine.getFormManagementService(); ----- - -++FormEngines.getDefaultFormEngine()++ 将在第一次调用时初始化并构建一个表单引擎,之后调用总是返回相同的表单引擎。使用 +FormEngines.init()+ 和 +FormEngines.destroy()+ 可以正确创建和关闭所有表单引擎。 - -FormEngines类将扫描所有 +flowable.form.cfg.xml+ 和 +flowable-form-context.xml+ 配置文件。对于所有 +flowable.form.cfg.xml+ 配置文件,表单引擎将以典型的Flowable方式构建:+FormEngineConfiguration.createFormEngineConfigurationFromInputStream(inputStream).buildFormEngine()+。对于所有 +flowable-form-context.xml+ 配置文件,表单引擎将以Spring方式构建:首先创建Spring应用程序上下文,然后表单引擎会从该应用程序上下文中获取。 - -所有的服务类均是无状态的。这意味着您可以轻松地在群集中的多个节点上运行Flowable表单模块,每个节点都连接同一个数据库,而不必担心哪台机器实际执行了旧的调用。对任何服务类的任何调用都是幂等的,无论它在何处执行。 - -*FormRepositoryService* 可能是Flowable表单引擎工作时所需的第一个服务类。该服务类提供用于管理和使用++部署文件++和++表单定义++的操作。表单定义是表单模型的根本概念(表单定义的主要概念在 <>中进行了解释)。 - -++部署文件++是 Flowable 表单引擎中的打包最小单元。一个部署文件中可以包含多个表单定义的JSON 文件。发布一个部署文件意味着将其部署到引擎相关表中,在该引擎中,所有表单定义在存储到数据库之前都会被校验和解析。从那一刻起,系统会感知到这个部署文件,并且部署文件中包含的任何表单都可以被执行。 - -此外,这个服务类允许您: - -* 查询引擎已知的表单定义的部署文件。 -* 检索表单定义的POJO类,它可用于使用Java中而不是JSON数据结构。 - -*FormService* 提供了使用用户为特定表单定义填写的值来创建表单实例的方法。它也可以被用于查询表单实例。 - -使用 Flowable 表单模块编写自定义应用程序时,通常不需要 *FormManagementService* 。它允许您检索有关引擎版本,数据库表和表元数据的信息。 - - -=== 异常策略 - -Flowable中的基础异常是 +org.flowable.engine.FlowableException+,这是一个未经检查的异常。这种异常可以被API随时抛出,其他特定方法中发生的“预期中的”异常被记录在link:$$http://www.flowable.org/docs/javadocs/index.html$$[文档]中。例如 ++FormRuleService++ 的摘录: - -尽管我们想要避免一个大的异常层次结构,下列的异常子类仍会在特定情况下被抛出。在流程执行或 API 调用期间发生的所有其他错误都不适合下面可能发生的异常,这些错误将作为常规 ++FlowableExceptions++ 抛出。 - -* ++FlowableOptimisticLockingException++:当由同一数据条目的并发访问引起的数据存储中发生乐观锁问题时抛出。 -* ++FlowableClassLoadingException++:当未找到请求加载的类或加载时发生错误时抛出。 -* ++FlowableObjectNotFoundException++:当请求或操作的对象不存在时抛出。 -* ++FlowableIllegalArgumentException++:这个异常表示在Flowable 表单 API调用中使用了非法参数、在引擎的配置中配置了非法值或者提供了非法值。 - -[[queryAPI]] - - -=== 查询 API - - -有两种方法可以从引擎查询数据:使用查询 API 和本地查询。查询 API 允许您使用流畅的 API 编写完全类型安全的查询。您可以为查询添加各种查询条件(所有条件共同应用逻辑与)与一个排序参数。示例如下: - -[source,java,linenums] ----- -List formDeployments = formRepositoryService.createDeploymentQuery() - .deploymentNameLike("deployment%") - .orderByDeployTime() - .list(); ----- - -有时您需要更强大的查询操作,例如,使用或运算符或使用查询 API 无法表达的查询。对于这些情况,我们引入了本地查询,允许您编写自己的 SQL 语句进行查询。返回类型由您使用的查询对象定义,数据会映射到正确的对象,例如 Deployment、FormInstance 等。由于查询将在数据库中触发,因此必须使用在数据库中定义的表名和列名,这需要一些有关内部数据结构的知识,建议谨慎使用本机查询。表名可以通过 API 进行检索,以使依赖尽可能小。 - -[source,java,linenums] ----- - -long count = formRepositoryService.createNativeDeploymentQuery() - .sql("SELECT count(*) FROM " + formManagementService.getTableName(FormDeploymentEntity.class) + " D1, " - + formManagementService.getTableName(FormDefinitionEntity.class) + " D2 " - + "WHERE D1.ID_ = D2.DEPLOYMENT_ID_ " - + "AND D1.ID_ = #{deploymentId}") - .parameter("deploymentId", deployment.getId()) - .count(); ----- - -[[apiUnitTesting]] - - -=== 单元测试 - -由于 Flowable 表单模块是一个嵌入式的 Java 引擎,因此为表单定义编写单元测试就像编写常规单元测试一样简单。 - -Flowable 支持 JUnit 4、JUnit 5 做单元测试。 - -在编写JUnit 5单元测试时,可以使用 +org.flowable.form.engine.test.FlowableFormExtension+。 -通过此扩展,表单引擎和服务类可用作测试和生命周期方法的参数。 -使用此++拓展++将启用 +org.flowable.form.engine.test.FormDeploymentAnnotation+ 注解(请参阅下面有关其使用和配置的说明),它将在类路径中查找默认配置文件。 -使用相同的配置文件时,表单引擎会在多个单元测试中静态缓存。 - -当使用 +@FormDeploymentAnnotation+ 注解测试方法时,在每次测试之前,将发布在+ FormDeploymentAnnotation#resources +中定义的表单文件。 -如果没有定义资源,将发布与测试类在同一包中的 ++testClassName.testMethod.form++ 形式的资源文件。 -在测试结束时,部署文件将会删除,包括所有相关的表单实例、定义等。 -有关更多信息,请参阅 ++FormDeploymentAnnotation++ 类。 - -在编写JUnit 4单元测试时,可以使用 +org.flowable.form.engine.test.FlowableFormRule+ 规则。通过这个规则,表单引擎和服务类可以通过 getter 方法获得。包括这个++规则++将允许使用 +org.flowable.form.engine.test.FormDeploymentAnnotation+ 注解(参见上面有关其使用和配置的说明),它将在类路径上查找默认配置文件。使用相同的配置文件时,表单引擎会在多个单元测试中静态缓存。 -也可以为规则提供自定义的引擎配置。 - -以下代码片段显示了使用 JUnit 5单元测试的示例。 - -.JUnit 5 test -[source,java,linenums] ----- -@ExtendWith(FlowableFormExtension.class) -// 如果需要自定义表单配置,则应取消注释下面的部分 -//@FormConfigurationResource("custom1.flowable.form.cfg.xml") -class MyFormDefinitionTest { - - private FormEngine formEngine; - - @BeforeEach - void setUp(FormEngine formEngine) { - this.formEngine = formEngine; - } - - @Test - @FormDeploymentAnnotation - void formUsageExample() { - FormService formService = formEngine.getFormService(); - - FormInstance result = formService.getFormInstanceModelById( - "f7689f79-f1cc-11e6-8549-acde48001122", null); - - Assertions.assertNotNull(result); - } -} ----- - -以下代码片段显示了使用 JUnit 4单元测试和 +FlowableFormRule+ (传递可选的自定义配置)的示例。 - -.JUnit 4 test -[source,java,linenums] ----- -public class MyFormDefinitionTest { - - @Rule - public FlowableFormRule flowableFormRule = new FlowableFormRule("custom1.flowable.form.cfg.xml"); - - @Test - @FormDeploymentAnnotation - public void formUsageExample() { - FormEngine formEngine = flowableFormRule.getFormEngine(); - FormService formService = dmnEngine.getFormService(); - - FormInstance result = formService.getFormInstanceModelById( - "f7689f79-f1cc-11e6-8549-acde48001122", null); - - Assert.assertNotNull(result)); - } -} ----- - - -[[apiFormEngineInWebApp]] - - -=== Web 应用程序中的表单引擎 - -+FormEngine+ 是一个线程安全的类,可以很容易地在多个线程之间共享。在 Web 应用程序中,这意味着可以在容器启动时创建一次表单引擎,并在容器关闭时关闭引擎。 - -以下代码片段显示了如何在普通的 Servlet 环境中编写一个简单的 +ServletContextListener+ 来初始化和销毁表单引擎: - -[source,java,linenums] ----- -public class FormEnginesServletContextListener implements ServletContextListener { - - public void contextInitialized(ServletContextEvent servletContextEvent) { - FormEngines.init(); - } - - public void contextDestroyed(ServletContextEvent servletContextEvent) { - FormEngines.destroy(); - } - -} ----- - -+contextInitialized+ 方法将委托给 +FormEngines.init()+。将在类路径中查找 +flowable.form.cfg.xml+ 配置文件,并为给定的配置创建 +FormEngine+ (例如,带有配置文件的多个JAR)。如果类路径上有多个这样的配置文件,请确保它们都有不同的名称。当需要 Form 引擎时,可以使用以下命令获取它: - -[source,java,linenums] ----- -FormEngines.getDefaultFormEngine() ----- - -或者 - -[source,java,linenums] ----- -FormEngines.getFormEngine("myName"); ----- - -当然,也可以如 <> 所述,使用创建表单引擎的任何变体。 - - -上下文监听器的 ++contextDestroyed++ 方法委托给++FormEngines.destroy()++。这将正确关闭所有初始化的表单引擎。 diff --git a/docs/userguide/src/zh_CN/form/ch04-Spring.adoc b/docs/userguide/src/zh_CN/form/ch04-Spring.adoc deleted file mode 100755 index c240c834d7e..00000000000 --- a/docs/userguide/src/zh_CN/form/ch04-Spring.adoc +++ /dev/null @@ -1,128 +0,0 @@ -[[springintegration]] -== 集成Spring - -虽然你可以在没有Spring的情况下使用Flowable 表单,但我们提供了一些非常好的集成功能,本章将对此进行说明。 - -=== FormEngineFactoryBean - -表单引擎可以按照常规的Spring bean方式进行配置.整合引用到的类是org.flowable.form.spring.FormEngineFactoryBean.该bean持有一个表单引擎配置类并创建表单引擎.这意味着Spring属性的创建和配置与 <> 中记录的相同.关于Spring集成和配置引擎bean如下所示 -[source,xml,linenums] ----- - - ... - - - - - - ----- - -注意,formEngineConfiguration bean现在使用的是 +org.flowable.form.spring.SpringFormEngineConfiguration+ 类。 - -=== 自动部署资源 -集成Spring还具有部署资源的特性。在配置表单引擎时,您可以指定一组资源.当表单引擎被创建时,将扫描和部署这些资源并过滤防止重复部署。只有资源被更改时,才会将重新部署部署到Flowable 表单数据库.这在经常重启包含大量表单资源的Spring容器中具有很大的意义(例如,测试) - -例如: -[source,xml,linenums] ----- - - ... - - - - - - ----- - -默认情况下,上面的配置会将匹配过滤后的所有资源进行分组并单独部署到Flowable 表单引擎中,在整个部署过程中重复过滤以防止重新部署未更改的资源.在某些情况下,你可能并不想这么做.例如,如果以这种方式部署一组表单资源,并且这些资源中只有一个表单定义更改了,整个流程定义部署将被视为新的并且被重新部署,尽管实际上只改变了一个但是每个表单都被定义为了新的版本, -为了能够自定义部署的方式,您可以在 +SpringFormEngineConfiguration+ 中,指定 +deploymentMode+ 属性。该属性定义了从过滤器匹配的资源集合以及确定部署的方式。默认情况下,该属性提供3个默认属性: - -* ++default++: 将所有资源分组到单个部署中,并对该部署应用重复过滤。如果您未指定其他值,将默认使用它。 -* ++single-resource++: 为每个单独的资源单独部署,并对该部署应用重复过滤。适用于单独部署某个已更改表单定义的资源,仅创建该表单定义的新版本。 -* ++resource-parent-folder++: 为共享同一父文件夹的资源创建单独的部署,并对该部署应用重复过滤。适用于为大多数资源创建单独的部署,但仍可以通过将它们放在共享文件夹中来对其进行分组。以下是为 ++deploymentMode++ 属性指定 +single-resource+ 配置的示例: - -[source,xml,linenums] ----- - - ... - - - ----- - -除了使用上面列出的 +deploymentMode+ 属性之外,您还可以自定义属性来实现部署。如果需要,您可以创建 +SpringFormEngineConfiguration+ 的子类并重写+getAutoDeploymentStrategy(String deploymentMode)+ 方法。该法确定将哪个部署策略用于 +deploymentMode+ 配置的特定值。 - -[[springUnitTest]] - -=== 单元测试 - -与Spring集成时,使用标准的<>来测试表单将会变得非常简单. -以下示例展示了如何在基于Spring的JUnit 4和5测试中测试表单: - -.JUnit 5 测试 -[source,java,linenums] ----- -@ExtendWith(FlowableFormSpringExtension.class) -@ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = SpringJunitJupiterTest.TestConfiguration.class) -public class SpringJunit4Test { - - @Autowired - private FormEngine formEngine; - - @Autowired - private FormService formService; - - @Test - @FormDeploymentAnnotation - public void simpleFormInstanceTest() { - FormInstance result = formService.getFormInstanceModelById( - "f7689f79-f1cc-11e6-8549-acde48001122", null); - - Assertions.assertNotNull(result)); - } -} ----- - -使用 +FlowableFormSpringExtension+ 时允许使用 +Deployment+ 注解。 - -.JUnit 4 测试 -[source,java,linenums] ----- -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration("classpath:org/flowable/spring/test/junit4/springTypicalUsageTest-context.xml") -public class SpringJunit4Test { - - @Autowired - private FormEngine formEngine; - - @Autowired - private FormService formService; - - @Autowired - @Rule - public FlowableFormRule flowableSpringRule; - - @Test - @FormDeploymentAnnotation - public void simpleFormInstanceTest() { - FormInstance result = formService.getFormInstanceModelById( - "f7689f79-f1cc-11e6-8549-acde48001122", null); - - Assert.assertNotNull(result)); - } -} ----- - -注意,在测试时,您需要在Spring配置中定义 _org.flowable.form.engine.test.FlowableFormRule_ bean(在上面的示例中通过自动装配注入)。 -[source,xml,linenums] ----- - - - - ----- diff --git a/docs/userguide/src/zh_CN/form/ch05-Deployment.adoc b/docs/userguide/src/zh_CN/form/ch05-Deployment.adoc deleted file mode 100755 index 91dab063d48..00000000000 --- a/docs/userguide/src/zh_CN/form/ch05-Deployment.adoc +++ /dev/null @@ -1,141 +0,0 @@ -[[chDeployment]] - -== 部署 - -=== 表单定义 - -**表单定义**带有++.form++后缀名,可以被部署到**表单引擎**。 - -当**表单引擎**接入**流程引擎**后,**表单定义**和与此流程相关其他资源,将被打包进一个业务存档(BAR, Business archive)中。若使用了 flowable-form-engine-configurator 或 flowable-form-spring-configurator 模块,**流程引擎**部署服务将负责把表单资源部署到**流程引擎**中。 - - -==== 表单定义 - -每个**表单定义**由一个或多个表单字段定义组成。当部署一个**表单定义**时,其信息将会被插入到 ACT_FO_FORM_DEFINITION 表中。 - - -==== 编程方式部署 - -可使用如下方式部署一个**表单定义**: - -[source,java,linenums] ----- -String formDefinition = "path/to/definition-one.form"; -ZipInputStream inputStream = new ZipInputStream(new FileInputStream(barFileName)); - -formRepositoryService.createDeployment() - .name("definition-one") - .addClasspathResource(formDefinition) - .deploy(); - ----- - -[[versioningOfFormDefinitions]] - - -=== 表单定义的版本管理 - -**表单定义**的版本会在部署期间创建,Flowable在将**表单定义**存储到表单数据库前,为其分配一个版本。 - -对于每个**表单定义**,执行以下步骤来初始化这些属性++key++、++version++、 ++name++和++id++: - -* 表单定义JSON文件中的++key++属性,被用作数据库中表单定义信息表的++key++属性。 -* 表单定义JSON文件中的++name++属性,被用作数据库中表单定义信息表的++name++属性。 -* 当首次以一个特定的++key++属性部署表单定义时,将分配版本为1。对于具有相同++key++属性表单定义的所有后续部署,版本将设置为当前已部署的最大版本号加1。++key++属性用来区分不同的表单定义。 -* ++id++属性是一个唯一的编号,用以保证在集群环境下,流程定义缓存中,流程++id++的唯一性。 - -表单定义示例如下: - -[source,json,linenums] ----- -{ - "key": "form1", - "name": "My first form", - "fields": [ - { - "id": "input1", - "name": "Input1", - "type": "text", - "required": false, - "placeholder": "empty" - } - ] -} ----- - -当部署此表单定义后,数据库中表单定义信息表将如下所示: - -[options="header"] -|=============== -|id|key|name|version -|e29d4126-ed4d-11e6-9e00-7282cbd6ce64|form1|My first form|1 - -|=============== - - -假设我们现在部署相同表单定义的一个更新版本(例如,更改文本变量),但表单定义的++key++属性保持不变。数据库中表单定义信息表将包含以下条目: - -[options="header"] -|=============== -|id|key|name|version -|e29d4126-ed4d-11e6-9e00-7282cbd6ce64|form1|My first form|1 -|e9c2a6c0-c085-11e6-9096-6ab56fad108a|form1|My first form|2 - -|=============== - -如果我们创建第二个表单定义,如下所示,并将其部署到Flowable**表单引擎**,第三行将会添加到表中。 - -[source,xml,linenums] ----- -{ - "key": "form2", - "name": "My second form", - "fields": [ - { - "id": "input2", - "name": "Input2", - "type": "text", - "required": false, - "placeholder": "empty" - } - ] -} ----- - -数据库中表单定义信息表将如下所示: - -[options="header"] -|=============== -|id|key|name|version -|e29d4126-ed4d-11e6-9e00-7282cbd6ce64|form1|My first form|1 -|e9c2a6c0-c085-11e6-9096-6ab56fad108a|form1|My first form|2 -|d317d3f7-e948-11e6-9ce6-b28c070b517d|form2|My second form|1 - -|=============== - -请注意新表单定义的++key++属性与第一个表单定义不同。 Flowable**表单引擎**仅使用++key++属性区分表单定义。因此,新的表单定义部署版本为1。 - - -[[deploymentCategory]] - - -=== 类别 - -**表单部署**和**表单定义**都可以具有用户定义的类别。 -部署类别可以在如下API中指定: - -[source,java,linenums] ----- -formRepository - .createDeployment() - .category("yourCategory") - ... - .deploy(); ----- - -表单定义类别可以在如下API中指定: - -[source,java,linenums] ----- -formRepository.setFormDefinitionCategory("e9c2a6c0-c085-11e6-9096-6ab56fad108a", "yourCategory"); ----- diff --git a/docs/userguide/src/zh_CN/form/ch06-Form-Introduction.adoc b/docs/userguide/src/zh_CN/form/ch06-Form-Introduction.adoc deleted file mode 100755 index e6a80c429e1..00000000000 --- a/docs/userguide/src/zh_CN/form/ch06-Form-Introduction.adoc +++ /dev/null @@ -1,68 +0,0 @@ -[[formIntroduction]] - -== 表单介绍 -[[whatIsFormDefinition]] - -=== 表单定义是什么? - - -对于BPMN引擎而言,我们沿用了BPMN规范,同理对与DMN引擎,我们使用了DMN规范。但是对于开始或任务表单,并不存在类似的共性问题让我们使用。因此,我们自己定义了一个基于JSON格式的的表单结构定义,我们使用这种结构作为Flowable表单编辑器的输出格式,而且我们会在Flowable任务应用中提取该结构让开始或任务表单使用。 - -[[formDefining]] - -=== Defining a form - -用你最爱的文本或JSON编辑器新建一个JSON文件,然后给这个文件起个个性的名字。确保这个文件的后缀为.form,比如shareniu.fom,否则表单引擎将无法部署此文件。 - -表单的JSON定义以key、name和description开头。表单引擎通过属性key来辨别表单在整个表单引擎中的唯一身份。对于来源相同的同一个表单定义的版本系统也是基于属性key运作的。第二部分是一个数组类型fields,表单定义的字段在这里阐明。第三部分是可选的,用来定义表单的结果outcomes。示例如下: -[source,json,linenums] ----- -{ - "key": "form1", - "name": "My first form", - "fields": [ - { - "id": "input1", - "name": "Input1", - "type": "text", - "required": false, - "placeholder": "empty" - } - ], - "outcomes": [ - { - "id": "null", - "name": "Accept" - }, - { - "id": "null", - "name": "Reject" - } - ] -} ----- - -每个表单字段都有一个id、name和type属性。在同一个表单定义中id应该是独一无二的。当一个用户完成表单后id还能当作变量名使用。在这个小例子中,一个名叫input1的流程变量被创建了,用户填入这个文本字段里的东西就是这个变量的值。结果outcomes也可以被映射成一个变量,此变量基于表单标识符,格式为:"form__outcome"。举例说明,选中的结果会被设置为一个名叫"form_form1_outcome"的变量。你可以通过表达式${form_form1_outcome == "Accept"}来检验结果outcome是否为'Accept' - -表单支持以下类型字段 - -* text: 文本字段 -* multi-line-text: 多行文本字段 - -* integer: 文本字段,但是只允许数字类型的值 - -* boolean: 复选框字段 - -* date: 日期字段 - -* dropdown: 选择框字段,定义字段时可以设置选项的值 - -* radio-buttons: 单选字段,定义字段时可以设置选项的值 - -* people: 选择框字段,可以选中用户表里的一个用户 - -* functional-group: 选择框字段,可以选中分组表里的一个组 - -* upload: 上传文件字段 - -* expression: 一个标签,在标签文本中你可以运用JUEL表达式操作变量或其他动态的值 diff --git a/docs/userguide/src/zh_CN/form/ch07-REST.adoc b/docs/userguide/src/zh_CN/form/ch07-REST.adoc deleted file mode 100755 index 6b22a99c852..00000000000 --- a/docs/userguide/src/zh_CN/form/ch07-REST.adoc +++ /dev/null @@ -1,703 +0,0 @@ - -=== 部署 - - -*当使用tomcat时, 请参考在<>中的用法。* - -==== 部署列表 - ----- -GET form-repository/deployments ----- - -.URL查询参数 -[options="header"] -|=============== -|参数名称|是否必须|参数类型|描述 - -|name|否|字符串|仅返回根据名称查询返回的部署结果集. - -|name模糊查询|否|字符串|仅返回根据名称模糊匹配的部署结果集. - -|category|否|字符串|仅返回符合类别的部署结果集. - -|不等于category|否|字符串|仅返回不等于该类别的其他部署结果集. - -|tenantId|否|字符串|仅返回给符合租户ID的部署结果集. - -|模糊匹配tenantId值|否|字符串|仅返回模糊匹配到租户ID值的部署结果集. - -|withoutTenantId|否|布尔|如果为 true 则仅返回未设置tenantId的部署。如果为 false 则忽略参数租户ID。 - -|sort|否|'id' (默认), '名称', '部署时间' or '租户ID'|要排序的属性要与 'order' 一起使用. - -|普通的分页和排序可以用这个URL. - -|=============== - - -.REST 响应编码 -[options="header"] -|=============== -|响应编码|描述 -|200|表示请求成功. - -|=============== - - -*成功响应正文:* - -[source,json,linenums] ----- -{ - "data": [ - { - "id": "10", - "name": "flowable-form-examples", - "deploymentTime": "2010-10-13T14:54:26.750+02:00", - "category": "examples", - "url": "http://localhost:8081/form-api/form-repository/deployments/10", - "tenantId": null - } - ], - "total": 1, - "start": 0, - "sort": "id", - "order": "asc", - "size": 1 -} ----- - - - -==== 获取单个部署 - ----- -GET form-repository/deployments/{deploymentId} ----- - -.获取单个部署信息 - 请求参数 -[options="header"] -|=============== -|参数名称|是否必须|值类型|描述 - -|部署ID|是|字符串|根据部署ID获取部署信息. - -|=============== - - - -.获取部署信息 - 响应编码 -[options="header"] -|=============== -|响应编码|描述 - -|200|表示该部署信息已经找到并且返回. - -|404|表示请求的部署信息未找到. - -|=============== - - -*成功响应体:* - -[source,json,linenums] ----- -{ - "id": "10", - "name": "flowable-form-examples", - "deploymentTime": "2010-10-13T14:54:26.750+02:00", - "category": "examples", - "url": "http://localhost:8081/form-api/form-repository/deployments/10", - "tenantId" : null -} ----- - - - -==== 创建部署信息 - ----- -POST form-repository/deployments ----- - - -*请求正文:* - - -请求正文应包含multipart / form-data类型的数据。 请求中应该只有一个文件,任何其他文件都将被忽略。 部署名称是传入的文件字段的名称。 - - -可以在名称为tenantId的请求正文中传递附加参数(表单字段)。 此字段的值将用作完成此部署的租户的标识符。 - - -.创建新的部署信息 - 响应编码 - -[options="header"] -|=============== -|响应编码|描述 - -|201|表示已经部署成功. - -|400|表示请求正文中不存在任何内容,或者部署不支持内容mime-type。 状态描述包含其他信息。 - -|=============== - - -*成功响应正文:* - - -[source,json,linenums] ----- -{ - "id": "10", - "name": "simple.form", - "deploymentTime": "2010-10-13T14:54:26.750+02:00", - "category": null, - "url": "http://localhost:8081/form-api/form-repository/deployments/10", - "tenantId" : "myTenant" -} ----- - - -==== 删除部署信息 - ----- -DELETE form-repository/deployments/{deploymentId} ----- - -.删除一个部署信息 - 传输参数 -[options="header"] -|=============== -|参数|是否必须|值类型|描述 -|部署ID|是|字符串|要删除的部署的标识符。 - -|=============== - - -.删除某个部署 - 响应编码 -[options="header"] -|=============== -|响应编码|描述 -|204|表示已找到部署并已删除。 响应体是空的。 - -|404|表示未找到请求的部署。 - -|=============== - - - -==== 获取部署资源内容 - ----- -GET form-repository/deployments/{deploymentId}/resourcedata/{resourceId} ----- - -.获取部署资源内容 - 请求参数 -[options="header"] -|=============== -|参数|是否必须|值类型|描述 - -|部署ID|是|字符串|请求的资源所属的部署标识符。 - -|资源ID|必须|字符串|获取数据的资源的标识符。 *确保对resourceId进行URL编码,以防它包含正斜杠。 举个例子, 比如 'forms%2Fmy-form.form' 代替 'forms/my-form.form'.* - -|=============== - - - -.获取部署资源内容 - 响应编码 - -[options="header"] -|=============== -|响应编码|描述 -|200|表示已找到部署和资源,并且已返回资源数据。 - -|404|表示未找到请求的部署,或者部署中不存在具有给定ID的资源。 状态描述包含其他信息。 - -|=============== - - -*成功响应正文:* - - -响应正文将包含所请求资源的二进制资源内容。 响应内容类型将与资源'mimeType'属性中返回的类型相同。 此外,还设置了内容处置标题,允许浏览器下载文件而不是显示文件。 - -=== 表单定义 - - -==== 表单定义列表 - ----- -GET form-repository/form-definitions ----- - -.表单定义列表 - 请求参数 -[options="header"] -|=============== -|参数|是否必须|参数类型|描述 -|version|否|整型|仅返回给定版本定义的表单. - -|name|否|字符串|仅返回给定名称的定义的表单。 - -|根据name模糊匹配|否|字符串|仅返会根据名称模糊匹配到的定义表单 - -|key|否|字符串|仅返回具有给定键的表单定义。 - -|模糊匹配key|否|字符串|仅返回模糊匹配给定键的表单定义. - -|resourceName|否|字符串|仅返回具有给定资源名称的表单定义 - -|模糊匹配resourceName|否|字符串|仅返回具有模糊匹配资源名称的表单定义 - -|category|否|字符串|仅返回给定类别的表单定义。 - -|模糊匹配category|否|字符串|仅返回模糊匹配给定类别的表单定义。 - -|不等于category|否|字符串|仅返回非给定类别的表单定义。 - -|deploymentId|否|字符串|仅返回作为具有给定标识符的部署的一部分的表单定义。 - -|latest|否|布尔|仅返回最新的表单定义版本。 只能与'key'和'keyLike'参数一起使用,使用任何其他参数将导致400响应。 - -|sort|否|'name' (default), 'id', 'key', 'category', 'deploymentId' 和 'version'|要排序的属性,与“order”一起使用。 - -|一般 <>可以用在这个请求. - -|=============== - - -.表单定义列表 - 响应编码 - -[options="header"] -|=============== -|响应编码|描述 -|200|表示请求成功,并返回表单定义 - -|400|表示参数以错误的格式传递,或者“latest”与“key”和“keyLike”以外的其他参数一起使用。 状态消息包含其他信息。 - -|=============== - - - -*成功响应正文:* - -[source,json,linenums] ----- -{ - "data": [ - { - "id" : "818e4703-f1d2-11e6-8549-acde48001122", - "url" : "http://localhost:8182/form-repository/form-definitions/simpleForm", - "version" : 1, - "key" : "simpleForm", - "category" : "Examples", - "deploymentId" : "818e4703-f1d2-11e6-8549-acde48001121", - "parentDeploymentId" : "2", - "name" : "The Simple Form", - "description" : "This is a form for testing purposes", - } - ], - "total": 1, - "start": 0, - "sort": "name", - "order": "asc", - "size": 1 -} ----- - - -==== 获取定义的表单 - - ----- -GET repository/form-definitions/{formDefinitionId} ----- - - -.获取表单 - 请求参数 -[options="header"] -|=============== -|参数|是否必须|值类型|描述 -|formDefinitionId|是|字符串|要获取的流程定义的标识符。 - -|=============== - - -.获取定义的表单 - 响应编码 -[options="header"] -|=============== -|Response code|Description -|响应编码|描述 -|200|表示已找到并返回表单定义。 - -|404|表示找不到请求的表单定义。 - -|=============== - - -*成功返回例子:* - -[source,json,linenums] ----- -{ - "id" : "818e4703-f1d2-11e6-8549-acde48001122", - "url" : "http://localhost:8182/form-repository/form-definitions/simpleForm", - "version" : 1, - "key" : "simpleForm", - "category" : "Examples", - "deploymentId" : "818e4703-f1d2-11e6-8549-acde48001121", - "parentDeploymentId" : "2", - "name" : "The Simple Form", - "description" : "This is a form for testing purposes", -} ----- - - -==== 获取表单定义资源内容 - ----- -GET repository/form-definitions/{formDefinitionId}/resourcedata ----- - -.获取表单定义资源内容 - 请求参数 -[options="header"] -|=============== -|参数名|是否必须|参数类型|描述 - -|formDefinitionId|是|字符串|用于获取资源数据的表单定义的标识符。 - -|=============== - -*返回值:* - -返回的编码和响应体与+GET form-repository/deployment/{deploymentId}/resourcedata/{resourceId}+ 一样. - - -==== 获取定义表单的表单模型 - ----- -GET form-repository/form-definitions/{formDefinitionId}/model ----- - -.获取定义表单的表单模型 - 请求参数 -[options="header"] -|=============== -|请求参数|是否必须|参数类型|描述 - -|formDefinitionId|是|字符串|获取模型的表单定义的标识符。 -|=============== - - -.获取定义表单的表单模型 - 响应编码 -[options="header"] -|=============== -|响应编码|描述 -|200|表示找到了表单定义并返回了模型. - -|404|表示找不到请求的表单定义。 - -|=============== - - -*响应正文:* -响应主体是+ org.flowable.form.model.FormModel +的JSON表示,并包含完整的表单定义模型。 - -=== 表单实例 - - -==== 获取表单实例 - - ----- -GET form/form-instances/{formInstanceId} ----- - -.获取表单实例 - 请求参数 -[options="header"] -|=============== -|请求参数|是否必须|参数类型|描述 - -|formInstanceId|是|字符串|要获取的表单实例的标识符。 - -|=============== - - -.获取表单实例 - 响应编码 -[options="header"] -|=============== -|响应编码|描述 -|200|表示找到并返回了表单实例. - -|404|表示找不到请求的表单实例。 - -|=============== - - -*成功响应正文:* -[source,json,linenums] ----- -{ - "id":"48b9ac82-f1d3-11e6-8549-acde48001122", - "url":"http://localhost:8182/form/form-instances/48b9ac82-f1d3-11e6-8549-acde48001122", - "formDefinitionId":"818e4703-f1d2-11e6-8549-acde48001122", - "taskId":"88", - "processInstanceId":"66", - "processDefinitionId":"oneTaskProcess:1:158", - "submittedDate":"2013-04-17T10:17:43.902+0000", - "submittedBy":"testUser", - "formValuesId":"818e4703-f1d2-11e6-8549-acde48001110", - "tenantId": null -} ----- - - -==== 存储表单实例 - ----- -POST form/form-instances ----- - -*请求正文(以流程定义ID开头):* - -[source,json,linenums] ----- -{ - "formDefinitionId":"818e4703-f1d2-11e6-8549-acde48001122", - "taskId":"88", - "processInstanceId":"66", - "processDefinitionId":"oneTaskProcess:1:158", - "variables": { - "input1": "test" - } -} ----- - -*请求正文(从表单定义键开始):* - -[source,json,linenums] ----- -{ - "formDefinitionKey":"simpleForm", - "taskId":"88", - "processInstanceId":"66", - "processDefinitionId":"oneTaskProcess:1:158", - "variables": { - "input1": "test" - } -} ----- - - - -在请求正文中只能使用+ formDefinitionId +或+ formDefinitionKey +中的一个。 参数+变量+和+ tenantId +是可选的。 如果省略+ tenantId +,将使用默认租户。 有关变量格式的更多信息可以在<>中找到。 - -.存储表单实例 - 响应代码 -[options="header"] -|=============== -|响应吗|描述 -|201|表示已创建表单实例。 - -|400|表示未找到表单定义(基于标识符或键),通过发送给定消息未存储表单实例,或者已传递无效变量。 状态描述包含有关错误的其他信息。 - -|=============== - - -*响应成功正文:* - -[source,json,linenums] ----- -{ - "id":"48b9ac82-f1d3-11e6-8549-acde48001122", - "url":"http://localhost:8182/form/form-instances/48b9ac82-f1d3-11e6-8549-acde48001122", - "formDefinitionId":"818e4703-f1d2-11e6-8549-acde48001122", - "taskId":"88", - "processInstanceId":"66", - "processDefinitionId":"oneTaskProcess:1:158", - "submittedDate":"2013-04-17T10:17:43.902+0000", - "submittedBy":"testUser", - "formValuesId":"818e4703-f1d2-11e6-8549-acde48001110", - "tenantId": null -} ----- - - -[[restProcessInstancesGet]] - - -==== 表单实例列表 - ----- -GET form/form-instances ----- - -.表单实例列表 - 请求参数 -[options="header"] -|=============== -|请求参数|是否必须|值类型|描述 - -|id|否|字符串|仅返回具有给定标识符的流程实例。 - -|表单定义ID|否|字符串|仅返回具有给定表单定义标识符的表单实例。 - -|模糊匹配表单ID|否|字符串|仅返回具有表单定义标识符(模糊匹配给定值)的表单实例。 - -|任务ID|否|字符串|仅返回具有给定任务标识符的表单实例。 -|模糊匹配任务ID|否|字符串|仅返回具有任务标识符(如模糊匹配给定值)的表单实例。 - -|流程实例ID|否|字符串|仅返回具有给定流程实例标识符的表单实例。 - -|模糊匹配表单实例ID|否|字符串|仅返回具有与给定值(模糊匹配流程实例标识符)的表单实例。 - -|流程定义ID|否|字符串|仅返回具有给定流程定义标识符的表单实例。 - -|模糊匹配流程定义ID|否|字符串|仅返回具有与给定值(模糊匹配的流程定义标识符)的表单实例。 - -|由...提交|否|字符串|仅返回由...提交的给定提交的表单实例。 - -|模糊匹配由...提交|否|字符串|只返回模糊匹配给定值的提交的表单实例。 - -|租户ID|否|字符串|仅返回具有给定租户ID的流程实例。 - -|模糊匹配租户ID|否|字符串|仅返回具有类似给定值的(模糊匹配租户ID)的流程实例。 - -|没有租户ID|否|布尔|如果 true,则仅返回没有设置租户ID的流程实例。 如果是false,则忽略 租户ID 参数。 - -|排序|否|字符串|排序字段,应该是 提交日期 (默认)或 租户ID。 - -一般<>可以用在本链接 -|=============== - - -.表单实例列表 - 响应编码 -[options="header"] -|=============== -|响应编码|描述 -|200|表示请求成功,并返回表单实例 - -|400|表示参数以错误的格式传递。 状态消息包含其他信息。 - -|=============== - - -*成功响应正文:* - -[source,json,linenums] ----- -{ - "data":[ - { - "id":"48b9ac82-f1d3-11e6-8549-acde48001122", - "url":"http://localhost:8182/form/form-instances/48b9ac82-f1d3-11e6-8549-acde48001122", - "formDefinitionId":"818e4703-f1d2-11e6-8549-acde48001122", - "taskId":"88", - "processInstanceId":"66", - "processDefinitionId":"oneTaskProcess:1:158", - "submittedDate":"2013-04-17T10:17:43.902+0000", - "submittedBy":"testUser", - "formValuesId":"818e4703-f1d2-11e6-8549-acde48001110", - "tenantId": null - } - ], - "total":1, - "start":0, - "sort":"submittedDate", - "order":"asc", - "size":1 -} ----- - - -==== 查询表单实例 - ----- -POST query/form-instances ----- - -*请求正文:* - -[source,json,linenums] ----- -{ - "formDefinitionId":"818e4703-f1d2-11e6-8549-acde48001122" -} ----- - -请求正文可以包含可以在查询<>中使用的所有可能的过滤器 - -普通 <> 可用于此URL。 - - -.查询表单实例 - 响应编码 -[options="header"] -|=============== -|响应编码|描述 -|200|表示请求成功,并返回表单实例 - -|400|表示参数以错误的格式传递。 状态消息包含其他信息 - -|=============== - -*成功响正文:* - -[source,json,linenums] ----- -{ - "data":[ - { - "id":"48b9ac82-f1d3-11e6-8549-acde48001122", - "url":"http://localhost:8182/form/form-instances/48b9ac82-f1d3-11e6-8549-acde48001122", - "formDefinitionId":"818e4703-f1d2-11e6-8549-acde48001122", - "taskId":"88", - "processInstanceId":"66", - "processDefinitionId":"oneTaskProcess:1:158", - "submittedDate":"2013-04-17T10:17:43.902+0000", - "submittedBy":"testUser", - "formValuesId":"818e4703-f1d2-11e6-8549-acde48001110", - "tenantId": null - } - ], - "total":1, - "start":0, - "sort":"submittedDate", - "order":"asc", - "size":1 -} ----- - - -=== 表单引擎 - - -==== 获取表单引擎信息 - ----- -GET form-management/engine ----- - - -返回此REST服务中使用的引擎的只读视图。 - - -*成功响应正文:* - -[source,json,linenums] ----- -{ - "name":"default", - "version":"6.5.0.event-SNAPSHOT", - "resourceUrl":"file://flowable/flowable.form.cfg.xml", - "exception":null -} ----- - - -.获取引擎信息 - 响应编码 -[options="header"] -|=============== -|响应编码|描述 - -|200|表示返回表单引擎信息。 - -|=============== - diff --git a/docs/userguide/src/zh_CN/form/generate-html.sh b/docs/userguide/src/zh_CN/form/generate-html.sh deleted file mode 100755 index 51dc2ce7d04..00000000000 --- a/docs/userguide/src/zh_CN/form/generate-html.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -asciidoctor -a stylesheet=../base/flowable.css -o output/index.html index-html.adoc - -rm -rf output/images -mkdir output/images -cp -r images output - -## Copy Base Images -cp -r ../base/images output \ No newline at end of file diff --git a/docs/userguide/src/zh_CN/form/generate-pdf.sh b/docs/userguide/src/zh_CN/form/generate-pdf.sh deleted file mode 100755 index dc33052522a..00000000000 --- a/docs/userguide/src/zh_CN/form/generate-pdf.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -rm -rf output/flowable-form-userguide.pdf -asciidoctor-pdf -o output/flowable-form-userguide.pdf index-pdf.adoc diff --git a/docs/userguide/src/zh_CN/form/images/api.services.png b/docs/userguide/src/zh_CN/form/images/api.services.png deleted file mode 100755 index e75a7a8986b..00000000000 Binary files a/docs/userguide/src/zh_CN/form/images/api.services.png and /dev/null differ diff --git a/docs/userguide/src/zh_CN/form/index-common.adoc b/docs/userguide/src/zh_CN/form/index-common.adoc deleted file mode 100755 index 5117d77c3e4..00000000000 --- a/docs/userguide/src/zh_CN/form/index-common.adoc +++ /dev/null @@ -1,22 +0,0 @@ -== Introduction - -include::../base/header-Introduction.adoc[] - -include::ch02-Configuration.adoc[] - -include::ch03-API.adoc[] - -include::ch04-Spring.adoc[] - -include::ch05-Deployment.adoc[] - -include::ch06-Form-Introduction.adoc[] - - -[[restApiChapter]] - -== REST API - -include::../base/header-REST.adoc[] - -include::ch07-REST.adoc[] diff --git a/docs/userguide/src/zh_CN/form/index-html.adoc b/docs/userguide/src/zh_CN/form/index-html.adoc deleted file mode 100755 index f5a4f255708..00000000000 --- a/docs/userguide/src/zh_CN/form/index-html.adoc +++ /dev/null @@ -1,15 +0,0 @@ -= Flowable Form 用户手册 (v 6.5.0.event-SNAPSHOT) -:doctype: book -:docinfodir: ../base -:docinfo1: header -:icons: font -:numbered: -:source-highlighter: pygments -:pygments-css: class -:pygments-linenums-mode: table -:compat-mode: -:pdf-page-size: A4 -:nofooter: - - -include::index-common.adoc[] diff --git a/docs/userguide/src/zh_CN/form/index-pdf.adoc b/docs/userguide/src/zh_CN/form/index-pdf.adoc deleted file mode 100755 index fea40185368..00000000000 --- a/docs/userguide/src/zh_CN/form/index-pdf.adoc +++ /dev/null @@ -1,14 +0,0 @@ -= Flowable Form 用户手册 (v 6.5.0.event-SNAPSHOT) -:doctype: book -:toc: left -:toclevels: 4 -:icons: font -:numbered: -:source-highlighter: pygments -:pygments-css: class -:pygments-linenums-mode: table -:compat-mode: -:pdf-page-size: A4 -:nofooter: - -include::index-common.adoc[] diff --git a/docs/userguide/src/zh_CN/single/ch01-Introduction.adoc b/docs/userguide/src/zh_CN/single/ch01-Introduction.adoc deleted file mode 100755 index a49095d2e40..00000000000 --- a/docs/userguide/src/zh_CN/single/ch01-Introduction.adoc +++ /dev/null @@ -1,22 +0,0 @@ -== 说明 - -include::../bpmn/ch02-GettingStarted.adoc[tags=getting.started.flowable] - -include::../base/header-Introduction.adoc[] - - -=== 架构 - -*TBD* - -=== 支持平台 - -*TBD* - -=== 历史 - -*TBD* - -=== 新特性 - -*TBD* \ No newline at end of file diff --git a/docs/userguide/src/zh_CN/single/ch01b-Concepts.adoc b/docs/userguide/src/zh_CN/single/ch01b-Concepts.adoc deleted file mode 100755 index 54012a2cdf9..00000000000 --- a/docs/userguide/src/zh_CN/single/ch01b-Concepts.adoc +++ /dev/null @@ -1,11 +0,0 @@ -== 概念 - -include::../bpmn/ch07a-BPMN-Introduction.adoc[leveloffset=+1,tags=bpmn20.introduction] - -include::../bpmn/ch07b-BPMN-Constructs.adoc[leveloffset=+1] - -include::../cmmn/ch06-cmmn.adoc[leveloffset=+1] - -include::../dmn/ch06-DMN-Introduction.adoc[leveloffset=+1] - -include::../form/ch06-Form-Introduction.adoc[leveloffset=+1] diff --git a/docs/userguide/src/zh_CN/single/ch02-Engine.adoc b/docs/userguide/src/zh_CN/single/ch02-Engine.adoc deleted file mode 100755 index 1440de45cc7..00000000000 --- a/docs/userguide/src/zh_CN/single/ch02-Engine.adoc +++ /dev/null @@ -1,87 +0,0 @@ -== Engine - -=== Introduction - -*TBD* - -=== Installation - -*TBD* - -=== Flowable Common ??? - -==== Introduction - -*TBD* - -include::../bpmn/ch02-GettingStarted.adoc[leveloffset=+1,tags=getting.started.command.line] - -//include::../bpmn/ch04-API.adoc[leveloffset=+2] - -include::../bpmn/ch09-JPA.adoc[leveloffset=+2] - -include::../bpmn/ch10-History.adoc[leveloffset=+2] - - -=== BPMN - -==== Introduction - -*TBD* - -include::../bpmn/ch07a-BPMN-Introduction.adoc[leveloffset=+2,tags=bpmn20.10minutetutorial] - -include::../bpmn/ch03-Configuration.adoc[leveloffset=+2] - -include::../bpmn/ch04-API.adoc[leveloffset=+2] - -include::../bpmn/ch05-Spring.adoc[leveloffset=+2] - -include::../bpmn/ch06-Deployment.adoc[leveloffset=+2] - - -=== CMMN - -include::../cmmn/ch02-Configuration.adoc[leveloffset=+2] - -include::../cmmn/ch03-API.adoc[leveloffset=+2] - -include::../cmmn/ch04-Spring.adoc[leveloffset=+2] - -include::../cmmn/ch05-Deployment.adoc[leveloffset=+2] - - -=== DMN - -include::../dmn/ch02-Configuration.adoc[leveloffset=+2] - -include::../dmn/ch03-API.adoc[leveloffset=+2] - -include::../dmn/ch04-Spring.adoc[leveloffset=+2] - -include::../dmn/ch05-Deployment.adoc[leveloffset=+2] - - -=== 表单 - -include::../form/ch02-Configuration.adoc[leveloffset=+2] - -include::../form/ch03-API.adoc[leveloffset=+2] - -include::../form/ch04-Spring.adoc[leveloffset=+2] - -include::../form/ch05-Deployment.adoc[leveloffset=+2] - -=== 整合 - -include::../bpmn/ch16-Cdi.adoc[leveloffset=+2] - -include::../bpmn/ch16-Ldap.adoc[leveloffset=+2] - -// 建议 - -include::../bpmn/ch17-Advanced.adoc[leveloffset=+1] - -// TOOLING - -include::../bpmn/ch18-tooling.adoc[leveloffset=+1] diff --git a/docs/userguide/src/zh_CN/single/ch03-REST.adoc b/docs/userguide/src/zh_CN/single/ch03-REST.adoc deleted file mode 100755 index f7057275c53..00000000000 --- a/docs/userguide/src/zh_CN/single/ch03-REST.adoc +++ /dev/null @@ -1,17 +0,0 @@ -[[restApiChapter]] - -== REST API - -include::../bpmn/ch02-GettingStarted.adoc[tags=getting.started.rest] - -=== BPMN - -include::../bpmn/ch15-REST.adoc[leveloffset=+1] - -=== DMN - -include::../dmn/ch07-REST.adoc[leveloffset=+1] - -=== FORM - -include::../form/ch07-REST.adoc[leveloffset=+1] diff --git a/docs/userguide/src/zh_CN/single/ch04-Modeler.adoc b/docs/userguide/src/zh_CN/single/ch04-Modeler.adoc deleted file mode 100755 index f18ad308d90..00000000000 --- a/docs/userguide/src/zh_CN/single/ch04-Modeler.adoc +++ /dev/null @@ -1,5 +0,0 @@ -== 设计器 - -include::../bpmn/ch12-Designer.adoc[leveloffset=+1] - - diff --git a/docs/userguide/src/zh_CN/single/ch05-FlowableUI.adoc b/docs/userguide/src/zh_CN/single/ch05-FlowableUI.adoc deleted file mode 100755 index 3fbc72c20ea..00000000000 --- a/docs/userguide/src/zh_CN/single/ch05-FlowableUI.adoc +++ /dev/null @@ -1,3 +0,0 @@ -include::../bpmn/ch13-UI.adoc[] - - diff --git a/docs/userguide/src/zh_CN/single/generate-html.sh b/docs/userguide/src/zh_CN/single/generate-html.sh deleted file mode 100755 index 84475ff1b56..00000000000 --- a/docs/userguide/src/zh_CN/single/generate-html.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -asciidoctor -a stylesheet=../base/flowable.css -o output/index.html index-html.adoc - -echo "Retrieving Images" -rm -rf output/images -mkdir output/images - -## Copy Images -cp -r ../base/images output/ -cp -r ../bpmn/images output/ -cp -r ../cmmn/images output/ -cp -r ../dmn/images output/ -cp -r ../form/images output/ - diff --git a/docs/userguide/src/zh_CN/single/generate-pdf.sh b/docs/userguide/src/zh_CN/single/generate-pdf.sh deleted file mode 100755 index 918db9e1119..00000000000 --- a/docs/userguide/src/zh_CN/single/generate-pdf.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -rm -rf output/flowable-dmn-userguide.pdf -asciidoctor-pdf -o output/flowable-userguide.pdf index-pdf.adoc diff --git a/docs/userguide/src/zh_CN/single/index-common.adoc b/docs/userguide/src/zh_CN/single/index-common.adoc deleted file mode 100755 index 48f3b1569f0..00000000000 --- a/docs/userguide/src/zh_CN/single/index-common.adoc +++ /dev/null @@ -1,12 +0,0 @@ -include::ch01-Introduction.adoc[] - -include::ch01b-Concepts.adoc[] - -include::ch02-Engine.adoc[] - -include::ch03-REST.adoc[] - -include::ch04-Modeler.adoc[] - -include::ch05-FlowableUI.adoc[] - diff --git a/docs/userguide/src/zh_CN/single/index-html.adoc b/docs/userguide/src/zh_CN/single/index-html.adoc deleted file mode 100755 index bb74a5dff6e..00000000000 --- a/docs/userguide/src/zh_CN/single/index-html.adoc +++ /dev/null @@ -1,15 +0,0 @@ -= Flowable Unified DOCS (v 6.5.0.event-SNAPSHOT) -:doctype: book -:docinfodir: ../base -:docinfo1: header -:icons: font -:numbered: -:source-highlighter: pygments -:pygments-css: class -:pygments-linenums-mode: table -:compat-mode: -:pdf-page-size: A4 -:nofooter: - - -include::index-common.adoc[] diff --git a/docs/userguide/src/zh_CN/single/index-pdf.adoc b/docs/userguide/src/zh_CN/single/index-pdf.adoc deleted file mode 100755 index 35d327c0dfe..00000000000 --- a/docs/userguide/src/zh_CN/single/index-pdf.adoc +++ /dev/null @@ -1,15 +0,0 @@ -= Flowable DMN DOCS (v 6.5.0.event-SNAPSHOT) -:doctype: book -:toc: left -:toclevels: 4 -:icons: font -:numbered: -:source-highlighter: pygments -:pygments-css: class -:pygments-linenums-mode: table -:compat-mode: -:pdf-page-size: A4 -:nofooter: -ifndef::imagesdir[:imagesdir: output] - -include::index-common.adoc[] diff --git a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/cmmn/FlowableCmmnProperties.java b/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/cmmn/FlowableCmmnProperties.java index fd6b96a8d09..fa743ce0715 100644 --- a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/cmmn/FlowableCmmnProperties.java +++ b/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/cmmn/FlowableCmmnProperties.java @@ -56,8 +56,8 @@ public class FlowableCmmnProperties { private boolean enabled = true; /** - * Enables extra checks on the DMN xml that is parsed. See https://www.flowable.org/docs/userguide/index.html#advanced.safe.bpmn.xml - * Unfortunately, this feature is not available on some platforms (JDK 6, JBoss), hence you need to disable if your platform does not allow the use of + * Enables extra checks on the DMN xml that is parsed. + * Unfortunately, this feature is not available on some platforms, hence you need to disable if your platform does not allow the use of * StaxSource during XML parsing. */ private boolean enableSafeXml = true; diff --git a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/dmn/FlowableDmnProperties.java b/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/dmn/FlowableDmnProperties.java index 5132437cf65..6a5bfcb78ef 100644 --- a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/dmn/FlowableDmnProperties.java +++ b/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/dmn/FlowableDmnProperties.java @@ -60,8 +60,8 @@ public class FlowableDmnProperties { private boolean historyEnabled = true; /** - * Enables extra checks on the DMN xml that is parsed. See https://www.flowable.org/docs/userguide/index.html#advanced.safe.bpmn.xml - * Unfortunately, this feature is not available on some platforms (JDK 6, JBoss), hence you need to disable if your platform does not allow the use of + * Enables extra checks on the DMN xml that is parsed. + * Unfortunately, this feature is not available on some platforms, hence you need to disable if your platform does not allow the use of * StaxSource during XML parsing. */ private boolean enableSafeXml = true; diff --git a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/process/FlowableProcessProperties.java b/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/process/FlowableProcessProperties.java index 276530da277..e584a40cdd2 100644 --- a/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/process/FlowableProcessProperties.java +++ b/modules/flowable-spring-boot/flowable-spring-boot-starters/flowable-spring-boot-autoconfigure/src/main/java/org/flowable/spring/boot/process/FlowableProcessProperties.java @@ -42,8 +42,8 @@ public class FlowableProcessProperties { protected int definitionCacheLimit = -1; /** - * Enables extra checks on the BPMN xml that is parsed. See https://www.flowable.org/docs/userguide/index.html#advanced.safe.bpmn.xml - * Unfortunately, this feature is not available on some platforms (JDK 6, JBoss), hence you need to disable if your platform does not allow the use of + * Enables extra checks on the BPMN xml that is parsed. + * Unfortunately, this feature is not available on some platforms, hence you need to disable if your platform does not allow the use of * StaxSource during XML parsing. */ private boolean enableSafeXml = true;