├── .github
├── dependabot.yml
├── release.yml
└── workflows
│ ├── build-java.yml
│ ├── commit-message-check-format.yml
│ ├── release-create-R-release-branch.yml
│ ├── release-create-gh-release.yml
│ └── release.yml
├── .gitignore
├── LICENSE
├── NOTICE
├── R
└── bpmnLayoutGeneratoR
│ ├── .Rbuildignore
│ ├── .gitignore
│ ├── DESCRIPTION
│ ├── Makefile
│ ├── NAMESPACE
│ ├── R
│ ├── bpmnLayoutGeneratoR.R
│ └── init.R
│ ├── README.adoc
│ ├── bpmnLayoutGeneratoR.Rproj
│ └── img
│ └── readme_bpmn_display.png
├── README.md
├── docs
└── images
│ ├── release_01_find_commits_since_previous_release.png
│ └── release_02_list_commits_since_previous_release.png
└── java
├── .mvn
└── wrapper
│ └── maven-wrapper.properties
├── Makefile
├── README.md
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
├── main
├── java
│ └── io
│ │ └── process
│ │ └── analytics
│ │ └── tools
│ │ └── bpmn
│ │ └── generator
│ │ ├── App.java
│ │ ├── BPMNLayoutGenerator.java
│ │ ├── algo
│ │ ├── ShapeLayouter.java
│ │ └── ShapeSorter.java
│ │ ├── converter
│ │ ├── AlgoToDisplayModelConverter.java
│ │ ├── BpmnToAlgoModelConverter.java
│ │ ├── Configuration.java
│ │ └── waypoint
│ │ │ ├── BendConfiguration.java
│ │ │ ├── BendDirection.java
│ │ │ ├── Direction.java
│ │ │ ├── EdgeTerminalPoints.java
│ │ │ ├── GridSearcher.java
│ │ │ ├── Orientation.java
│ │ │ ├── WayPointDescriptor.java
│ │ │ ├── WayPointsComputer.java
│ │ │ ├── WayPointsConverter.java
│ │ │ └── WayPointsPositioner.java
│ │ ├── export
│ │ ├── ASCIIExporter.java
│ │ ├── BPMNExporter.java
│ │ └── SVGExporter.java
│ │ ├── input
│ │ └── CSVtoBPMN.java
│ │ ├── internal
│ │ ├── BPMNDiagramRichBuilder.java
│ │ ├── BpmnInOut.java
│ │ ├── BpmnNamespacePrefixMapper.java
│ │ ├── FileUtils.java
│ │ ├── IdUtils.java
│ │ ├── Semantic.java
│ │ ├── StringUtils.java
│ │ └── XmlParser.java
│ │ └── model
│ │ ├── Diagram.java
│ │ ├── Edge.java
│ │ ├── Grid.java
│ │ ├── Position.java
│ │ ├── Shape.java
│ │ ├── ShapeType.java
│ │ └── display
│ │ ├── DisplayDimension.java
│ │ ├── DisplayEdge.java
│ │ ├── DisplayFlowNode.java
│ │ ├── DisplayLabel.java
│ │ ├── DisplayModel.java
│ │ └── DisplayPoint.java
├── resources
│ └── log4j2.xml
└── xsd
│ ├── BPMN20.xsd
│ ├── BPMNDI.xsd
│ ├── DC.xsd
│ ├── DI.xsd
│ └── Semantic.xsd
└── test
├── java
└── io
│ └── process
│ └── analytics
│ └── tools
│ └── bpmn
│ └── generator
│ ├── AppFromBpmnTest.java
│ ├── AppFromCsvTest.java
│ ├── AppTest.java
│ ├── algo
│ ├── ShapeLayouterTest.java
│ └── ShapeSorterTest.java
│ ├── converter
│ ├── BpmnToAlgoModelConverterTest.java
│ └── waypoint
│ │ └── WayPointsPositionerTest.java
│ ├── export
│ └── SVGExporterTest.java
│ ├── input
│ └── CSVtoBPMNTest.java
│ ├── internal
│ ├── BPMNDiagramRichBuilderTest.java
│ ├── SemanticTest.java
│ └── XmlParserTest.java
│ └── model
│ └── GridTest.java
└── resources
├── bpmn
├── 01-startEvent.bpmn.xml
├── 02-startEvent_task_endEvent-without-collaboration.bpmn.xml
├── A.2.0.bpmn.xml
├── A.2.1.bpmn.xml
├── waypoints-avoid-edge-overlap-01-single_branch.bpmn.png
├── waypoints-avoid-edge-overlap-01-single_branch.bpmn.xml
├── waypoints-avoid-edge-overlap-02-2nd-branch-with-large-height.bpmn.png
├── waypoints-avoid-edge-overlap-02-2nd-branch-with-large-height.bpmn.xml
├── waypoints-avoid-edge-overlap-03-elements_in_front.bpmn.png
├── waypoints-avoid-edge-overlap-03-elements_in_front.bpmn.xml
├── waypoints-avoid-edge-overlap-04-multiple_empty_paths.bpmn.png
├── waypoints-avoid-edge-overlap-04-multiple_empty_paths.bpmn.xml
├── waypoints-positions-cycle_01_simple.bpmn.png
├── waypoints-positions-cycle_01_simple.bpmn.xml
├── waypoints-positions-cycle_02_gateways_in_cycle.bpmn.png
├── waypoints-positions-cycle_02_gateways_in_cycle.bpmn.xml
├── waypoints-positions-gateways.bpmn.xml
├── waypoints-positions-gateways.png
├── waypoints-positions-gateways_split_join.bpmn.xml
└── waypoints-positions-gateways_split_join.png
├── csv
├── PatientsProcess
│ ├── edge.csv
│ ├── edgeSimple.csv
│ ├── gateway_edge_simple.csv
│ ├── gateway_node_simple.csv
│ ├── gateways_edge.csv
│ ├── gateways_node.csv
│ ├── node.csv
│ └── nodeSimple.csv
├── VacationRequestBonita
│ ├── edges.csv
│ └── nodes.csv
└── VacationRequestBonita_v2
│ ├── edges.csv
│ └── nodes.csv
└── log4j2.xml
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # See https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates
2 | version: 2
3 | updates:
4 | - package-ecosystem: "github-actions"
5 | # Workflow files stored in the default location of `.github/workflows`
6 | directory: "/"
7 | schedule:
8 | interval: "weekly"
9 | day: "tuesday"
10 | open-pull-requests-limit: 2
11 | rebase-strategy: "disabled"
12 | commit-message:
13 | prefix: "chore(gha)"
14 | labels:
15 | - dependencies
16 | - github_actions
17 | - skip-changelog
18 |
--------------------------------------------------------------------------------
/.github/release.yml:
--------------------------------------------------------------------------------
1 | changelog:
2 | exclude:
3 | labels:
4 | - skip-changelog
5 | categories:
6 | - title: 🎉 New Features
7 | labels:
8 | - enhancement
9 | - title: 🐛 Bug Fixes
10 | labels:
11 | - bug
12 | - title: 📝 Documentation
13 | labels:
14 | - documentation
15 | - title: 📦 Dependency updates
16 | labels:
17 | - dependencies
18 | - title: ⚙️ Other Changes
19 | labels:
20 | - "*"
21 |
--------------------------------------------------------------------------------
/.github/workflows/build-java.yml:
--------------------------------------------------------------------------------
1 | name: Build Java
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | paths:
7 | - .github/workflows/build-java.yml
8 | - java/src/**/*
9 | - java/.mvn/**/*
10 | - java/pom.xml
11 | - java/mvnw
12 | pull_request:
13 | branches: [ master ]
14 | paths:
15 | - .github/workflows/build-java.yml
16 | - java/src/**/*
17 | - java/.mvn/**/*
18 | - java/pom.xml
19 | - java/mvnw
20 |
21 | jobs:
22 | build:
23 | runs-on: ubuntu-24.04
24 | strategy:
25 | # don't cancel running jobs even if one fails
26 | fail-fast: false
27 | matrix:
28 | java:
29 | - 17
30 | - 21
31 |
32 | steps:
33 | - uses: actions/checkout@v4
34 | - uses: actions/setup-java@v4
35 | with:
36 | java-version: ${{ matrix.java }}
37 | distribution: 'zulu'
38 | cache: maven
39 | - name: Build
40 | run: ./mvnw -V verify
41 | working-directory: java
42 |
--------------------------------------------------------------------------------
/.github/workflows/commit-message-check-format.yml:
--------------------------------------------------------------------------------
1 | name: Commit Message format check
2 |
3 | on:
4 | pull_request_target:
5 | # trigger when the PR title changes
6 | types: [opened, edited, reopened]
7 |
8 | jobs:
9 | pr-title:
10 | runs-on: ubuntu-24.04
11 | permissions:
12 | pull-requests: write # post comments when the PR title doesn't match the "Conventional Commits" rules
13 | steps:
14 | - name: Check Pull Request title
15 | uses: bonitasoft/actions/packages/pr-title-conventional-commits@v3
16 |
--------------------------------------------------------------------------------
/.github/workflows/release-create-R-release-branch.yml:
--------------------------------------------------------------------------------
1 | name: Release - create the R package release branch
2 |
3 | on:
4 | push:
5 | tags:
6 | - v*
7 |
8 | jobs:
9 | release:
10 | runs-on: ubuntu-24.04
11 | defaults:
12 | run:
13 | working-directory: ./R/bpmnLayoutGeneratoR
14 | steps:
15 | - name: Setup checkout
16 | uses: actions/checkout@v4
17 | with:
18 | # Use a PAT to ensure that
19 | # commits are authored with a specific user
20 | # workflow run are triggered after git push
21 | token: ${{ secrets.GH_RELEASE_TOKEN }}
22 | - name: Config git
23 | run: |
24 | git config --local user.email "${{ vars.PA_BOT_EMAIL }}"
25 | git config --local user.name "${{ vars.PA_BOT_NAME }}"
26 | git config pull.rebase true
27 |
28 | - name: Set env
29 | run: |
30 | echo "VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_ENV
31 |
32 | - uses: actions/setup-java@v4
33 | with:
34 | java-version: 17
35 | distribution: 'zulu'
36 | cache: 'maven'
37 |
38 | - name: Create release branch
39 | run: |
40 | git checkout -b bpmnLayoutGeneratoR-${{ env.VERSION }}
41 |
42 | - name: Make the R package
43 | run: |
44 | make install
45 |
46 | - name: Commit and push
47 | run: |
48 | release(R): bpmnLayoutGeneratoR-${{ env.VERSION }}
49 | git push --set-upstream origin release/v${{ env.VERSION }}
50 |
--------------------------------------------------------------------------------
/.github/workflows/release-create-gh-release.yml:
--------------------------------------------------------------------------------
1 | name: Release - create the GitHub release
2 |
3 | on:
4 | push:
5 | tags:
6 | - v*
7 |
8 | jobs:
9 | create_release:
10 | runs-on: ubuntu-24.04
11 | permissions:
12 | contents: write # create the GH release
13 | steps:
14 | - name: Set env
15 | run: |
16 | echo "VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_ENV
17 | - name: Create release
18 | uses: ncipollo/release-action@v1
19 | with:
20 | body: |
21 | **Adapt this one liner summary**
22 | ⚡ This new version improves ... ⚡
23 |
24 | _If appropriate, briefly explain the contents of the new version._
25 |
26 | ## Breaking changes
27 |
28 | **TODO: keep if relevant and follow the guidelines below**
29 |
30 | - explain why it is introduced
31 | - explain the impact (use case, usage, impact a lot of user or only few, ....)
32 | - add references to issue or pull request to help users to understand the breaking change
33 |
34 | ### Removal of deprecated API
35 |
36 | **TODO: keep if relevant and follow the guidelines below**
37 |
38 | - list API
39 | - add reference to the version and release notes where it was announced as "deprecated"
40 |
41 | ## Deprecated APIs
42 |
43 | **TODO: keep if relevant and follow the guidelines below**
44 |
45 | - list the APIs
46 | - explain why they are deprecated
47 | - provide the new API to use instead. If none exist, mention it
48 | - explain in which version it will be removed. We usually keep 3 minor versions prior removal.
49 | - ensure that an issue exists to track the removal (one by version is OK) and it is attached to a milestone related to the version
50 |
51 | ## Highlights
52 |
53 | **Add screenshots, animations or videos to make your description more user-friendly!**
54 |
55 | ℹ️ For more details, see #.
56 |
57 | ### Other changes.... adapt and create more paragraphs
58 | draft: true
59 | generateReleaseNotes: true
60 | name: ${{ env.VERSION }}
61 | token: ${{ secrets.GH_RELEASE_TOKEN }}
62 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | version:
7 | description: 'The version to release'
8 | required: true
9 |
10 | jobs:
11 | releaseVersion:
12 | runs-on: ubuntu-24.04
13 | env:
14 | MAVEN_ARGS: "-B -ntp"
15 | VERSION: ${{ github.event.inputs.version }}
16 | steps:
17 | - run: |
18 | echo "Version: ${{ env.VERSION }}"
19 |
20 | - name: Setup checkout
21 | uses: actions/checkout@v4
22 | with:
23 | # Use a PAT to ensure that
24 | # commits are authored with a specific user
25 | # workflow run are triggered after git push
26 | token: ${{ secrets.GH_RELEASE_TOKEN }}
27 | - name: Config git
28 | run: |
29 | git config --local user.email "${{ vars.PA_BOT_EMAIL }}"
30 | git config --local user.name "${{ vars.PA_BOT_NAME }}"
31 | git config pull.rebase true
32 | - name: Checkout default branch
33 | run: git checkout master && git pull --tags
34 |
35 | - uses: actions/setup-java@v4
36 | with:
37 | java-version: 17
38 | distribution: 'zulu'
39 | cache: 'maven'
40 | - name: Set release version of the java project
41 | run: |
42 | cd ${{ github.workspace }}/java && ./mvnw ${{env.MAVEN_ARGS}} versions:set -DnewVersion=${{ env.VERSION }} versions:commit
43 | cd ${{ github.workspace }}
44 | git commit -a -m "chore(release): ${{ env.VERSION }}"
45 |
46 | - name: Create the release tag
47 | run: |
48 | git tag -a v${{ env.VERSION }} -m "chore(release): ${{ env.VERSION }}"
49 | - name: Set development version of the java project
50 | run: |
51 | cd ${{ github.workspace }}/java && ./mvnw ${{env.MAVEN_ARGS}} versions:set -DnextSnapshot=true versions:commit
52 | cd ${{ github.workspace }}
53 | git commit -a -m "chore(release): prepare next development version"
54 |
55 | - name: Push commits and tags
56 | run: |
57 | git push
58 | git push --tags
59 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build
2 | target/
3 | out/
4 |
5 | # IDE
6 | .idea/
7 | *.iml
8 |
--------------------------------------------------------------------------------
/NOTICE:
--------------------------------------------------------------------------------
1 | Copyright 2020 Bonitasoft S.A.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
15 |
--------------------------------------------------------------------------------
/R/bpmnLayoutGeneratoR/.Rbuildignore:
--------------------------------------------------------------------------------
1 | ^.*\.Rproj$
2 | ^\.Rproj\.user$
3 |
--------------------------------------------------------------------------------
/R/bpmnLayoutGeneratoR/.gitignore:
--------------------------------------------------------------------------------
1 | .Rproj.user
2 | .Rhistory
3 |
--------------------------------------------------------------------------------
/R/bpmnLayoutGeneratoR/DESCRIPTION:
--------------------------------------------------------------------------------
1 | Package: bpmnLayoutGeneratoR
2 | Title: What the Package Does (One Line, Title Case)
3 | Version: 0.0.0.9000
4 | Authors@R:
5 | person(given = "First",
6 | family = "Last",
7 | role = c("aut", "cre"),
8 | email = "first.last@example.com",
9 | comment = c(ORCID = "YOUR-ORCID-ID"))
10 | Description: What the package does (one paragraph).
11 | Imports: rJava (>= 1.0.4)
12 | SystemRequirements: Java (>= 8)
13 | License: `use_mit_license()`, `use_gpl3_license()` or friends to pick a
14 | license
15 | Encoding: UTF-8
16 | LazyData: true
17 | Roxygen: list(markdown = TRUE)
18 | RoxygenNote: 7.1.1
19 |
--------------------------------------------------------------------------------
/R/bpmnLayoutGeneratoR/Makefile:
--------------------------------------------------------------------------------
1 | PACKAGE_NAME=rJavaPackageExample
2 | # Path to subproject. If there are more subprojects, more variables like this
3 | # have to be added.
4 | # We require each subproject to contain a Makefile with `build` and `clean`
5 | # targets defined: `build` builds subprojects' artefacts, and `clean` removes
6 | # files derived from source code. We also require building to include running
7 | # the tests.
8 | JAVA_PROJECT_PATH=../../java
9 |
10 | # Directory where build package should be placed.
11 | BUILD_TARGET=target
12 | # Place where the produced Jar files should go.
13 | JAVA_BUILD_TARGET=inst/java
14 |
15 | all: build
16 |
17 | build: $(BUILD_TARGET) tests docs
18 |
19 | # Create portable bundle package ready to be installed.
20 | $(BUILD_TARGET): build-subprojects
21 | rm -rf $(JAVA_BUILD_TARGET)
22 | mkdir -p $(JAVA_BUILD_TARGET)
23 | cp $(JAVA_PROJECT_PATH)/target/*jar-with-dependencies.jar $(JAVA_BUILD_TARGET)
24 | mkdir -p $(BUILD_TARGET)
25 | Rscript -e "devtools::build(path = \"$(BUILD_TARGET)\")"
26 |
27 | # Build subprojects. We assume that testing is a part of their building process.
28 | build-subprojects:
29 | $(MAKE) -C $(JAVA_PROJECT_PATH) build
30 |
31 | # Run all tests. Tests in subprojects are not run explicitly because we assume
32 | # that building them requires them to pass tests anyway.
33 | test: $(BUILD_TARGET)
34 | # Rscript run_all_tests.R
35 |
36 | # Generate documentation.
37 | docs:
38 | Rscript -e "devtools::document()"
39 |
40 | # Check the code and package structure for common problems; run tests.
41 | # The number of ERRORs and WARNINGs should be zero. Ideally, the number of
42 | # NOTE's also should be zero. Currently there's one NOTE that says that the
43 | # paths to some of the files are too long (see README).
44 | check: build
45 | Rscript -e "devtools::check()"
46 |
47 | # Install the package in the system.
48 | install: test docs
49 | R CMD INSTALL .
50 |
51 | # Uninstall the package.
52 | uninstall:
53 | R CMD REMOVE $(PACKAGE_NAME)
54 |
55 | clean: clean-subprojects
56 | rm -rf man NAMESPACE *.tar.gz
57 | rm -rf $(JAVA_BUILD_TARGET)
58 | rm -rf $(BUILD_TARGET)
59 |
60 | clean-subprojects:
61 | $(MAKE) -C $(JAVA_PROJECT_PATH) clean
62 |
--------------------------------------------------------------------------------
/R/bpmnLayoutGeneratoR/NAMESPACE:
--------------------------------------------------------------------------------
1 | # Generated by roxygen2: do not edit by hand
2 |
3 | export(generateBpmnLayout)
4 |
--------------------------------------------------------------------------------
/R/bpmnLayoutGeneratoR/R/bpmnLayoutGeneratoR.R:
--------------------------------------------------------------------------------
1 | #' @export
2 | generateBpmnLayout <- function(flow_node, sequence_flow, outputType = "BPMN") {
3 | bpmnLayoutJava <- rJava::.jnew("io/process/analytics/tools/bpmn/generator/BPMNLayoutGenerator")
4 | type <- rJava::J(class = "io/process/analytics.tools/bpmn/generator/BPMNLayoutGenerator$ExportType", "valueOf", outputType)
5 |
6 | flow_node_as_csv <- paste(to_csv(flow_node), collapse = "\n")
7 | sequence_flow_as_csv <- paste(to_csv(sequence_flow), collapse = "\n")
8 |
9 | tryCatch( diagramAsString <- bpmnLayoutJava$generateLayoutFromCSV(flow_node_as_csv, sequence_flow_as_csv, type), Exception = function(e){
10 | e$printStackTrace()
11 | # raise the error
12 | stop("BPMN Layout generation fails. See Java stack trace.")
13 | } )
14 | return(diagramAsString)
15 | }
16 |
17 | to_csv <- function(x) {
18 | connection <- textConnection("fn_as_csv", "w", local = TRUE)
19 | utils::write.csv(x, connection)
20 | return(fn_as_csv)
21 | }
22 |
--------------------------------------------------------------------------------
/R/bpmnLayoutGeneratoR/R/init.R:
--------------------------------------------------------------------------------
1 | .onLoad <- function(libname, pkgname) {
2 | rJava::.jinit()
3 | rJava::.jpackage(pkgname, lib.loc = libname)
4 | rJava::.jaddClassPath(paste(libname, "/", pkgname, "/", "java"))
5 | writeLines("Using classpath")
6 | writeLines(rJava::.jclassPath())
7 | }
--------------------------------------------------------------------------------
/R/bpmnLayoutGeneratoR/README.adoc:
--------------------------------------------------------------------------------
1 | = bpmnLayoutGeneratoR
2 |
3 | This library wraps the bpmn-layout-generator java library
4 |
5 |
6 | == Prerequisites
7 |
8 | `bpmnLayoutGeneratoR` depends on http://rforge.net/rJava/:[rJava].
9 |
10 | You must install a JDK to make `rJava` work. For the JDK installation, you can use for instance
11 |
12 | * your OS package installer
13 | * Adoptium: https://adoptium.net/installation/
14 |
15 | Once the JDK is installed, don't forget to run `R CMD javareconf`. See https://cran.r-project.org/doc/manuals/R-admin.html#Java-support
16 |
17 | For more details, please refer to the http://rforge.net/rJava/:[rJava documentation] and the https://github.com/s-u/rJava/blob/master/README.md[rJava GitHub README].
18 |
19 | == Usage
20 |
21 | Install the package. `bpmnLayoutGeneratoR-x.y.z` is the version you want to install, see the available branches on GitHub
22 |
23 | [source,R]
24 | ----
25 | # install the package
26 | devtools::install_github("process-analytics/bpmn-layout-generators", ref="bpmnLayoutGeneratoR-x.y.z", subdir="R/bpmnLayoutGeneratoR")
27 | ----
28 |
29 | Then load data and generate the layout
30 |
31 | [source,R]
32 | ----
33 | # example source sequence_flow and flow_node
34 | flow_node <- data.frame(id=c(1,2),node=c("task1","task2"),type=c("task","task"))
35 | sequence_flow <- data.frame(id=1,from_id=1,to_id=2)
36 |
37 | # Call the library and generate the diagram using "ASCII", "BPMN" or "SVG". Defaults to "BPMN".
38 | diagram <- bpmnLayoutGeneratoR::generateBpmnLayout(flow_node, sequence_flow, "BPMN")
39 | ----
40 |
41 | If you want to display the BPMN diagram, you can install the https://github.com/process-analytics/bpmn-visualization-R[bpmnVisualization] package and then run
42 | [source,R]
43 | ----
44 | bpmnVisualization::display(diagram)
45 | ----
46 |
47 | The preview displays something like
48 |
49 | image::img/readme_bpmn_display.png[BPMN display in R preview]
50 |
51 | [#release]
52 | == Build and release new version
53 |
54 | [NOTE]
55 | ====
56 | Generally, the R release follow the Java release and is fully automated, so there is nothing to do.
57 | For more details, see the xref:../../README.md[overall release process].
58 |
59 | In this case, the branch mentioned here must be created from the related tag.
60 |
61 | Otherwise, it has to be created from the `master` branch.
62 | ====
63 |
64 | The following is for a manual release:
65 |
66 | * create a branch named `bpmnLayoutGeneratoR-x.y.z` (replace with version)
67 | * execute `make install` in the directory `R/bpmnLayoutGeneratoR`
68 | * commit and push everything with title `release: bpmnLayoutGeneratoR-x.y.z`
69 |
70 |
--------------------------------------------------------------------------------
/R/bpmnLayoutGeneratoR/bpmnLayoutGeneratoR.Rproj:
--------------------------------------------------------------------------------
1 | Version: 1.0
2 |
3 | RestoreWorkspace: Default
4 | SaveWorkspace: Default
5 | AlwaysSaveHistory: Default
6 |
7 | EnableCodeIndexing: Yes
8 | UseSpacesForTab: Yes
9 | NumSpacesForTab: 2
10 | Encoding: UTF-8
11 |
12 | RnwWeave: Sweave
13 | LaTeX: pdfLaTeX
14 |
15 | BuildType: Package
16 | PackageUseDevtools: Yes
17 | PackageInstallArgs: --no-multiarch --with-keep.source
18 |
--------------------------------------------------------------------------------
/R/bpmnLayoutGeneratoR/img/readme_bpmn_display.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/process-analytics/bpmn-layout-generators/6bea69c8bdd1936eca949eb2ad8f40dc2985d831/R/bpmnLayoutGeneratoR/img/readme_bpmn_display.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | BPMN Layout Generators
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | **:warning: THIS IS AN EXPERIMENTAL PROJECT :warning:**
26 |
27 | Tools for generating the graphical layout of the BPMN process (BPMNDI Graphical Model) in BPMN files.
28 | They can be used with diagrams containing only the BPMN Semantic part or to replace the existing BPMNDI part.
29 |
30 |
31 |
32 | ## Implementations
33 |
34 | > [!NOTE]
35 | > The implementations are based or partially based on https://www.researchgate.net/publication/221542866_A_Simple_Algorithm_for_Automatic_Layout_of_BPMN_Processes
36 |
37 | Available implementations:
38 | - [java](java/README.md)
39 | - [R](R/bpmnLayoutGeneratoR/README.adoc) This is only a wrapper of the java library
40 |
41 |
42 | ## Existing alternatives
43 |
44 | Java
45 | - https://github.com/camunda-consulting/code/tree/382f1521a4e9cd6bb92c2f9eacbe64a0e3835242/snippets/bpmndi-generator (latest available commit on 2020-04-08)
46 | - https://github.com/camunda-consulting/migrate-to-camunda-tools/: tools to migrate from several vendors to Camunda, adaptation of the `bpmndi-generator`
47 | - Camunda `fluent builder API`: https://docs.camunda.org/manual/7.9/user-guide/model-api/bpmn-model-api/fluent-builder-api/#generation-of-diagram-interchange
48 |
49 | Javascript
50 | - https://github.com/bpmn-io/bpmn-auto-layout/
51 |
52 |
53 | ## 🚀 Release how-to
54 |
55 | > [!IMPORTANT]
56 | > Follow the paragraphs in the order in which they are documented.
57 |
58 | ### Preparation
59 |
60 | #### Decide on the value of the new version to be released
61 |
62 | > [!NOTE]
63 | > The versioning follows **semver** (be aware of the rules for 0.x.y versions).
64 |
65 | Go to the page of the last [release](https://github.com/process-analytics/bpmn-layout-generators/releases/latest) to know what the latest version was.
66 |
67 | Check for changes since the release of the last version:
68 |
69 | 
70 |
71 | Check the commit list to determine the type of version to release (major, minor or patch) based on changes and the value of the previous version (follow semver rules):
72 |
73 | 
74 |
75 | The version you've just determined should follow the form `x.y.z`, so keep this in mind for future tasks.
76 |
77 | #### Prepare the release notes
78 |
79 | The GitHub release will include an auto-generated release notes which is based on the labels of the merged Pull Requests.
80 |
81 | Ensure that all merged PR included in the release are labelled. You can find the [unlabeled PR](https://github.com/process-analytics/bpmn-layout-generators/pulls?q=is%3Apr+sort%3Aupdated-desc+no%3Alabel+is%3Amerged) to easily labeled them.
82 |
83 |
84 | ### Perform the release
85 |
86 | When all updates have been completed, you are ready to publish a new release.
87 |
88 | Go to the [release workflow](https://github.com/process-analytics/bpmn-layout-generators/actions/workflows/release.yml) in GitHub Actions and run it by choosing the version to release.
89 |
90 | This workflow:
91 | - Creates a Git tag
92 | - Triggers the creation of the release branch of the R package
93 | - Triggers the creation of a draft GitHub release
94 |
95 | ### Publish the release notes
96 |
97 | The release workflow has initiated a new draft GitHub release, which needs to be updated and published :
98 | - For more details about GitHub release, follow the [GitHub help](https://help.github.com/en/github/administering-a-repository/managing-releases-in-a-repository#creating-a-release):
99 | - The release notes has been [automatically generated](https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes). Review and adjust it if necessary.
100 | - Publish the GitHub release
101 |
102 |
103 | ## License
104 |
105 | `bpmn-layout-generators` is released under the [Apache 2.0](LICENSE) license. \
106 | Copyright © 2020-present, Bonitasoft S.A.
107 |
--------------------------------------------------------------------------------
/docs/images/release_01_find_commits_since_previous_release.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/process-analytics/bpmn-layout-generators/6bea69c8bdd1936eca949eb2ad8f40dc2985d831/docs/images/release_01_find_commits_since_previous_release.png
--------------------------------------------------------------------------------
/docs/images/release_02_list_commits_since_previous_release.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/process-analytics/bpmn-layout-generators/6bea69c8bdd1936eca949eb2ad8f40dc2985d831/docs/images/release_02_list_commits_since_previous_release.png
--------------------------------------------------------------------------------
/java/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | # Licensed to the Apache Software Foundation (ASF) under one
2 | # or more contributor license agreements. See the NOTICE file
3 | # distributed with this work for additional information
4 | # regarding copyright ownership. The ASF licenses this file
5 | # to you under the Apache License, Version 2.0 (the
6 | # "License"); you may not use this file except in compliance
7 | # with the License. You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing,
12 | # software distributed under the License is distributed on an
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | # KIND, either express or implied. See the License for the
15 | # specific language governing permissions and limitations
16 | # under the License.
17 | wrapperVersion=3.3.2
18 | distributionType=only-script
19 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
20 |
--------------------------------------------------------------------------------
/java/Makefile:
--------------------------------------------------------------------------------
1 | all: build
2 |
3 | build: target/*.jar
4 |
5 | target/*.jar: pom.xml $(shell find src -name '*')
6 | ./mvnw package
7 |
8 | test:
9 | ./mvnw test
10 |
11 | clean:
12 | rm -rf target
13 |
--------------------------------------------------------------------------------
/java/README.md:
--------------------------------------------------------------------------------
1 | # BPMN Layout Generator Java Implementation
2 |
3 | ## Requirements
4 |
5 | To build and run, use:
6 | > JDK 17 or JDK 21
7 |
8 | > [!WARNING]
9 | > The build produces bytecode for JDK 17 or newer, so you cannot run the provided jar with older JDK versions.
10 |
11 |
12 | ## Get the bpmn-layout-generator jar
13 |
14 | Choose one of the following options:
15 |
16 | ### Download
17 |
18 | The jar is available in the release branches of the [R package](../R/bpmnLayoutGeneratoR/README.adoc).
19 |
20 | For example, for version `0.1.4`, you can download the jar from https://github.com/process-analytics/bpmn-layout-generators/tree/bpmnLayoutGeneratoR-0.1.4/R/bpmnLayoutGeneratoR/inst/java.
21 |
22 |
23 | ### Build
24 |
25 | > [!NOTE]
26 | > Building the jar let you use the latest version of the code.
27 |
28 | The project bundles a Maven Wrapper, so just run
29 | ``` bash
30 | ./mvnw package
31 | ```
32 |
33 | ## Usage
34 |
35 | **Note**: for more options, run with the `--help` option
36 |
37 | To generate the layout of an existing BPMN file and save the result as a BPMN file, run
38 | ```
39 | java -jar target/bpmn-layout-generator-*-jar-with-dependencies.jar --output=
40 | ```
41 | If you want to have the resulting layout in an SVG file, pass `--output-type=SVG`
42 | Notice that `ASCII` and `SVG` output types have been developed to get feedback when running tests i.e. to get a quick preview of the
43 | algorithm result. They are not fully implemented and won't probably never be (if you have some interest on that
44 | topic, feel free to provide a Pull Request)
45 |
46 |
47 | To generate BPMN semantic and diagram layout from discovery CSV files, run
48 | ```
49 | java -jar target/bpmn-layout-generator-*-jar-with-dependencies.jar \
50 | --input-type=CSV \
51 | --output= \
52 | csv/PatientsProcess/nodeSimple.csv csv/PatientsProcess/edgeSimple.cs
53 | ```
54 |
55 |
56 | ## Release
57 |
58 | The release process is fully automated. See the [release process](../README.md) for more details.
59 |
--------------------------------------------------------------------------------
/java/mvnw.cmd:
--------------------------------------------------------------------------------
1 | <# : batch portion
2 | @REM ----------------------------------------------------------------------------
3 | @REM Licensed to the Apache Software Foundation (ASF) under one
4 | @REM or more contributor license agreements. See the NOTICE file
5 | @REM distributed with this work for additional information
6 | @REM regarding copyright ownership. The ASF licenses this file
7 | @REM to you under the Apache License, Version 2.0 (the
8 | @REM "License"); you may not use this file except in compliance
9 | @REM with the License. You may obtain a copy of the License at
10 | @REM
11 | @REM http://www.apache.org/licenses/LICENSE-2.0
12 | @REM
13 | @REM Unless required by applicable law or agreed to in writing,
14 | @REM software distributed under the License is distributed on an
15 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | @REM KIND, either express or implied. See the License for the
17 | @REM specific language governing permissions and limitations
18 | @REM under the License.
19 | @REM ----------------------------------------------------------------------------
20 |
21 | @REM ----------------------------------------------------------------------------
22 | @REM Apache Maven Wrapper startup batch script, version 3.3.2
23 | @REM
24 | @REM Optional ENV vars
25 | @REM MVNW_REPOURL - repo url base for downloading maven distribution
26 | @REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
27 | @REM MVNW_VERBOSE - true: enable verbose log; others: silence the output
28 | @REM ----------------------------------------------------------------------------
29 |
30 | @IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0)
31 | @SET __MVNW_CMD__=
32 | @SET __MVNW_ERROR__=
33 | @SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
34 | @SET PSModulePath=
35 | @FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @(
36 | IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
37 | )
38 | @SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
39 | @SET __MVNW_PSMODULEP_SAVE=
40 | @SET __MVNW_ARG0_NAME__=
41 | @SET MVNW_USERNAME=
42 | @SET MVNW_PASSWORD=
43 | @IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*)
44 | @echo Cannot start maven from wrapper >&2 && exit /b 1
45 | @GOTO :EOF
46 | : end batch / begin powershell #>
47 |
48 | $ErrorActionPreference = "Stop"
49 | if ($env:MVNW_VERBOSE -eq "true") {
50 | $VerbosePreference = "Continue"
51 | }
52 |
53 | # calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
54 | $distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
55 | if (!$distributionUrl) {
56 | Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
57 | }
58 |
59 | switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {
60 | "maven-mvnd-*" {
61 | $USE_MVND = $true
62 | $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip"
63 | $MVN_CMD = "mvnd.cmd"
64 | break
65 | }
66 | default {
67 | $USE_MVND = $false
68 | $MVN_CMD = $script -replace '^mvnw','mvn'
69 | break
70 | }
71 | }
72 |
73 | # apply MVNW_REPOURL and calculate MAVEN_HOME
74 | # maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/
75 | if ($env:MVNW_REPOURL) {
76 | $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" }
77 | $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')"
78 | }
79 | $distributionUrlName = $distributionUrl -replace '^.*/',''
80 | $distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$',''
81 | $MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain"
82 | if ($env:MAVEN_USER_HOME) {
83 | $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain"
84 | }
85 | $MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join ''
86 | $MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME"
87 |
88 | if (Test-Path -Path "$MAVEN_HOME" -PathType Container) {
89 | Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME"
90 | Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
91 | exit $?
92 | }
93 |
94 | if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {
95 | Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl"
96 | }
97 |
98 | # prepare tmp dir
99 | $TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile
100 | $TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir"
101 | $TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null
102 | trap {
103 | if ($TMP_DOWNLOAD_DIR.Exists) {
104 | try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
105 | catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
106 | }
107 | }
108 |
109 | New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null
110 |
111 | # Download and Install Apache Maven
112 | Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
113 | Write-Verbose "Downloading from: $distributionUrl"
114 | Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
115 |
116 | $webclient = New-Object System.Net.WebClient
117 | if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
118 | $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)
119 | }
120 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
121 | $webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
122 |
123 | # If specified, validate the SHA-256 sum of the Maven distribution zip file
124 | $distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
125 | if ($distributionSha256Sum) {
126 | if ($USE_MVND) {
127 | Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
128 | }
129 | Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash
130 | if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {
131 | Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property."
132 | }
133 | }
134 |
135 | # unzip and move
136 | Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null
137 | Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null
138 | try {
139 | Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null
140 | } catch {
141 | if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) {
142 | Write-Error "fail to move MAVEN_HOME"
143 | }
144 | } finally {
145 | try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
146 | catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
147 | }
148 |
149 | Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
150 |
--------------------------------------------------------------------------------
/java/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | io.process.analytics.tools.bpmn
7 | bpmn-layout-generator
8 | 0.2.1-SNAPSHOT
9 |
10 |
11 | UTF-8
12 | 17
13 | 17
14 |
15 | 5.10.2
16 |
17 |
18 |
19 |
20 | org.projectlombok
21 | lombok
22 | 1.18.34
23 | provided
24 |
25 |
26 | jakarta.xml.bind
27 | jakarta.xml.bind-api
28 | 2.3.3
29 |
30 |
31 | com.sun.xml.bind
32 | jaxb-impl
33 | 2.3.3
34 |
35 |
36 |
37 |
38 | org.apache.logging.log4j
39 | log4j-core
40 | 2.23.1
41 |
42 |
43 | info.picocli
44 | picocli
45 | 4.7.5
46 |
47 |
48 |
49 | org.junit.jupiter
50 | junit-jupiter-api
51 | ${junit.version}
52 | test
53 |
54 |
55 | org.junit.jupiter
56 | junit-jupiter-engine
57 | ${junit.version}
58 | test
59 |
60 |
61 | org.junit.jupiter
62 | junit-jupiter-params
63 | ${junit.version}
64 | test
65 |
66 |
67 | org.assertj
68 | assertj-core
69 | 3.25.3
70 | test
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 | maven-assembly-plugin
80 | 3.7.1
81 |
82 |
83 | maven-clean-plugin
84 | 3.3.2
85 |
86 |
87 | maven-resources-plugin
88 | 3.3.1
89 |
90 |
91 | maven-compiler-plugin
92 | 3.13.0
93 |
94 |
95 | maven-surefire-plugin
96 | 3.3.0
97 |
98 |
99 | maven-jar-plugin
100 | 3.4.2
101 |
102 |
103 | maven-install-plugin
104 | 3.1.2
105 |
106 |
107 | maven-deploy-plugin
108 | 3.1.2
109 |
110 |
111 |
112 |
113 |
114 | org.apache.maven.plugins
115 | maven-assembly-plugin
116 |
117 |
118 | package
119 |
120 | single
121 |
122 |
123 |
124 |
125 | io.process.analytics.tools.bpmn.generator.App
126 |
127 |
128 |
129 | jar-with-dependencies
130 |
131 |
132 |
133 |
134 |
135 |
136 | org.codehaus.mojo
137 | jaxb2-maven-plugin
138 | 2.5.0
139 |
140 |
141 | xjc
142 |
143 | xjc
144 |
145 |
146 |
147 |
148 | io.process.analytics.tools.bpmn.generator.internal.generated.model
149 | en
150 |
151 |
152 |
153 |
154 | org.codehaus.mojo
155 | build-helper-maven-plugin
156 | 3.6.0
157 |
158 |
159 | add-source
160 | generate-sources
161 |
162 | add-source
163 |
164 |
165 |
166 | ${project.build.directory}/generate-sources/jaxb
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/App.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Bonitasoft S.A.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package io.process.analytics.tools.bpmn.generator;
16 |
17 | import static java.lang.String.format;
18 | import static java.util.Arrays.stream;
19 | import static java.util.stream.Collectors.joining;
20 |
21 | import java.io.File;
22 | import java.nio.file.Files;
23 | import java.nio.file.NoSuchFileException;
24 | import java.util.concurrent.Callable;
25 |
26 | import io.process.analytics.tools.bpmn.generator.BPMNLayoutGenerator.ExportType;
27 | import io.process.analytics.tools.bpmn.generator.internal.FileUtils;
28 | import lombok.extern.log4j.Log4j2;
29 | import picocli.CommandLine;
30 | import picocli.CommandLine.Command;
31 | import picocli.CommandLine.Option;
32 | import picocli.CommandLine.Parameters;
33 |
34 | @Log4j2
35 | @Command(name = "App", mixinStandardHelpOptions = true)
36 | public class App implements Callable {
37 |
38 |
39 | @Option(names = {"-t", "--input-type"},
40 | description = "BPMN or CSV.",
41 | paramLabel = "TYPE")
42 | String inputType = "BPMN";
43 | @Option(names = {"-u", "--output-type"},
44 | description = "BPMN, SVG or ASCII.",
45 | paramLabel = "TYPE")
46 | String outputType = "BPMN";
47 |
48 | @Option(names = {"-o", "--output"},
49 | description = "Output file.",
50 | paramLabel = "OUTPUT")
51 | private File outputFile;
52 | @Parameters(arity = "1..2", paramLabel = "INPUT", description = "Input file(s).")
53 | private File[] inputFiles;
54 |
55 | public static void main(String[] args) throws Exception {
56 | int exitCode = runApp(args);
57 | System.exit(exitCode);
58 | }
59 |
60 | static int runApp(String... args) {
61 | return new CommandLine(new App()).execute(args);
62 | }
63 |
64 |
65 | private App() {
66 | }
67 |
68 | @Override
69 | public Integer call() {
70 | try {
71 | BPMNLayoutGenerator bpmnLayoutGenerator = new BPMNLayoutGenerator();
72 | String output;
73 | switch (inputType) {
74 | case "BPMN":
75 | if (inputFiles.length != 1) {
76 | System.err.println("Expected only one input file to import from BPMN format, got: " + inputType.length());
77 | }
78 | output = bpmnLayoutGenerator.generateLayoutFromBPMNSemantic(FileUtils.fileContent(inputFiles[0]), exportType(outputType));
79 | break;
80 | case "CSV":
81 | if (inputFiles.length != 2) {
82 | System.err.println("Expected 2 input files to import from CSV format, got: " + inputType.length());
83 | }
84 | output = bpmnLayoutGenerator.generateLayoutFromCSV(FileUtils.fileContent(inputFiles[0]), FileUtils.fileContent(inputFiles[1]), exportType(outputType));
85 | break;
86 | default:
87 | System.err.println("Unexpected input type: " + inputType);
88 | return 2;
89 | }
90 | if (outputFile != null) {
91 | FileUtils.touch(outputFile);
92 | Files.write(outputFile.toPath(), output.getBytes());
93 | } else {
94 | System.out.println(output);
95 | }
96 | } catch (NoSuchFileException e) {
97 | System.err.println("File not found: " + e.getMessage());
98 | return 2;
99 | } catch (Exception e) {
100 | System.err.println("An error occurred: " + e.getMessage());
101 | return 1;
102 | }
103 | return 0;
104 | }
105 |
106 |
107 | private ExportType exportType(String arg) {
108 | try {
109 | return ExportType.valueOf(arg.toUpperCase());
110 | } catch (IllegalArgumentException e) {
111 | throw new IllegalArgumentException(
112 | format("Invalid export type: %s. Must be one of [%s]", arg,
113 | stream(ExportType.values())
114 | .map(Enum::toString)
115 | .map(String::toLowerCase)
116 | .collect(joining(", "))));
117 | }
118 | }
119 |
120 | }
121 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/BPMNLayoutGenerator.java:
--------------------------------------------------------------------------------
1 | package io.process.analytics.tools.bpmn.generator;
2 |
3 | import static io.process.analytics.tools.bpmn.generator.export.BPMNExporter.defaultBpmnExporter;
4 | import static io.process.analytics.tools.bpmn.generator.internal.BpmnInOut.defaultBpmnInOut;
5 |
6 | import io.process.analytics.tools.bpmn.generator.algo.ShapeLayouter;
7 | import io.process.analytics.tools.bpmn.generator.algo.ShapeSorter;
8 | import io.process.analytics.tools.bpmn.generator.converter.BpmnToAlgoModelConverter;
9 | import io.process.analytics.tools.bpmn.generator.export.ASCIIExporter;
10 | import io.process.analytics.tools.bpmn.generator.export.SVGExporter;
11 | import io.process.analytics.tools.bpmn.generator.input.CSVtoBPMN;
12 | import io.process.analytics.tools.bpmn.generator.internal.BpmnInOut;
13 | import io.process.analytics.tools.bpmn.generator.internal.generated.model.TDefinitions;
14 | import io.process.analytics.tools.bpmn.generator.model.Diagram;
15 | import io.process.analytics.tools.bpmn.generator.model.Grid;
16 | import lombok.Getter;
17 | import lombok.RequiredArgsConstructor;
18 | import lombok.extern.log4j.Log4j2;
19 |
20 | @Log4j2
21 | public class BPMNLayoutGenerator {
22 |
23 |
24 | public enum ExportType {
25 | ASCII,
26 | BPMN,
27 | SVG
28 | }
29 |
30 | protected final BpmnInOut bpmnInOut = defaultBpmnInOut();
31 |
32 |
33 | /*
34 | Public methods
35 | */
36 |
37 | public String generateLayoutFromBPMNSemantic(String bpmn, ExportType exportType) {
38 | TDefinitions tDefinitions = bpmnInOut.readFromBpmn(bpmn);
39 | LayoutSortedDiagram layout = layout(tDefinitions);
40 | return export(layout, exportType);
41 | }
42 |
43 | public String generateLayoutFromCSV(String nodes, String edges, ExportType exportType) {
44 | TDefinitions tDefinitions = new CSVtoBPMN().readFromCSV(nodes, edges);
45 | LayoutSortedDiagram layout = layout(tDefinitions);
46 | return export(layout, exportType);
47 | }
48 |
49 |
50 | /*
51 | BPMN --> Diagram
52 | */
53 |
54 | private LayoutSortedDiagram layout(TDefinitions definitions) {
55 | log.info("Converting BPMN into internal model");
56 | Diagram diagram = new BpmnToAlgoModelConverter().toAlgoModel(definitions);
57 | log.info("Conversion done");
58 |
59 | log.info("Sorting and generating Layout");
60 | Diagram sortedDiagram = new ShapeSorter().sort(diagram);
61 | Grid grid = new ShapeLayouter().layout(sortedDiagram);
62 | log.info("Sort and Layout done");
63 |
64 | return new LayoutSortedDiagram(definitions, grid, sortedDiagram);
65 | }
66 |
67 |
68 |
69 |
70 | /*
71 | Diagram --> Exported format
72 | */
73 |
74 | private String exportToAscii(LayoutSortedDiagram diagram) {
75 | log.info("Exporting to ASCII file");
76 | return new ASCIIExporter().export(diagram.getGrid());
77 | }
78 |
79 | protected String exportToBpmn(LayoutSortedDiagram diagram) {
80 | log.info("Exporting to BPMN");
81 | TDefinitions newDefinitions = defaultBpmnExporter().export(diagram.originalDefinitions, diagram.grid, diagram.diagram);
82 | return bpmnInOut.writeToBpmn(newDefinitions);
83 | }
84 |
85 | private String exportToSvg(LayoutSortedDiagram diagram) {
86 | log.info("Exporting to SVG");
87 | return new SVGExporter().export(diagram.getGrid(), diagram.getDiagram());
88 | }
89 |
90 |
91 | private String export(LayoutSortedDiagram layout, ExportType exportType) {
92 | return switch (exportType) {
93 | case ASCII -> exportToAscii(layout);
94 | case BPMN -> exportToBpmn(layout);
95 | case SVG -> exportToSvg(layout);
96 | default -> throw new IllegalStateException("Unexpected Export Type: " + exportType);
97 | };
98 | }
99 |
100 | @RequiredArgsConstructor
101 | @Getter
102 | // TODO switch to record
103 | public static class LayoutSortedDiagram {
104 |
105 | private final TDefinitions originalDefinitions;
106 | private final Grid grid;
107 | private final Diagram diagram;
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/algo/ShapeLayouter.java:
--------------------------------------------------------------------------------
1 | package io.process.analytics.tools.bpmn.generator.algo;
2 |
3 | import static io.process.analytics.tools.bpmn.generator.export.ASCIIExporter.toAscii;
4 | import static io.process.analytics.tools.bpmn.generator.model.Position.position;
5 |
6 | import java.util.List;
7 |
8 | import io.process.analytics.tools.bpmn.generator.model.Edge;
9 | import io.process.analytics.tools.bpmn.generator.model.Grid;
10 | import io.process.analytics.tools.bpmn.generator.model.Shape;
11 | import io.process.analytics.tools.bpmn.generator.model.Position;
12 | import io.process.analytics.tools.bpmn.generator.model.Diagram;
13 | import lombok.extern.log4j.Log4j2;
14 |
15 | @Log4j2
16 | public class ShapeLayouter {
17 |
18 |
19 | public Grid layout(Diagram diagram) {
20 | Grid grid = new Grid();
21 | for (Shape shape : diagram.getShapes()) {
22 | Position positionOfCurrentShape = positionShape(diagram, grid, shape);
23 | putOnGrid(grid, positionOfCurrentShape);
24 | // TODO check usage of supplier, intellij says it is deprecated
25 | log.debug("Adding {}:\n{}", shape::getName, () -> toAscii(grid));
26 | addRowsWhenShapeIsASplit(diagram, grid, shape, positionOfCurrentShape);
27 | }
28 | compactGrid(grid);
29 | log.debug("After compact grid \n{}", () -> toAscii(grid));
30 | return grid;
31 | }
32 |
33 | private void putOnGrid(Grid grid, Position positionOfCurrentShape) {
34 | if (grid.isFilled(positionOfCurrentShape)) {
35 | //never overlap an element
36 | grid.addRowAfter(positionOfCurrentShape.getY());
37 | grid.add(positionOfCurrentShape.toBuilder().y(positionOfCurrentShape.getY() + 1).build());
38 | } else {
39 | grid.add(positionOfCurrentShape);
40 | }
41 | }
42 |
43 | private void addRowsWhenShapeIsASplit(Diagram diagram, Grid grid, Shape shape, Position positionOfCurrentShape) {
44 | List outgoingEdges = diagram.getOutgoingEdges(shape.getId());
45 | if (outgoingEdges.size() > 1) {
46 | //add rows to place elements of this split
47 | int rowsToAddBeforeAndAfter = outgoingEdges.size() / 2;
48 | for (int i = 0; i < rowsToAddBeforeAndAfter; i++) {
49 | grid.addRowAfter(positionOfCurrentShape.getY());
50 | grid.addRowBefore(positionOfCurrentShape.getY());
51 | }
52 | }
53 | }
54 |
55 | private Position positionShape(Diagram diagram, Grid grid, Shape shape) {
56 | Position positionOfCurrentShape;
57 | List incomingEdges = diagram.getIncomingEdges(shape.getId());
58 | if (incomingEdges.isEmpty()) {
59 | //This is a start node, insert it in a new column
60 | positionOfCurrentShape = addStartShape(grid, shape);
61 | } else if (incomingEdges.size() == 1) {
62 | //find the previous node position
63 | String previousShapeID = incomingEdges.get(0).getFrom();
64 | List outgoingEdgesOfPreviousShape = diagram.getOutgoingEdges(previousShapeID);
65 | if (outgoingEdgesOfPreviousShape.size() == 1) {
66 | positionOfCurrentShape = addDirectlyNextTo(grid, shape, previousShapeID);
67 | } else {
68 | positionOfCurrentShape = addSplit(grid, shape, previousShapeID, outgoingEdgesOfPreviousShape);
69 | }
70 | } else {
71 | positionOfCurrentShape = addJoin(grid, shape, incomingEdges);
72 | }
73 | return positionOfCurrentShape;
74 | }
75 |
76 | private void compactGrid(Grid grid) {
77 | int i = 0;
78 | while (i < grid.getLastRowIndex()) {
79 | List currentRow = grid.getRow(i).stream().map(Position::getX).toList();
80 | List nextRow = grid.getRow(i + 1).stream().map(Position::getX).toList();
81 |
82 | boolean currentRowCanBeMovedBelow = true;
83 | for (Integer shapeIndexInCurrentRow : currentRow) {
84 | int index = shapeIndexInCurrentRow;
85 | //we can move the current row below if each element have all adjacent cells free in the row below
86 | if (nextRow.stream().anyMatch(s -> s == index || s == index + 1 || s == index - 1)) {
87 | currentRowCanBeMovedBelow = false;
88 | break;
89 | }
90 | }
91 |
92 | if (currentRowCanBeMovedBelow) {
93 | final int finalI = i + 1;
94 | for (Position position : grid.getRow(i)) {
95 | grid.remove(position);
96 | grid.add(position.toBuilder().y(finalI).build());
97 | }
98 | grid.removeEmptyRow(i);
99 | } else {
100 | i++;
101 | }
102 | }
103 | }
104 |
105 | private Position addStartShape(Grid grid, Shape shape) {
106 | return position(shape, 0, grid.getLastRowIndex() + 1);
107 | }
108 |
109 | private Position addSplit(Grid grid, Shape shape, String previousShapeID, List outgoingEdgesOfPreviousShape) {
110 | Position previousShapePosition = grid.getPosition(previousShapeID);
111 | int numberOfShapesInTheSplit = outgoingEdgesOfPreviousShape.size();
112 | int indexOfCurrentShape = outgoingEdgesOfPreviousShape.stream().map(Edge::getTo).toList().indexOf(shape.getId());
113 | //put element right to the split vertically distributed according to the index
114 | int relativeYPosition;
115 | if (numberOfShapesInTheSplit % 2 == 0 && indexOfCurrentShape >= numberOfShapesInTheSplit / 2) {
116 | //if there is an even number of element, there is no "middle" element so we must add 1 to the index of the elements after the "middle"
117 | relativeYPosition = indexOfCurrentShape + 1 - numberOfShapesInTheSplit / 2;
118 | } else {
119 | relativeYPosition = indexOfCurrentShape - numberOfShapesInTheSplit / 2;
120 | }
121 | return position(shape, previousShapePosition.getX() + 1, previousShapePosition.getY() + relativeYPosition);
122 | }
123 |
124 | private Position addJoin(Grid grid, Shape shape, List incomingEdges) {
125 | //first implementation: middle of elements it joins
126 | // later we should also try yo find the split to align it to that if possible
127 | List positions = incomingEdges.stream().map(Edge::getFrom).map(grid::getPosition).toList();
128 | int xMax = positions.stream().map(Position::getX).reduce(0, Math::max);
129 | int yMax = positions.stream().map(Position::getY).reduce(0, Math::max);
130 | int yMin = positions.stream().map(Position::getY).reduce(Integer.MAX_VALUE, Math::min);
131 |
132 | int xElement = xMax + 1;
133 | int yElement = (yMin + yMax) / 2;
134 | if ((yMin + yMax) % 2 != 0) {
135 | grid.addRowAfter(yElement);
136 | yElement++;
137 | }
138 | return position(shape, xElement, yElement);
139 | }
140 |
141 | private Position addDirectlyNextTo(Grid grid, Shape shapeToAdd, String rightTo) {
142 | Position previous = grid.getPosition(rightTo);
143 | return position(shapeToAdd, previous.getX() + 1, previous.getY());
144 | }
145 |
146 |
147 | }
148 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/converter/AlgoToDisplayModelConverter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Bonitasoft S.A.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.process.analytics.tools.bpmn.generator.converter;
17 |
18 | import static io.process.analytics.tools.bpmn.generator.converter.Configuration.CELL_HEIGHT;
19 | import static io.process.analytics.tools.bpmn.generator.converter.Configuration.CELL_WIDTH;
20 |
21 | import java.util.Collection;
22 | import java.util.stream.Collectors;
23 |
24 | import io.process.analytics.tools.bpmn.generator.converter.waypoint.WayPointsComputer;
25 | import io.process.analytics.tools.bpmn.generator.model.*;
26 | import io.process.analytics.tools.bpmn.generator.model.display.*;
27 |
28 | public class AlgoToDisplayModelConverter {
29 |
30 | public DisplayModel convert(Grid grid, Diagram diagram) {
31 | DisplayModel.DisplayModelBuilder model = DisplayModel.builder();
32 | // dimensions must be increased when generating alternate path to avoid edge overlapping on shapes
33 | // mainly impact on svg exporter. If the dimensions are not updated, the alternate paths are not fully displayed
34 | // as they are out of the viewport of the svg
35 | // increase to display edges with extra paths to avoid shape overlapping
36 | model.width(grid.width() * CELL_WIDTH).height((grid.height() + 1) * CELL_HEIGHT);
37 |
38 | Collection flowNodes = grid.getPositions().stream()
39 | .map(position -> toDisplayFlowNode(position, diagram))
40 | .collect(Collectors.toList());
41 | model.flowNodes(flowNodes);
42 |
43 | WayPointsComputer wayPointsComputer = new WayPointsComputer(grid, flowNodes);
44 | diagram.getEdges()
45 | .stream()
46 | .map(edge -> new DisplayEdge(edge.getId(), wayPointsComputer.compute(edge)))
47 | .forEach(model::edge);
48 |
49 | return model.build();
50 | }
51 |
52 | private DisplayFlowNode toDisplayFlowNode(Position position, Diagram diagram) {
53 | int xOffset = position.getX() * CELL_WIDTH;
54 | int yOffset = position.getY() * CELL_HEIGHT;
55 | int nodeWidth = x(60);
56 | int nodeHeight = y(60);
57 |
58 | // TODO manage when not found (should not occur)
59 | Shape shape = diagram.getShapes().stream()
60 | .filter(s -> s.getId().equals(position.getShape()))
61 | .findFirst().get();
62 | String name = shape.getName();
63 |
64 | // ensure to have a square shape (i.e. same width and height) for non activity elements
65 | ShapeType shapeType = shape.getType();
66 | if (shapeType == ShapeType.EVENT || shapeType == ShapeType.GATEWAY) {
67 | int nodeDimension = Math.min(nodeWidth, nodeHeight);
68 | if (shapeType == ShapeType.EVENT) {
69 | nodeDimension /= 2;
70 | }
71 | nodeWidth = nodeDimension;
72 | nodeHeight = nodeDimension;
73 | }
74 |
75 | int x = xOffset + (CELL_WIDTH - nodeWidth) / 2;
76 | int y = yOffset + (CELL_HEIGHT - nodeHeight) / 2;
77 | DisplayDimension flowNodeDimension = new DisplayDimension(x, y, nodeWidth, nodeHeight);
78 |
79 | // Labels positions better work with the SVG export
80 | // BPMN label positions are adjusted in BPMNDiagramRichBuilder
81 | int labelX = xOffset + x(50);
82 | int labelY = yOffset + y(50);
83 | if (shapeType == ShapeType.EVENT) { // put the label under the shape
84 | labelY = (int) (y + nodeHeight * 1.5);
85 | } else if (shapeType == ShapeType.GATEWAY) { // put the label on the top left of the shape
86 | labelX = (int) (x - nodeWidth * 0.5);
87 | labelY = (int) (y - nodeHeight * 0.5);
88 | }
89 |
90 | DisplayDimension labelDimension = new DisplayDimension(labelX, labelY, nodeWidth, nodeHeight);
91 | DisplayLabel label = new DisplayLabel(name, y(16), labelDimension);
92 |
93 | return DisplayFlowNode.builder().bpmnElementId(shape.getId())
94 | .dimension(flowNodeDimension)
95 | .label(label)
96 | .type(shapeType)
97 | .rx(y(10))
98 | .strokeWidth(y(5))
99 | .build();
100 | }
101 |
102 | private static int x(int percentage) {
103 | return CELL_WIDTH * percentage / 100;
104 | }
105 |
106 | private static int y(int percentage) {
107 | return CELL_HEIGHT * percentage / 100;
108 | }
109 |
110 | }
111 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/converter/BpmnToAlgoModelConverter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Bonitasoft S.A.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.process.analytics.tools.bpmn.generator.converter;
17 |
18 | import static io.process.analytics.tools.bpmn.generator.internal.Semantic.getId;
19 | import static io.process.analytics.tools.bpmn.generator.model.ShapeType.*;
20 |
21 | import java.util.List;
22 |
23 | import io.process.analytics.tools.bpmn.generator.internal.Semantic;
24 | import io.process.analytics.tools.bpmn.generator.internal.Semantic.BpmnElements;
25 | import io.process.analytics.tools.bpmn.generator.internal.generated.model.*;
26 | import io.process.analytics.tools.bpmn.generator.model.Edge;
27 | import io.process.analytics.tools.bpmn.generator.model.Diagram;
28 | import io.process.analytics.tools.bpmn.generator.model.Shape;
29 | import io.process.analytics.tools.bpmn.generator.model.ShapeType;
30 |
31 | public class BpmnToAlgoModelConverter {
32 |
33 | public Diagram toAlgoModel(TDefinitions definitions) {
34 | Semantic semantic = new Semantic(definitions);
35 | Diagram.DiagramBuilder diagram = Diagram.builder();
36 |
37 | List processes = semantic.getProcesses();
38 | for (TProcess process : processes) {
39 | BpmnElements bpmnElements = semantic.getBpmnElements(process);
40 |
41 | bpmnElements.getFlowNodes()
42 | .stream()
43 | .map(BpmnToAlgoModelConverter::toShape)
44 | .forEach(diagram::shape);
45 |
46 | bpmnElements.getSequenceFlows()
47 | .stream()
48 | .map(seqFlow -> Edge.edge(seqFlow.getId(), getId(seqFlow.getSourceRef()), getId(seqFlow.getTargetRef())))
49 | .forEach(diagram::edge);
50 | }
51 |
52 | return diagram.build();
53 | }
54 |
55 | // visible for testing
56 | static Shape toShape(TFlowElement flowNode) {
57 | ShapeType shapeType = ACTIVITY;
58 | boolean isSplitGateway = false;
59 | if (flowNode instanceof TGateway) {
60 | shapeType = GATEWAY;
61 | isSplitGateway = ((TGateway) flowNode).getOutgoing().size() > 1;
62 | } else if (flowNode instanceof TEvent) {
63 | shapeType = EVENT;
64 | }
65 | return new Shape(flowNode.getId(), flowNode.getName(), shapeType, isSplitGateway);
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/converter/Configuration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Bonitasoft S.A.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | package io.process.analytics.tools.bpmn.generator.converter;
14 |
15 | public class Configuration {
16 | // TODO this should be configurable for by the client code
17 | public static final int CELL_WIDTH = 200;
18 | public static final int CELL_HEIGHT = 100;
19 |
20 | public static final int EDGE_OUTGOING_FIRST_HORIZONTAL_SEGMENT_LENGTH = 20;
21 | }
22 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/converter/waypoint/BendConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Bonitasoft S.A.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.process.analytics.tools.bpmn.generator.converter.waypoint;
17 |
18 | import lombok.Builder;
19 | import lombok.ToString;
20 |
21 | @Builder
22 | @ToString
23 | public class BendConfiguration {
24 | public final BendDirection direction;
25 | public final int offset;
26 | }
27 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/converter/waypoint/BendDirection.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Bonitasoft S.A.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.process.analytics.tools.bpmn.generator.converter.waypoint;
17 |
18 | public enum BendDirection {
19 |
20 | BOTTOM, TOP;
21 |
22 | public int numericFactor() {
23 | return this == BOTTOM ? 1 : -1;
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/converter/waypoint/Direction.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Bonitasoft S.A.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.process.analytics.tools.bpmn.generator.converter.waypoint;
17 |
18 | public enum Direction {
19 | LeftToRight, RightToLeft, // generally for horizontal orientation
20 | BottomToTop, TopToBottom, // generally for vertical orientation
21 | BottomLeftToTopRight, TopRightToBottomLeft, BottomRightToTopLeft, TopLeftToBottomRight
22 | }
23 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/converter/waypoint/EdgeTerminalPoints.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Bonitasoft S.A.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | package io.process.analytics.tools.bpmn.generator.converter.waypoint;
14 |
15 | import io.process.analytics.tools.bpmn.generator.model.display.DisplayDimension;
16 | import io.process.analytics.tools.bpmn.generator.model.display.DisplayPoint;
17 |
18 | /**
19 | * Compute coordinates of the terminal points (source or target) of an Edge.
20 | */
21 | public class EdgeTerminalPoints {
22 |
23 | public DisplayPoint rightMiddle(DisplayDimension dimension) {
24 | return new DisplayPoint(dimension.x + dimension.width, dimension.y + dimension.height / 2);
25 | }
26 |
27 | public DisplayPoint leftMiddle(DisplayDimension dimension) {
28 | return new DisplayPoint(dimension.x, dimension.y + dimension.height / 2);
29 | }
30 |
31 | public DisplayPoint centerBottom(DisplayDimension dimension) {
32 | return new DisplayPoint(dimension.x + dimension.width / 2, dimension.y + dimension.height);
33 | }
34 |
35 | public DisplayPoint centerTop(DisplayDimension dimension) {
36 | return new DisplayPoint(dimension.x + dimension.width / 2, dimension.y);
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/converter/waypoint/GridSearcher.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Bonitasoft S.A.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | package io.process.analytics.tools.bpmn.generator.converter.waypoint;
14 |
15 | import io.process.analytics.tools.bpmn.generator.model.Edge;
16 | import io.process.analytics.tools.bpmn.generator.model.Grid;
17 | import io.process.analytics.tools.bpmn.generator.model.Position;
18 | import lombok.RequiredArgsConstructor;
19 | import lombok.extern.log4j.Log4j2;
20 |
21 | @RequiredArgsConstructor
22 | @Log4j2
23 | public class GridSearcher {
24 |
25 | private final Grid grid;
26 |
27 | public Position getPositionFrom(Edge edge) {
28 | return getPosition(edge, true);
29 | }
30 |
31 | public Position getPositionTo(Edge edge) {
32 | return getPosition(edge, false);
33 | }
34 |
35 | private Position getPosition(Edge edge, boolean isFrom) {
36 | String shapeId = isFrom && !edge.isReverted() || (!isFrom && edge.isReverted()) ? edge.getFrom() : edge.getTo();
37 | return getPositionOfShape(shapeId);
38 | }
39 |
40 | private Position getPositionOfShape(String shapeId) {
41 | return grid.getPositions()
42 | .stream()
43 | .filter(p -> shapeId.equals(p.getShape()))
44 | .findFirst()
45 | .get(); // always exist, otherwise error occur on flow node generation
46 | }
47 |
48 | public boolean isShapeExistAtLeft(Position position) {
49 | return grid.getPositions()
50 | .stream()
51 | .filter(p -> p.getY() == position.getY())
52 | .anyMatch(p -> p.getX() == position.getX() - 1);
53 | }
54 |
55 | public boolean isShapeExistAtRight(final Position position) {
56 | return grid.getPositions()
57 | .stream()
58 | .filter(p -> p.getY() == position.getY())
59 | .anyMatch(p -> p.getX() == position.getX() + 1);
60 | }
61 |
62 | public boolean isShapeExistAbove(final Position positionFrom) {
63 | return grid.getPositions()
64 | .stream()
65 | .filter(p -> p.getX() == positionFrom.getX())
66 | .anyMatch(p -> p.getY() == positionFrom.getY() - 1);
67 | }
68 |
69 | public BendConfiguration computeConfigurationToPassByEmptyRow(Position positionFrom, Position positionTo,
70 | BendDirection searchDirection) {
71 | int positionFromY = positionFrom.getY();
72 | int offset = -1;
73 | boolean isElementBetween = true;
74 |
75 | log.debug("Search empty rows in direction {}", searchDirection);
76 | while (isElementBetween) {
77 | offset++;
78 | isElementBetween = this.hasElementsBetweenPositionsHorizontally(
79 | positionFromY + searchDirection.numericFactor() * offset,
80 | positionFrom.getX(), positionTo.getX());
81 | }
82 | log.debug("Found empty row at offset {}", offset);
83 | return BendConfiguration.builder().direction(searchDirection).offset(offset).build();
84 | }
85 |
86 | private boolean hasElementsBetweenPositionsHorizontally(final int y, final int x1, final int x2) {
87 | log.debug("Searching for elements horizontally between positions. y={} x1={} x2={}", y, x1, x2);
88 | return grid.getPositions()
89 | .stream()
90 | .filter(p -> p.getY() == y)
91 | .filter(p -> p.getX() > Math.min(x1, x2))
92 | .anyMatch(p -> p.getX() < Math.max(x1, x2));
93 | }
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/converter/waypoint/Orientation.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Bonitasoft S.A.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.process.analytics.tools.bpmn.generator.converter.waypoint;
17 |
18 | public enum Orientation {
19 | Horizontal, Vertical, HorizontalVertical, VerticalHorizontal, // standard orientations
20 | VerticalHorizontalVertical // extra orientations to avoid edges overlapping shapes
21 | }
22 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/converter/waypoint/WayPointDescriptor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Bonitasoft S.A.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | package io.process.analytics.tools.bpmn.generator.converter.waypoint;
14 |
15 | import lombok.Builder;
16 | import lombok.ToString;
17 |
18 | @Builder
19 | @ToString
20 | public class WayPointDescriptor {
21 |
22 | public final Direction direction;
23 | public final Orientation orientation;
24 | public final BendConfiguration bendConfiguration;
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/converter/waypoint/WayPointsComputer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Bonitasoft S.A.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | package io.process.analytics.tools.bpmn.generator.converter.waypoint;
14 |
15 | import java.util.Collection;
16 | import java.util.List;
17 |
18 | import io.process.analytics.tools.bpmn.generator.model.Edge;
19 | import io.process.analytics.tools.bpmn.generator.model.Grid;
20 | import io.process.analytics.tools.bpmn.generator.model.Position;
21 | import io.process.analytics.tools.bpmn.generator.model.display.DisplayFlowNode;
22 | import io.process.analytics.tools.bpmn.generator.model.display.DisplayPoint;
23 | import lombok.extern.log4j.Log4j2;
24 |
25 | @Log4j2
26 | public class WayPointsComputer {
27 |
28 | private final Collection flowNodes;
29 | private final GridSearcher gridSearcher;
30 | private final WayPointsConverter wayPointsConverter = new WayPointsConverter();
31 | private final WayPointsPositioner wayPointsPositioner;
32 |
33 | public WayPointsComputer(final Grid grid, final Collection flowNodes) {
34 | this.flowNodes = flowNodes;
35 | gridSearcher = new GridSearcher(grid);
36 | wayPointsPositioner = new WayPointsPositioner(gridSearcher);
37 | }
38 |
39 | public List compute(Edge edge) {
40 | log.debug("Inferring waypoints of edge {}", edge);
41 | Position positionFrom = gridSearcher.getPositionFrom(edge);
42 | Position positionTo = gridSearcher.getPositionTo(edge);
43 |
44 | WayPointDescriptor wayPointDescriptor = wayPointsPositioner.computeWaypointDescriptor(positionFrom, positionTo);
45 | DisplayFlowNode flowNodeFrom = getFlowNode(positionFrom.getShape());
46 | DisplayFlowNode flowNodeTo = getFlowNode(positionTo.getShape());
47 |
48 | return wayPointsConverter.toDisplayPoints(wayPointDescriptor, flowNodeFrom.dimension, flowNodeTo.dimension);
49 | }
50 |
51 | private DisplayFlowNode getFlowNode(String flowNodeId) {
52 | return flowNodes.stream()
53 | .filter(f -> flowNodeId.equals(f.bpmnElementId))
54 | .findFirst()
55 | .get(); // always exist, otherwise error occur on flow node generation
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/converter/waypoint/WayPointsPositioner.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Bonitasoft S.A.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | package io.process.analytics.tools.bpmn.generator.converter.waypoint;
14 |
15 | import static io.process.analytics.tools.bpmn.generator.converter.waypoint.Direction.*;
16 | import static io.process.analytics.tools.bpmn.generator.converter.waypoint.Orientation.*;
17 |
18 | import io.process.analytics.tools.bpmn.generator.converter.waypoint.WayPointDescriptor.WayPointDescriptorBuilder;
19 | import io.process.analytics.tools.bpmn.generator.model.Position;
20 | import io.process.analytics.tools.bpmn.generator.model.ShapeType;
21 | import lombok.RequiredArgsConstructor;
22 | import lombok.extern.log4j.Log4j2;
23 |
24 | @RequiredArgsConstructor
25 | @Log4j2
26 | public class WayPointsPositioner {
27 |
28 | private final GridSearcher gridSearcher;
29 |
30 | public WayPointDescriptor computeWaypointDescriptor(Position positionFrom, Position positionTo) {
31 | WayPointDescriptorBuilder builder = WayPointDescriptor.builder();
32 |
33 | if (positionFrom.getX() == positionTo.getX()) {
34 | builder.orientation(Vertical);
35 | if (positionFrom.getY() < positionTo.getY()) {
36 | builder.direction(TopToBottom);
37 | } else {
38 | builder.direction(BottomToTop);
39 | }
40 | } else if (positionFrom.getY() == positionTo.getY()) {
41 | builder.orientation(Horizontal);
42 | int positionFromX = positionFrom.getX();
43 | int positionToX = positionTo.getX();
44 |
45 | if (positionFromX < positionToX) {
46 | builder.direction(LeftToRight);
47 | if (positionFromX + 1 != positionToX) {
48 | updateWhenExtraBendPointsRequired(builder, positionFrom, positionTo);
49 | }
50 | } else {
51 | builder.direction(RightToLeft);
52 | if (positionFromX - 1 != positionToX) {
53 | updateWhenExtraBendPointsRequired(builder, positionFrom, positionTo);
54 | }
55 | }
56 | } else if (positionFrom.getX() < positionTo.getX()) {
57 | if (positionFrom.getY() < positionTo.getY()) {
58 | builder.direction(TopLeftToBottomRight);
59 | boolean shapeExistAtRightPositionFrom = gridSearcher.isShapeExistAtRight(positionFrom);
60 | Orientation orientation = shapeExistAtRightPositionFrom
61 | || (isGatewayAt(positionFrom) && isGatewaySplitAt(positionFrom) && (!isGatewayAt(positionTo) || isGatewaySplitAt(positionTo)))
62 | ? VerticalHorizontal
63 | : HorizontalVertical;
64 | builder.orientation(orientation);
65 | } else {
66 | builder.direction(BottomLeftToTopRight);
67 | if (isGatewayAt(positionFrom)) {
68 | Orientation orientation = !isGatewaySplitAt(positionFrom)
69 | || isGatewayAt(positionTo) && !isGatewaySplitAt(positionTo)
70 | ? HorizontalVertical
71 | : VerticalHorizontal;
72 | builder.orientation(orientation);
73 | } else {
74 | boolean shapeExistAbovePositionFrom = gridSearcher.isShapeExistAbove(positionFrom);
75 | Orientation orientation = shapeExistAbovePositionFrom || isGatewayAt(positionTo)
76 | ? HorizontalVertical
77 | : VerticalHorizontal;
78 | builder.orientation(orientation);
79 | }
80 | }
81 | } else {
82 | if (positionFrom.getY() < positionTo.getY()) {
83 | builder.direction(TopRightToBottomLeft);
84 | boolean shapeExistAtLeftPositionFrom = gridSearcher.isShapeExistAtLeft(positionFrom);
85 | Orientation orientation = shapeExistAtLeftPositionFrom || isGatewaySplitAt(positionFrom)
86 | ? VerticalHorizontal
87 | : HorizontalVertical;
88 | builder.orientation(orientation);
89 | } else {
90 | builder.direction(BottomRightToTopLeft);
91 | boolean shapeExistAbovePositionFrom = gridSearcher.isShapeExistAbove(positionFrom);
92 | Orientation orientation = shapeExistAbovePositionFrom || isGatewayAt(positionTo)
93 | ? HorizontalVertical
94 | : VerticalHorizontal;
95 | builder.orientation(orientation);
96 | }
97 | }
98 |
99 | WayPointDescriptor wayPointDescriptor = builder.build();
100 | log.debug("Computed {}", wayPointDescriptor);
101 | return wayPointDescriptor;
102 | }
103 |
104 | private void updateWhenExtraBendPointsRequired(WayPointDescriptorBuilder builder, Position positionFrom,
105 | Position positionTo) {
106 | log.debug("Detected potential overlapping of horizontal edge on shapes. Shape: {}", positionFrom.getShape());
107 |
108 | BendConfiguration bendConfigurationBottom = gridSearcher.computeConfigurationToPassByEmptyRow(positionFrom, positionTo,
109 | BendDirection.BOTTOM);
110 | if (bendConfigurationBottom.offset == 0) {
111 | log.debug("Keep the horizontal orientation");
112 | return;
113 | }
114 | log.debug("Not possible to keep horizontal orientation");
115 | builder.orientation(VerticalHorizontalVertical);
116 | builder.bendConfiguration(bendConfigurationBottom);
117 |
118 | if (bendConfigurationBottom.offset == 1) {
119 | return;
120 | }
121 |
122 | BendConfiguration bendConfigurationTop = gridSearcher.computeConfigurationToPassByEmptyRow(positionFrom, positionTo,
123 | BendDirection.TOP);
124 | if (bendConfigurationTop.offset < bendConfigurationBottom.offset) {
125 | builder.bendConfiguration(bendConfigurationTop);
126 | }
127 | }
128 |
129 | private static boolean isGatewayAt(Position position) {
130 | return ShapeType.GATEWAY.equals(position.getShapeType());
131 | }
132 |
133 | private static boolean isGatewaySplitAt(Position position) {
134 | return isGatewayAt(position) && position.isSplitGateway();
135 | }
136 |
137 | }
138 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/export/ASCIIExporter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Bonitasoft S.A.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.process.analytics.tools.bpmn.generator.export;
17 |
18 | import static io.process.analytics.tools.bpmn.generator.internal.StringUtils.defaultIfNull;
19 |
20 | import java.util.Arrays;
21 | import java.util.List;
22 |
23 | import io.process.analytics.tools.bpmn.generator.model.Grid;
24 | import io.process.analytics.tools.bpmn.generator.model.Position;
25 |
26 | public class ASCIIExporter {
27 |
28 | private static final int CELL_WIDTH = 7;
29 |
30 | public String export(Grid grid) {
31 | int width = grid.width();
32 | int height = grid.height();
33 | List positions = grid.getPositions();
34 | return export(width, height, positions);
35 | }
36 |
37 | public String export(int width, int height, List positions) {
38 | char[][] charGrid = new char[height][width * CELL_WIDTH];
39 | for (char[] chars : charGrid) {
40 | Arrays.fill(chars, ' ');
41 | }
42 | for (Position position : positions) {
43 | char[] charRow = charGrid[position.getY()];
44 | char[] name = defaultIfNull(position.getShapeName()).toCharArray();
45 | System.arraycopy(name, 0, charRow, 7 * position.getX(), Math.min(name.length, CELL_WIDTH));
46 | }
47 | StringBuilder content = new StringBuilder("Diagram:\n");
48 | content.append('+').append(horizontalBar(CELL_WIDTH * width)).append('+').append('\n');
49 | for (char[] chars : charGrid) {
50 | content.append('|').append(chars).append('|').append('\n');
51 | }
52 | content.append('+').append(horizontalBar(CELL_WIDTH * width)).append('+').append('\n');
53 | return content.toString();
54 | }
55 |
56 | private char[] horizontalBar(int size) {
57 | char[] chars = new char[size];
58 | Arrays.fill(chars, '-');
59 | return chars;
60 | }
61 |
62 | public static String toAscii(Grid grid) {
63 | return new ASCIIExporter().export(grid);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/export/BPMNExporter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Bonitasoft S.A.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.process.analytics.tools.bpmn.generator.export;
17 |
18 | import io.process.analytics.tools.bpmn.generator.converter.AlgoToDisplayModelConverter;
19 | import io.process.analytics.tools.bpmn.generator.model.display.DisplayModel;
20 | import io.process.analytics.tools.bpmn.generator.internal.BPMNDiagramRichBuilder;
21 | import io.process.analytics.tools.bpmn.generator.internal.generated.model.TDefinitions;
22 | import io.process.analytics.tools.bpmn.generator.model.Diagram;
23 | import io.process.analytics.tools.bpmn.generator.model.Grid;
24 | import lombok.RequiredArgsConstructor;
25 |
26 | @RequiredArgsConstructor
27 | public class BPMNExporter {
28 |
29 | private final AlgoToDisplayModelConverter converter;
30 |
31 | public static BPMNExporter defaultBpmnExporter() {
32 | return new BPMNExporter(new AlgoToDisplayModelConverter());
33 | }
34 |
35 | public TDefinitions export(TDefinitions originalBpmnDefinitions, Grid grid, Diagram diagram) {
36 | BPMNDiagramRichBuilder builder = new BPMNDiagramRichBuilder(originalBpmnDefinitions);
37 | DisplayModel displayModel = converter.convert(grid, diagram);
38 | displayModel.flowNodes.forEach(builder::addFlowNode);
39 | displayModel.edges.forEach(builder::addEdge);
40 | return builder.build();
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/input/CSVtoBPMN.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020-2021 Bonitasoft S.A.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package io.process.analytics.tools.bpmn.generator.input;
16 |
17 | import io.process.analytics.tools.bpmn.generator.internal.Semantic;
18 | import io.process.analytics.tools.bpmn.generator.internal.generated.model.*;
19 |
20 | import javax.xml.XMLConstants;
21 | import javax.xml.namespace.QName;
22 | import java.util.ArrayList;
23 | import java.util.HashMap;
24 | import java.util.List;
25 | import java.util.Map;
26 |
27 | import static io.process.analytics.tools.bpmn.generator.internal.Semantic.addFlowNodes;
28 | import static io.process.analytics.tools.bpmn.generator.internal.Semantic.addSequenceFlows;
29 |
30 | public class CSVtoBPMN {
31 |
32 | // map original flow element id with the values we are using
33 | // id cannot be numeric, in that case we map the id with a generated one, letting edge reference element ids with the values we are using for BPMN
34 | private final Map mappingShapeId = new HashMap<>();
35 |
36 | // map flow element id with its incoming and outgoing edges
37 | private final Map shapeRelations = new HashMap<>();
38 |
39 | public TDefinitions readFromCSV(String nodes, String edges) {
40 | TProcess process = new TProcess();
41 | process.setId("process_1");
42 | TDefinitions definitions = new TDefinitions();
43 | definitions.setId("definitions_1");
44 | definitions.setTargetNamespace(XMLConstants.NULL_NS_URI);
45 | Semantic semantic = new Semantic(definitions);
46 | semantic.add(process);
47 |
48 | List flowNodeElements = getFlowNodeElements(nodes);
49 | addFlowNodes(process, flowNodeElements);
50 | addSequenceFlows(process, getEdgeElements(edges));
51 | assignIncomingAndOutgoingReferences(flowNodeElements);
52 |
53 | return definitions;
54 | }
55 |
56 | private List getFlowNodeElements(String nodes) {
57 | String[] lines = toLinesWithoutHeader(nodes);
58 | List flowElements = new ArrayList<>();
59 | for (String line : lines) {
60 | if (line == null) {
61 | continue;
62 | }
63 | String[] node = line.split(",");
64 | TFlowNode flowNode = gettFlowNode(node);
65 | flowNode.setName(removeEnclosingDoubleQuote(node[2]));
66 |
67 | String originalId = node[1];
68 | String bpmnId = originalId;
69 | if (isNumeric(originalId)) {
70 | bpmnId = "bpmnElement_" + originalId;
71 | }
72 | this.mappingShapeId.put(originalId, bpmnId);
73 |
74 | flowNode.setId(bpmnId);
75 | flowElements.add(flowNode);
76 | }
77 | return flowElements;
78 | }
79 |
80 | private static TFlowNode gettFlowNode(String[] node) {
81 | String type = removeEnclosingDoubleQuote(node[3]);
82 | TFlowNode flowNode = switch (type) {
83 | case "start_event" -> new TStartEvent();
84 | case "end_event" -> new TEndEvent();
85 | case "gateway", "parallel_gateway" -> new TParallelGateway();
86 | case "exclusive_gateway" -> new TExclusiveGateway();
87 | case "inclusive_gateway" -> new TInclusiveGateway();
88 | case "user_task" -> new TUserTask();
89 | case "service_task" -> new TServiceTask();
90 | default -> new TTask();
91 | };
92 | return flowNode;
93 | }
94 |
95 | private void assignIncomingAndOutgoingReferences(List flowNodeElements) {
96 | for (TFlowNode flowNode : flowNodeElements) {
97 | EdgeRelation edgeRelation = this.shapeRelations.get(flowNode.getId());
98 | edgeRelation.incoming.stream().map(CSVtoBPMN::bpmnElementQName).forEach(flowNode.getIncoming()::add);
99 | edgeRelation.outgoing.stream().map(CSVtoBPMN::bpmnElementQName).forEach(flowNode.getOutgoing()::add);
100 | }
101 | }
102 |
103 | // TODO rework to find the right value
104 | private static QName bpmnElementQName(String bpmnElement) {
105 | return new QName(XMLConstants.NULL_NS_URI, bpmnElement, XMLConstants.DEFAULT_NS_PREFIX); // sequenceFlow_1
106 | // return new QName("http://www.omg.org/spec/BPMN/20100524/MODEL", bpmnElement, XMLConstants.DEFAULT_NS_PREFIX); // semantic:sequenceFlow_1
107 | }
108 |
109 | private static String removeEnclosingDoubleQuote(String s) {
110 | return s.replaceAll("^\"|\"$", "");
111 | }
112 |
113 | private String[] toLinesWithoutHeader(String fileContent) {
114 | String[] lines = fileContent.split("\n");
115 | lines[0] = null;
116 | return lines;
117 | }
118 |
119 | private List getEdgeElements(String edges) {
120 | String[] lines = toLinesWithoutHeader(edges);
121 | List flowElements = new ArrayList<>();
122 | for (String line : lines) {
123 | if(line == null){
124 | continue;
125 | }
126 | String[] edge = line.split(",");
127 | TSequenceFlow tSequenceFlow = new TSequenceFlow();
128 |
129 | TUserTask sourceRef = new TUserTask();
130 | tSequenceFlow.setSourceRef(sourceRef);
131 | String sourceRefId = this.mappingShapeId.getOrDefault(edge[2], edge[2]);
132 | sourceRef.setId(sourceRefId);
133 |
134 | TUserTask targetRef = new TUserTask();
135 | tSequenceFlow.setTargetRef(targetRef);
136 | String targetRefId = this.mappingShapeId.getOrDefault(edge[3], edge[3]);
137 | targetRef.setId(targetRefId);
138 |
139 | String sequenceFlowId = edge[1];
140 | if (isNumeric(sequenceFlowId)) {
141 | sequenceFlowId = "sequenceFlow_" + sequenceFlowId;
142 | }
143 | tSequenceFlow.setId(sequenceFlowId);
144 | flowElements.add(tSequenceFlow);
145 |
146 | // prepare incoming/outgoing management
147 | getEdgeRelation(sourceRefId).outgoing.add(sequenceFlowId);
148 | getEdgeRelation(targetRefId).incoming.add(sequenceFlowId);
149 | }
150 | return flowElements;
151 | }
152 |
153 | private EdgeRelation getEdgeRelation(String shapeId) {
154 | EdgeRelation edgeRelation = this.shapeRelations.get(shapeId);
155 | if (edgeRelation == null) {
156 | edgeRelation= new EdgeRelation();
157 | this.shapeRelations.put(shapeId, edgeRelation);
158 | }
159 | return edgeRelation;
160 | }
161 |
162 | // TODO not optimal for performance, see https://www.baeldung.com/java-check-string-number
163 | // bpmn element id cannot be numeric
164 | private static boolean isNumeric(String s) {
165 | if (s == null) {
166 | return false;
167 | }
168 | try {
169 | Double.parseDouble(s);
170 | } catch (NumberFormatException nfe) {
171 | return false;
172 | }
173 | return true;
174 | }
175 |
176 | private static class EdgeRelation {
177 |
178 | public final List incoming = new ArrayList<>();
179 | public final List outgoing = new ArrayList<>();
180 |
181 | }
182 |
183 | }
184 |
185 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/internal/BPMNDiagramRichBuilder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Bonitasoft S.A.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.process.analytics.tools.bpmn.generator.internal;
17 |
18 | import java.util.ArrayList;
19 | import java.util.List;
20 | import java.util.Optional;
21 |
22 | import javax.xml.XMLConstants;
23 | import javax.xml.bind.JAXBElement;
24 | import javax.xml.namespace.QName;
25 |
26 | import io.process.analytics.tools.bpmn.generator.model.display.DisplayDimension;
27 | import io.process.analytics.tools.bpmn.generator.model.display.DisplayEdge;
28 | import io.process.analytics.tools.bpmn.generator.model.display.DisplayFlowNode;
29 | import io.process.analytics.tools.bpmn.generator.model.display.DisplayPoint;
30 | import io.process.analytics.tools.bpmn.generator.internal.generated.model.*;
31 | import io.process.analytics.tools.bpmn.generator.model.ShapeType;
32 | import lombok.NonNull;
33 | import lombok.RequiredArgsConstructor;
34 |
35 | /**
36 | * Helper to build a BPMNDiagram based on existing TDefinitions semantic part
37 | */
38 | @RequiredArgsConstructor
39 | public class BPMNDiagramRichBuilder {
40 |
41 | @NonNull
42 | private final TDefinitions definitions;
43 |
44 | private final List bpmnShapes = new ArrayList<>();
45 | private final List bpmnEdges = new ArrayList<>();
46 |
47 | // visible for testing
48 | BPMNDiagram initializeBPMNDiagram() {
49 | BPMNDiagram bpmnDiagram = new BPMNDiagram();
50 | bpmnDiagram.setId("BPMNDiagram_1");
51 |
52 | BPMNPlane bpmnPlane = new BPMNPlane();
53 | bpmnDiagram.setBPMNPlane(bpmnPlane);
54 | bpmnPlane.setId("BPMNPlane_1");
55 | putBpmnElement(bpmnPlane, computeBPMNPlaneBpmnElementId());
56 |
57 | return bpmnDiagram;
58 | }
59 |
60 | public void addFlowNode(DisplayFlowNode flowNode) {
61 | BPMNShape bpmnShape = new BPMNShape();
62 | String bpmnElementId = flowNode.bpmnElementId;
63 | bpmnShape.setId("BPMNShape_" + bpmnElementId);
64 | putBpmnElement(bpmnShape, bpmnElementId);
65 |
66 | bpmnShape.setBounds(bounds(flowNode.dimension));
67 |
68 | // For activity, don't pass label position, BPMN vendor generally manage default positionning very well (centered on activity inside)
69 | ShapeType shapeType = flowNode.type;
70 | if (!ShapeType.ACTIVITY.equals(shapeType)) {
71 | BPMNLabel label = new BPMNLabel();
72 | DisplayDimension labelDimension = flowNode.label.dimension;
73 |
74 | // For event adjust positions
75 | if(ShapeType.EVENT == shapeType) {
76 | labelDimension = new DisplayDimension( flowNode.dimension.x, labelDimension.y, labelDimension.width, labelDimension.height);
77 | }
78 |
79 | label.setBounds(bounds(labelDimension));
80 | // TODO add label style?
81 | bpmnShape.setBPMNLabel(label);
82 | }
83 |
84 | bpmnShapes.add(bpmnShape);
85 | }
86 |
87 | public void addEdge(DisplayEdge edge) {
88 | BPMNEdge bpmnEdge = new BPMNEdge();
89 | String bpmnElementId = edge.bpmnElementId;
90 | bpmnEdge.setId("BPMNEdge_" + bpmnElementId);
91 | putBpmnElement(bpmnEdge, bpmnElementId);
92 |
93 | List bpmnEdgeWaypoint = bpmnEdge.getWaypoint();
94 | edge.wayPoints.stream()
95 | .map(BPMNDiagramRichBuilder::toPoint)
96 | .forEach(bpmnEdgeWaypoint::add);
97 |
98 | bpmnEdges.add(bpmnEdge);
99 | }
100 |
101 | private static Point toPoint(DisplayPoint displayPoint) {
102 | Point point = new Point();
103 | point.setX(displayPoint.x);
104 | point.setY(displayPoint.y);
105 | return point;
106 | }
107 |
108 | private static Bounds bounds(DisplayDimension dimension) {
109 | Bounds bounds = new Bounds();
110 | bounds.setX(dimension.x);
111 | bounds.setY(dimension.y);
112 | bounds.setWidth(dimension.width);
113 | bounds.setHeight(dimension.height);
114 | return bounds;
115 | }
116 |
117 | private static void putBpmnElement(BPMNShape bpmnShape, String bpmnElementRef) {
118 | bpmnShape.setBpmnElement(noNamespaceQName(bpmnElementRef));
119 | }
120 |
121 | private static QName noNamespaceQName(String bpmnElementRef) {
122 | return new QName(XMLConstants.NULL_NS_URI, bpmnElementRef);
123 | }
124 |
125 | private static void putBpmnElement(BPMNEdge bpmnEdge, String bpmnElementRef) {
126 | bpmnEdge.setBpmnElement(noNamespaceQName(bpmnElementRef));
127 | }
128 |
129 | public TDefinitions build() {
130 | // TODO it should be better to clone the initial definitions
131 | List diagrams = definitions.getBPMNDiagram();
132 | diagrams.clear();
133 | BPMNDiagram bpmnDiagram = initializeBPMNDiagram();
134 | diagrams.add(bpmnDiagram);
135 |
136 | BPMNPlane bpmnPlane = bpmnDiagram.getBPMNPlane();
137 | List> diagramElements = bpmnPlane.getDiagramElement();
138 |
139 | bpmnShapes.stream()
140 | .map(s -> new JAXBElement<>(bpmnElementQName("BPMNShape"), BPMNShape.class, null, s))
141 | .forEach(diagramElements::add);
142 |
143 | bpmnEdges.stream()
144 | .map(s -> new JAXBElement<>(bpmnElementQName("BPMNEdge"), BPMNEdge.class, null, s))
145 | .forEach(diagramElements::add);
146 |
147 | return definitions;
148 | }
149 |
150 | private static QName bpmnElementQName(String bpmnElement) {
151 | return new QName("http://www.omg.org/spec/BPMN/20100524/DI", bpmnElement, XMLConstants.DEFAULT_NS_PREFIX);
152 | }
153 |
154 | // TODO we need to know if this is a process or a collaboration to set the actual QName
155 | private static void putBpmnElement(BPMNPlane bpmnPlane, String bpmnElementRef) {
156 | bpmnPlane.setBpmnElement(noNamespaceQName(bpmnElementRef));
157 | }
158 |
159 | // TODO move to the Semantic class?
160 | // bpmn element value depends on semantic collaboration existence
161 | // if no collaboration, there is a single process, so use its id
162 | private String computeBPMNPlaneBpmnElementId() {
163 | final Semantic semantic = new Semantic(definitions);
164 | Optional collaboration = semantic.getCollaboration();
165 | // TODO empty processes is supposed to be managed by Semantic
166 | return collaboration.map(TBaseElement::getId)
167 | .orElseGet(() -> semantic.getProcesses().get(0).getId());
168 | }
169 |
170 | }
171 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/internal/BpmnInOut.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Bonitasoft S.A.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.process.analytics.tools.bpmn.generator.internal;
17 |
18 | import static io.process.analytics.tools.bpmn.generator.internal.FileUtils.fileContent;
19 |
20 | import java.io.File;
21 | import java.io.IOException;
22 |
23 | import io.process.analytics.tools.bpmn.generator.internal.generated.model.TDefinitions;
24 |
25 | public class BpmnInOut {
26 |
27 | private final XmlParser xmlParser;
28 |
29 | public static BpmnInOut defaultBpmnInOut() {
30 | return new BpmnInOut(new XmlParser());
31 | }
32 |
33 | public BpmnInOut(XmlParser xmlParser) {
34 | this.xmlParser = xmlParser;
35 | }
36 |
37 | public TDefinitions readFromBpmn(String xml) {
38 | return xmlParser.unmarshall(xml);
39 | }
40 |
41 | public TDefinitions readFromBpmn(File bpmn) {
42 | try {
43 | String xml = fileContent(bpmn);
44 | return readFromBpmn(xml);
45 | } catch (IOException e) {
46 | throw new RuntimeException("Error while reading file " + bpmn.getName(), e);
47 | }
48 | }
49 |
50 | public String writeToBpmn(TDefinitions definitions) {
51 | return xmlParser.marshal(definitions);
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/internal/BpmnNamespacePrefixMapper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Bonitasoft S.A.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.process.analytics.tools.bpmn.generator.internal;
17 |
18 | import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
19 |
20 | import java.util.HashMap;
21 | import java.util.Map;
22 | import java.util.Set;
23 |
24 | public class BpmnNamespacePrefixMapper extends NamespacePrefixMapper {
25 |
26 | private static final Map namespaces = new HashMap<>();
27 | static {
28 | namespaces.put("http://www.omg.org/spec/BPMN/20100524/DI", "bpmndi");
29 | namespaces.put("http://www.omg.org/spec/BPMN/20100524/MODEL", "semantic");
30 | namespaces.put("http://www.omg.org/spec/DD/20100524/DC", "dc");
31 | namespaces.put("http://www.omg.org/spec/DD/20100524/DI", "di");
32 | }
33 |
34 | @Override
35 | public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
36 | return namespaces.getOrDefault(namespaceUri, suggestion);
37 | }
38 |
39 | @Override
40 | public String[] getPreDeclaredNamespaceUris() {
41 | Set uris = namespaces.keySet();
42 | return uris.toArray(new String[0]);
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/internal/FileUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Bonitasoft S.A.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.process.analytics.tools.bpmn.generator.internal;
17 |
18 | import java.io.File;
19 | import java.io.IOException;
20 | import java.nio.file.Files;
21 | import java.util.List;
22 |
23 | public class FileUtils {
24 |
25 | // when switching to JDK11+, use Files#readString instead
26 | public static String fileContent(File file) throws IOException {
27 | List strings = Files.readAllLines(file.toPath());
28 | // we do not care of having a OS related eol as the xml reader can handle whatever eol, so use an hardcoded eol
29 | return String.join("\n", strings);
30 | }
31 |
32 | public static void createParents(File file) {
33 | // TODO throw IOException if failure like commons-io
34 | file.getParentFile().mkdirs();
35 | }
36 |
37 | public static void touch(File file) throws IOException {
38 | createParents(file);
39 | file.createNewFile();
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/internal/IdUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Bonitasoft S.A.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | package io.process.analytics.tools.bpmn.generator.internal;
14 |
15 | import java.util.UUID;
16 |
17 | public class IdUtils {
18 |
19 | public static String generateRandomId() {
20 | return UUID.randomUUID().toString();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/internal/Semantic.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Bonitasoft S.A.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.process.analytics.tools.bpmn.generator.internal;
17 |
18 | import java.util.*;
19 | import java.util.stream.Collectors;
20 |
21 | import javax.xml.XMLConstants;
22 | import javax.xml.bind.JAXBElement;
23 | import javax.xml.namespace.QName;
24 |
25 | import io.process.analytics.tools.bpmn.generator.internal.generated.model.*;
26 | import lombok.Getter;
27 | import lombok.NonNull;
28 | import lombok.RequiredArgsConstructor;
29 |
30 | /**
31 | * Helper to access to the BPMN semantic part
32 | */
33 | @RequiredArgsConstructor
34 | // TODO switch to record
35 | // TODO lombok getter on class
36 | public class Semantic {
37 |
38 | @NonNull
39 | @Getter
40 | private final TDefinitions definitions;
41 |
42 | // assuming this is a TBaseElement
43 | public static String getId(Object object) {
44 | return ((TBaseElement) object).getId();
45 | }
46 |
47 | public Optional getCollaboration() {
48 | List collaborations = definitions.getRootElement().stream()
49 | .map(JAXBElement::getValue)
50 | .filter(TCollaboration.class::isInstance)
51 | .map(TCollaboration.class::cast)
52 | .toList();
53 |
54 | // TODO check at most 1 otherwise error
55 | // TODO refactor into a more functional way
56 | if (collaborations.isEmpty()) {
57 | return Optional.empty();
58 | }
59 | return Optional.of(collaborations.get(0));
60 | }
61 |
62 | public List getProcesses() {
63 | // TODO manage no process (should not occurred)
64 | return definitions.getRootElement().stream()
65 | .map(JAXBElement::getValue)
66 | .filter(TProcess.class::isInstance)
67 | .map(TProcess.class::cast)
68 | .collect(Collectors.toList());
69 | }
70 |
71 | // TODO manage lanes
72 | public BpmnElements getBpmnElements(TProcess process) {
73 | // TODO manage TLaneSet
74 | // List laneSet = process.getLaneSet();
75 | // // there is always a TLaneSet (see BPMN spec)
76 | // List lanes = laneSet.get(0).getLane();
77 | // // TODO do this for all lanes
78 | // // TODO have a look at childLaneSet
79 | // List> flowNodeRef = lanes.get(0).getFlowNodeRef();
80 |
81 |
82 | List> flowElements = process.getFlowElement();
83 | List extends TFlowElement> flowNodes = flowElements.stream()
84 | .map(JAXBElement::getValue)
85 | .filter(TFlowNode.class::isInstance)
86 | .map(TFlowNode.class::cast)
87 | .collect(Collectors.toList());
88 |
89 | List extends TSequenceFlow> sequenceFlows = flowElements.stream()
90 | .map(JAXBElement::getValue)
91 | .filter(TSequenceFlow.class::isInstance)
92 | .map(TSequenceFlow.class::cast)
93 | .collect(Collectors.toList());
94 |
95 | return new BpmnElements(flowNodes, sequenceFlows);
96 | }
97 |
98 | public void add(TProcess process) {
99 | definitions.getRootElement()
100 | .add(new JAXBElement<>(bpmnElementQName("process"), TProcess.class, null, process));
101 | }
102 |
103 | public static void addFlowNodes(TProcess process, Collection flowElements) {
104 | flowElements.stream()
105 | .map(f -> new JAXBElement<>(bpmnElementQName(f), TFlowNode.class, null, f))
106 | .forEach(f -> process.getFlowElement().add(f));
107 | }
108 |
109 | public static void addSequenceFlows(TProcess process, Collection sequenceFlowElements) {
110 | sequenceFlowElements.stream()
111 | .map(e -> new JAXBElement<>(bpmnElementQName("sequenceFlow"), TSequenceFlow.class, null, e))
112 | .forEach(e -> process.getFlowElement().add(e));
113 | }
114 |
115 | private static QName bpmnElementQName(String bpmnElement) {
116 | return new QName("http://www.omg.org/spec/BPMN/20100524/MODEL", bpmnElement, XMLConstants.DEFAULT_NS_PREFIX);
117 | }
118 |
119 | //TODO add other type of flow node elements
120 | private static final Map, String> bpmnElementBindings = new HashMap<>() {{
121 | put(TParallelGateway.class, "parallelGateway");
122 | put(TInclusiveGateway.class, "inclusiveGateway");
123 | put(TExclusiveGateway.class, "exclusiveGateway");
124 | put(TGateway.class, "gateway");
125 | put(TTask.class, "task");
126 | put(TUserTask.class, "userTask");
127 | put(TServiceTask.class, "serviceTask");
128 | put(TEndEvent.class, "endEvent");
129 | put(TStartEvent.class, "startEvent");
130 | }};
131 |
132 | private static QName bpmnElementQName(TFlowNode flowNode) {
133 | return bpmnElementQName(bpmnElementBindings.getOrDefault(flowNode.getClass(), "task"));
134 | }
135 |
136 | @RequiredArgsConstructor
137 | @Getter
138 | public static class BpmnElements {
139 |
140 | private final List extends TFlowElement> flowNodes;
141 | private final List extends TSequenceFlow> sequenceFlows;
142 | }
143 |
144 | }
145 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/internal/StringUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Bonitasoft S.A.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.process.analytics.tools.bpmn.generator.internal;
17 |
18 | public class StringUtils {
19 |
20 | public static String defaultIfNull(String string) {
21 | return string != null ? string : "";
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/internal/XmlParser.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Bonitasoft S.A.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.process.analytics.tools.bpmn.generator.internal;
17 |
18 | import java.io.StringReader;
19 | import java.io.StringWriter;
20 |
21 | import javax.xml.bind.*;
22 | import javax.xml.transform.stream.StreamSource;
23 |
24 | import io.process.analytics.tools.bpmn.generator.internal.generated.model.ObjectFactory;
25 | import io.process.analytics.tools.bpmn.generator.internal.generated.model.TDefinitions;
26 |
27 | public class XmlParser {
28 |
29 | private static final JAXBContext context = initContext();
30 |
31 | private static JAXBContext initContext() {
32 | try {
33 | return JAXBContext.newInstance(TDefinitions.class);
34 | } catch (JAXBException e) {
35 | throw new RuntimeException("Unable to initialize the JAXBContext", e);
36 | }
37 | }
38 |
39 | public String marshal(TDefinitions definitions) {
40 | try {
41 | JAXBElement root = new ObjectFactory().createDefinitions(definitions);
42 | StringWriter stringWriter = new StringWriter();
43 | createMarshaller().marshal(root, stringWriter);
44 | return stringWriter.toString();
45 | } catch (JAXBException e) {
46 | throw new RuntimeException("Unable to marshal", e);
47 | }
48 | }
49 |
50 | private Marshaller createMarshaller() throws JAXBException {
51 | Marshaller marshaller = context.createMarshaller();
52 | marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
53 | try {
54 | marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new BpmnNamespacePrefixMapper());
55 | } catch(PropertyException e) {
56 | // In case another JAXB implementation is used
57 | // do not stop processing, namespace prefixes will be generated automatically in that case
58 | // TODO switch to logger
59 | e.printStackTrace();
60 | }
61 | return marshaller;
62 | }
63 |
64 | public TDefinitions unmarshall(String xml) {
65 | try {
66 | StreamSource source = new StreamSource(new StringReader(xml));
67 | JAXBElement root = context.createUnmarshaller().unmarshal(source, TDefinitions.class);
68 | return root.getValue();
69 | } catch (JAXBException e) {
70 | throw new RuntimeException("Unable to marshal", e);
71 | }
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/model/Diagram.java:
--------------------------------------------------------------------------------
1 | package io.process.analytics.tools.bpmn.generator.model;
2 |
3 | import java.util.List;
4 | import java.util.Set;
5 | import java.util.stream.Collectors;
6 |
7 | import lombok.Builder;
8 | import lombok.Data;
9 | import lombok.Singular;
10 |
11 | @Data
12 | @Builder
13 | public class Diagram {
14 |
15 | @Singular
16 | private List shapes;
17 | @Singular
18 | private Set edges;
19 |
20 |
21 | public List getIncomingEdges(String shapeId) {
22 | return edges.stream().filter(e -> e.getTo().equals(shapeId)).collect(Collectors.toList());
23 | }
24 |
25 | public List getOutgoingEdges(String shapeId) {
26 | return edges.stream().filter(e -> e.getFrom().equals(shapeId)).collect(Collectors.toList());
27 | }
28 |
29 | public List getOriginalIncomingEdges(String shapeId) {
30 | return edges.stream().filter(e -> (e.getTo().equals(shapeId) && !e.isReverted()) || (e.getFrom().equals(shapeId) && e.isReverted())).collect(Collectors.toList());
31 | }
32 |
33 | public List getOriginalOutgoingEdges(String shapeId) {
34 | return edges.stream().filter(e -> (e.getFrom().equals(shapeId) && !e.isReverted()) || (e.getTo().equals(shapeId) && e.isReverted())).collect(Collectors.toList());
35 | }
36 |
37 | public Shape getShape(String shapeId) {
38 | return shapes.stream().filter(s -> s.getId().equals(shapeId)).findFirst().get();
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/model/Edge.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Bonitasoft S.A.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.process.analytics.tools.bpmn.generator.model;
17 |
18 | import static io.process.analytics.tools.bpmn.generator.internal.IdUtils.generateRandomId;
19 |
20 | import lombok.Builder;
21 | import lombok.Data;
22 |
23 | @Data
24 | @Builder( toBuilder = true)
25 | public class Edge {
26 |
27 | private final String id; // the bpmnElement id
28 | private final String from;
29 | private final String to;
30 | /**
31 | * This property helps to break cycles
32 | *
33 | * `true` when the original edge is in the opposite direction
34 | *
35 | * When drown, it should be drown in the opposite direction.
36 | * When positioning shapes, it should be kept reverted
37 | */
38 | private final boolean reverted;
39 |
40 | public static Edge edge(String id, String from, String to) {
41 | return new Edge(id, from, to, false);
42 | }
43 | public static Edge edge(Shape from, Shape to) {
44 | return new Edge(generateRandomId(), copy(from.getId()), copy(to.getId()), false);
45 | }
46 | public static Edge revertedEdge(Edge original) {
47 | return original.toBuilder().from(original.getTo()).to(original.getFrom()).reverted(true).build();
48 | }
49 |
50 | private static String copy(String s) {
51 | return s + ""; // hack to ensure the returned string is equal to the provided one but doesn't have the same reference
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/model/Grid.java:
--------------------------------------------------------------------------------
1 | package io.process.analytics.tools.bpmn.generator.model;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import java.util.stream.Collectors;
6 |
7 | /**
8 | *
9 | * Represent a grid with coordinate as follows
10 | *
11 | *
12 | * + ➞ x
13 | * ↓
14 | * y
15 | *
16 | */
17 | // TODO use lombok getter?
18 | public class Grid {
19 |
20 | private final List positions = new ArrayList<>();
21 |
22 | public static Grid of(Position... positions) {
23 | Grid grid = new Grid();
24 | for (Position position : positions) {
25 | grid.add(position);
26 | }
27 | return grid;
28 | }
29 |
30 | /**
31 | * @return the width of the grid
32 | */
33 | public int width() {
34 | return getLastColumnIndex() + 1;
35 | }
36 |
37 | /**
38 | * @return the height of the grid
39 | */
40 | public int height() {
41 | return getLastRowIndex() + 1;
42 | }
43 |
44 | public Integer getLastRowIndex() {
45 | return positions.stream().map(Position::getY).reduce(-1, Math::max);
46 | }
47 |
48 | public Integer getLastColumnIndex() {
49 | return positions.stream().map(Position::getX).reduce(-1, Math::max);
50 | }
51 |
52 | public List getPositions() {
53 | return positions;
54 | }
55 |
56 | public Position getPosition(String node) {
57 | return positions.stream().filter(position -> position.getShape().equals(node)).findFirst().orElseThrow(() -> new IllegalStateException("Node not yet positionned in grid:" + node));
58 | }
59 |
60 | public List getRow(int index) {
61 | return positions.stream().filter(p -> p.getY() == index).collect(Collectors.toList());
62 | }
63 |
64 | public void remove(Position position) {
65 | if (!positions.contains(position)) {
66 | throw new IllegalArgumentException("Position " + position + " is not in the grid");
67 | }
68 | positions.remove(position);
69 | }
70 |
71 | /**
72 | * Add a new position the grid
73 | *
74 | * @param position to add
75 | */
76 | public void add(Position position) {
77 | positions.add(position);
78 | }
79 |
80 | /**
81 | * Add a new row after a given row
82 | * This will update positions of all elements already in this grid
83 | *
84 | * @param y add a row after that row
85 | */
86 | public void addRowAfter(int y) {
87 | for (Position cellToMove : getAllPositionBelow(y)) {
88 | positions.remove(cellToMove);
89 | positions.add(cellToMove.toBuilder().y(cellToMove.getY() + 1).build());
90 | }
91 | }
92 |
93 | private List getAllPositionBelow(int y) {
94 | return positions.stream().filter(p -> p.getY() > y).collect(Collectors.toList());
95 | }
96 |
97 | public void addRowBefore(int y) {
98 | addRowAfter(y - 1);
99 | }
100 |
101 | public void removeEmptyRow(int y) {
102 | List row = getRow(y);
103 | if (!row.isEmpty()) {
104 | throw new IllegalArgumentException("Row " + y + " is not empty");
105 | }
106 | for (Position cellToMove : getAllPositionBelow(y)) {
107 | positions.remove(cellToMove);
108 | positions.add(cellToMove.toBuilder().y(cellToMove.getY() - 1).build());
109 | }
110 | }
111 |
112 | public boolean isFilled(Position position) {
113 | return positions.stream().anyMatch(p -> p.getX() == position.getX() && p.getY() == position.getY());
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/model/Position.java:
--------------------------------------------------------------------------------
1 | package io.process.analytics.tools.bpmn.generator.model;
2 |
3 | import lombok.Builder;
4 | import lombok.Data;
5 |
6 | @Data
7 | @Builder(toBuilder = true)
8 | public class Position {
9 | private final String shape;
10 | private final String shapeName;
11 | private final ShapeType shapeType;
12 | private final boolean isSplitGateway;
13 |
14 | private final int x;
15 | private final int y;
16 |
17 | public static Position position(Shape shape, int x, int y) {
18 | return new Position(shape.getId(), shape.getName(), shape.getType(), shape.isSplitGateway(), x, y);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/model/Shape.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Bonitasoft S.A.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.process.analytics.tools.bpmn.generator.model;
17 |
18 | import static io.process.analytics.tools.bpmn.generator.model.ShapeType.ACTIVITY;
19 |
20 | import lombok.Builder;
21 | import lombok.Data;
22 | import lombok.RequiredArgsConstructor;
23 |
24 | @Data
25 | @Builder(toBuilder = true)
26 | @RequiredArgsConstructor
27 | // TODO switch to record
28 | public class Shape {
29 |
30 | private final String id; // the bpmnElement id
31 | private final String name;
32 | private final ShapeType type;
33 | private final boolean isSplitGateway;
34 |
35 | public static Shape shape(String name) {
36 | return new Shape(name, name, ACTIVITY, false);
37 | }
38 |
39 | public static Shape shape(String id, String name) {
40 | return new Shape(id, name, ACTIVITY, false);
41 | }
42 |
43 | public static Shape shape(String id, String name, ShapeType type) {
44 | return new Shape(id, name, type, false);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/model/ShapeType.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Bonitasoft S.A.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.process.analytics.tools.bpmn.generator.model;
17 |
18 | public enum ShapeType {
19 | ACTIVITY, EVENT, GATEWAY
20 | }
21 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/model/display/DisplayDimension.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Bonitasoft S.A.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | package io.process.analytics.tools.bpmn.generator.model.display;
14 |
15 | import lombok.RequiredArgsConstructor;
16 |
17 | @RequiredArgsConstructor
18 | // TODO switch to record
19 | public class DisplayDimension {
20 |
21 | public final int x;
22 | public final int y;
23 | public final int width;
24 | public final int height;
25 | }
26 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/model/display/DisplayEdge.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Bonitasoft S.A.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | package io.process.analytics.tools.bpmn.generator.model.display;
14 |
15 | import lombok.Builder;
16 | import lombok.RequiredArgsConstructor;
17 |
18 | import java.util.List;
19 |
20 | @RequiredArgsConstructor
21 | @Builder
22 | // TODO switch to record
23 | public class DisplayEdge {
24 |
25 | public final String bpmnElementId;
26 | public final List wayPoints;
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/model/display/DisplayFlowNode.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Bonitasoft S.A.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | package io.process.analytics.tools.bpmn.generator.model.display;
14 |
15 | import io.process.analytics.tools.bpmn.generator.model.ShapeType;
16 | import lombok.Builder;
17 | import lombok.RequiredArgsConstructor;
18 |
19 | @RequiredArgsConstructor
20 | @Builder
21 | // TODO switch to record
22 | public class DisplayFlowNode {
23 |
24 | public final String bpmnElementId;
25 | public final DisplayDimension dimension;
26 | public final DisplayLabel label;
27 | // for non BPMN exporters only
28 | public final ShapeType type;
29 | public final int rx;
30 | public final int strokeWidth;
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/model/display/DisplayLabel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Bonitasoft S.A.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | package io.process.analytics.tools.bpmn.generator.model.display;
14 |
15 | import lombok.RequiredArgsConstructor;
16 |
17 | @RequiredArgsConstructor
18 | // TODO switch to record
19 | public class DisplayLabel {
20 |
21 | public final String text; // for non BPMN exporters only
22 | public final int fontSize;
23 | public final DisplayDimension dimension;
24 | }
25 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/model/display/DisplayModel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Bonitasoft S.A.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | package io.process.analytics.tools.bpmn.generator.model.display;
14 |
15 | import lombok.Builder;
16 | import lombok.RequiredArgsConstructor;
17 | import lombok.Singular;
18 |
19 | import java.util.List;
20 |
21 | @RequiredArgsConstructor
22 | @Builder
23 | // TODO switch to record
24 | public class DisplayModel {
25 | public final int width;
26 | public final int height;
27 |
28 | @Singular
29 | public final List flowNodes;
30 | @Singular
31 | public final List edges;
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/java/src/main/java/io/process/analytics/tools/bpmn/generator/model/display/DisplayPoint.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Bonitasoft S.A.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | package io.process.analytics.tools.bpmn.generator.model.display;
14 |
15 | import lombok.RequiredArgsConstructor;
16 | import lombok.ToString;
17 |
18 | @RequiredArgsConstructor
19 | @ToString
20 | // TODO switch to record
21 | public class DisplayPoint {
22 |
23 | public final int x;
24 | public final int y;
25 | }
26 |
--------------------------------------------------------------------------------
/java/src/main/resources/log4j2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/java/src/main/xsd/BPMN20.xsd:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/java/src/main/xsd/BPMNDI.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/java/src/main/xsd/DC.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/java/src/main/xsd/DI.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/java/src/test/java/io/process/analytics/tools/bpmn/generator/AppFromBpmnTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Bonitasoft S.A.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.process.analytics.tools.bpmn.generator;
17 |
18 | import org.junit.jupiter.api.Test;
19 |
20 | import java.io.File;
21 | import java.io.IOException;
22 |
23 | import static io.process.analytics.tools.bpmn.generator.App.runApp;
24 | import static io.process.analytics.tools.bpmn.generator.AppTest.*;
25 | import static io.process.analytics.tools.bpmn.generator.internal.FileUtils.fileContent;
26 | import static org.assertj.core.api.Assertions.assertThat;
27 |
28 | public class AppFromBpmnTest {
29 |
30 | @Test
31 | public void main_generates_output_files_for_A_2_0() throws Exception {
32 | runAndCheckBpmnAndSvgGeneration("A.2.0.bpmn.xml");
33 | }
34 |
35 | @Test
36 | public void main_generates_output_files_for_A_2_1() throws Exception {
37 | runAndCheckBpmnAndSvgGeneration("A.2.1.bpmn.xml");
38 | }
39 |
40 | @Test
41 | public void main_generates_ascii_output_file() throws Exception {
42 | String outputPath = outputPath("02-startEvent_task_endEvent-without-collaboration.bpmn.txt");
43 | runApp(input("bpmn/02-startEvent_task_endEvent-without-collaboration.bpmn.xml"), "--output-type=ASCII", "-o", outputPath);
44 |
45 | File asciiFile = new File(outputPath);
46 | assertThat(asciiFile).exists().isFile();
47 | assertThat(fileContent(asciiFile)).contains("+---");
48 | }
49 |
50 | @Test
51 | public void main_generates_output_files_for_waypoints_positions_for_gateways() throws Exception {
52 | runAndCheckBpmnAndSvgGeneration("waypoints-positions-gateways.bpmn.xml");
53 | }
54 |
55 | @Test
56 | public void main_generates_output_files_for_waypoints_positions_for_gateways_split_join() throws Exception {
57 | runAndCheckBpmnAndSvgGeneration("waypoints-positions-gateways_split_join.bpmn.xml");
58 | }
59 |
60 | @Test
61 | public void main_generates_output_files_for_waypoints_positions_cycle_01_simple() throws Exception {
62 | runAndCheckBpmnAndSvgGeneration("waypoints-positions-cycle_01_simple.bpmn.xml");
63 | }
64 |
65 | @Test
66 | public void main_generates_output_files_for_waypoints_positions_cycle_02_gateways_in_cycle() throws Exception {
67 | runAndCheckBpmnAndSvgGeneration("waypoints-positions-cycle_02_gateways_in_cycle.bpmn.xml");
68 | }
69 |
70 | // =================================================================================================================
71 | // Avoid edge overlap on shape
72 | // =================================================================================================================
73 |
74 | @Test
75 | public void main_generates_output_files_waypoints_avoid_edge_overlap_01_single_branch() throws Exception {
76 | runAndCheckBpmnAndSvgGeneration("waypoints-avoid-edge-overlap-01-single_branch.bpmn.xml");
77 | }
78 |
79 | @Test
80 | public void main_generates_output_files_waypoints_avoid_edge_overlap_02_2nd_branch_with_large_height()
81 | throws Exception {
82 | runAndCheckBpmnAndSvgGeneration("waypoints-avoid-edge-overlap-02-2nd-branch-with-large-height.bpmn.xml");
83 | }
84 |
85 | @Test
86 | public void main_generates_output_files_waypoints_avoid_edge_overlap_03_elements_in_front()
87 | throws Exception {
88 | runAndCheckBpmnAndSvgGeneration("waypoints-avoid-edge-overlap-03-elements_in_front.bpmn.xml");
89 | }
90 |
91 | @Test
92 | public void main_generates_output_files_waypoints_avoid_edge_overlap_04_multiple_empty_paths() throws Exception {
93 | runAndCheckBpmnAndSvgGeneration("waypoints-avoid-edge-overlap-04-multiple_empty_paths.bpmn.xml");
94 | }
95 |
96 | // =================================================================================================================
97 | // UTILS
98 | // =================================================================================================================
99 |
100 | private static void runAndCheckBpmnAndSvgGeneration(String inputFileName) throws IOException {
101 | runAndCheckBpmnGeneration(inputFileName);
102 | runAndCheckSvgGeneration(inputFileName);
103 | }
104 |
105 | private static void runAndCheckBpmnGeneration(String inputFileName) throws IOException {
106 | String outputPath = outputPath(inputFileName);
107 | runApp(input("bpmn/" + inputFileName), "-o", outputPath);
108 | assertBpmnOutFile(outputPath);
109 | }
110 |
111 | private static void runAndCheckSvgGeneration(String inputFileName) throws IOException {
112 | String outputPath = outputPath(inputFileName + ".svg");
113 | runApp(input("bpmn/" + inputFileName), "--output-type=SVG", "-o", outputPath);
114 | assertSvgOutFile(outputPath);
115 | }
116 |
117 | private static String outputPath(String fileName) {
118 | return "target/test/output/AppFromBpmnTest/" + fileName;
119 | }
120 |
121 | }
122 |
--------------------------------------------------------------------------------
/java/src/test/java/io/process/analytics/tools/bpmn/generator/AppFromCsvTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Bonitasoft S.A.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.process.analytics.tools.bpmn.generator;
17 |
18 | import static io.process.analytics.tools.bpmn.generator.App.runApp;
19 | import static io.process.analytics.tools.bpmn.generator.AppTest.*;
20 |
21 | import java.io.IOException;
22 |
23 | import org.junit.jupiter.api.Test;
24 |
25 | public class AppFromCsvTest {
26 |
27 | @Test
28 | public void main_generates_bpmn_with_simple_discovery_data() throws Exception {
29 | runAndCheckBpmnAndSvgGeneration("csv/PatientsProcess/nodeSimple.csv", "csv/PatientsProcess/edgeSimple.csv",
30 | "from_simple_csv_diagram.bpmn");
31 | }
32 |
33 | @Test
34 | public void main_generates_bpmn_with_gateways() throws Exception {
35 | runAndCheckBpmnAndSvgGeneration("csv/PatientsProcess/gateway_node_simple.csv",
36 | "csv/PatientsProcess/gateway_edge_simple.csv", "from_csv_with_gateways.bpmn");
37 | }
38 |
39 | @Test
40 | public void main_generates_bpmn_with_patients_process_discovery_data() throws Exception {
41 | runAndCheckBpmnAndSvgGeneration("csv/PatientsProcess/node.csv", "csv/PatientsProcess/edge.csv",
42 | "from_patients_csv_diagram.bpmn");
43 | }
44 |
45 | @Test
46 | public void main_generates_bpmn_with_vacation_request_bonita_discovery_data() throws Exception {
47 | runAndCheckBpmnAndSvgGeneration("csv/VacationRequestBonita/nodes.csv", "csv/VacationRequestBonita/edges.csv",
48 | "from_vacation_request_bonita_csv_diagram.bpmn");
49 | }
50 |
51 | @Test
52 | public void main_generates_bpmn_with_vacation_request_bonita_v2_discovery_data() throws Exception {
53 | runAndCheckBpmnAndSvgGeneration("csv/VacationRequestBonita_v2/nodes.csv",
54 | "csv/VacationRequestBonita_v2/edges.csv",
55 | "from_vacation_request_bonita_v2_csv_diagram.bpmn");
56 | }
57 |
58 | // =================================================================================================================
59 | // UTILS
60 | // =================================================================================================================
61 |
62 | private static void runAndCheckBpmnAndSvgGeneration(String inputNodesFileName, String inputEdgesFileName,
63 | String outputFileBaseName) throws IOException {
64 | runAndCheckBpmnGeneration(inputNodesFileName, inputEdgesFileName, outputFileBaseName + ".xml");
65 | runAndCheckSvgGeneration(inputNodesFileName, inputEdgesFileName, outputFileBaseName + ".svg");
66 | }
67 |
68 | private static void runAndCheckBpmnGeneration(String inputNodesFileName, String inputEdgesFileName,
69 | String outputFileName) throws IOException {
70 | String outputPath = outputPath(outputFileName);
71 | runApp("--input-type=CSV", "--output", outputPath, input(inputNodesFileName), input(inputEdgesFileName));
72 | assertBpmnOutFile(outputPath);
73 | }
74 |
75 | private static void runAndCheckSvgGeneration(String inputNodesFileName, String inputEdgesFileName, String outputFileName) throws IOException {
76 | String outputPath = outputPath(outputFileName);
77 | runApp("--input-type=CSV", "--output-type=SVG", "--output", outputPath, input(inputNodesFileName), input(inputEdgesFileName));
78 | assertSvgOutFile(outputPath);
79 | }
80 |
81 | private static String outputPath(String fileName) {
82 | return "target/test/output/AppFromCsvTest/" + fileName;
83 | }
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/java/src/test/java/io/process/analytics/tools/bpmn/generator/AppTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Bonitasoft S.A.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.process.analytics.tools.bpmn.generator;
17 |
18 | import static io.process.analytics.tools.bpmn.generator.App.runApp;
19 | import static io.process.analytics.tools.bpmn.generator.internal.FileUtils.fileContent;
20 | import static org.assertj.core.api.Assertions.assertThat;
21 |
22 | import java.io.File;
23 | import java.io.IOException;
24 |
25 | import org.junit.jupiter.api.Test;
26 |
27 | public class AppTest {
28 |
29 | @Test
30 | public void main_fail_on_non_existing_input_file() throws Exception {
31 | int returnCode = runApp("input");
32 |
33 | assertThat(returnCode).isEqualTo(2);
34 | }
35 |
36 | @Test
37 | public void main_fail_on_wrong_export_type() throws Exception {
38 | int returnCode = runApp("input", "--output-type", "unknown_export_type");
39 |
40 | assertThat(returnCode).isEqualTo(2);
41 | }
42 |
43 | // =================================================================================================================
44 | // UTILS
45 | // =================================================================================================================
46 |
47 | public static void assertBpmnOutFile(String outputPath) throws IOException {
48 | File bpmnFile = new File(outputPath);
49 | assertThat(bpmnFile).exists().isFile();
50 | assertThat(fileContent(bpmnFile)).contains("
34 | // task_1
35 | //
36 | //
37 | // startEvent_1
38 | // endEvent_1
39 | //
40 | //
41 | // task_1
42 | //
43 | //
44 | //
45 | TDefinitions definitions = definitionsFromBpmnFile(
46 | "src/test/resources/bpmn/02-startEvent_task_endEvent-without-collaboration.bpmn.xml");
47 |
48 | Diagram diagram = new BpmnToAlgoModelConverter().toAlgoModel(definitions);
49 |
50 | assertThat(diagram.getShapes()).containsOnly(
51 | shape("startEvent_1", "Start Event", EVENT),
52 | shape("task_1", "Task 1", ACTIVITY),
53 | shape("endEvent_1", "End Event", EVENT));
54 | assertThat(diagram.getEdges()).containsOnly(
55 | edge("sequenceFlow_1", "startEvent_1", "task_1"),
56 | edge("sequenceFlow_2", "task_1", "endEvent_1"));
57 | }
58 |
59 | @Test
60 | void should_convert_activities_to_shape() {
61 | assertThat(toShape(new TUserTask(), new TSendTask(), new TSubProcess()))
62 | .containsOnly(shape("bpmn_id", "bpmn_name", ACTIVITY));
63 | }
64 |
65 | private static Stream toShape(TFlowNode... flowNodes) {
66 | return Stream.of(flowNodes).map(BpmnToAlgoModelConverterTest::setBaseFields)
67 | .map(BpmnToAlgoModelConverter::toShape);
68 | }
69 |
70 | private static TFlowNode setBaseFields(TFlowNode flowNode) {
71 | flowNode.setId("bpmn_id");
72 | flowNode.setName("bpmn_name");
73 | return flowNode;
74 | }
75 |
76 | @Test
77 | void should_convert_events_to_shape() {
78 | assertThat(toShape(new TStartEvent(), new TIntermediateCatchEvent(), new TEndEvent()))
79 | .containsOnly(shape("bpmn_id", "bpmn_name", EVENT));
80 | }
81 |
82 | @Test
83 | void should_convert_gateways_to_shape() {
84 | assertThat(toShape(new TParallelGateway(), new TComplexGateway()))
85 | .containsOnly(shape("bpmn_id", "bpmn_name", GATEWAY));
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/java/src/test/java/io/process/analytics/tools/bpmn/generator/export/SVGExporterTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 Bonitasoft S.A.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 |
14 | package io.process.analytics.tools.bpmn.generator.export;
15 |
16 | import io.process.analytics.tools.bpmn.generator.converter.waypoint.Direction;
17 | import io.process.analytics.tools.bpmn.generator.model.display.DisplayPoint;
18 | import org.junit.jupiter.params.ParameterizedTest;
19 | import org.junit.jupiter.params.provider.Arguments;
20 | import org.junit.jupiter.params.provider.MethodSource;
21 |
22 | import java.util.List;
23 | import java.util.stream.Stream;
24 |
25 | import static org.assertj.core.api.Assertions.assertThat;
26 |
27 | class SVGExporterTest {
28 |
29 | @ParameterizedTest
30 | @MethodSource("provideWaypointsForDirectionDetection")
31 | void detect_last_segment_direction(List waypoints, Direction expectedDirection) {
32 | var direction = SVGExporter.detectLastSegmentDirection(waypoints);
33 | assertThat(direction).isEqualTo(expectedDirection);
34 | }
35 |
36 | private static Stream provideWaypointsForDirectionDetection() {
37 | return Stream.of(
38 | Arguments.of(List.of(new DisplayPoint(0, 37), new DisplayPoint(10, 37)), Direction.LeftToRight),
39 | Arguments.of(List.of(new DisplayPoint(40, 58), new DisplayPoint(10, 58)), Direction.RightToLeft),
40 | Arguments.of(List.of(new DisplayPoint(13, 73), new DisplayPoint(13, 137)), Direction.TopToBottom),
41 | Arguments.of(List.of(new DisplayPoint(33, 73), new DisplayPoint(33, 37)), Direction.BottomToTop)
42 | );
43 | }
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/java/src/test/java/io/process/analytics/tools/bpmn/generator/input/CSVtoBPMNTest.java:
--------------------------------------------------------------------------------
1 | package io.process.analytics.tools.bpmn.generator.input;
2 |
3 | import io.process.analytics.tools.bpmn.generator.internal.Semantic;
4 | import io.process.analytics.tools.bpmn.generator.internal.Semantic.BpmnElements;
5 | import io.process.analytics.tools.bpmn.generator.internal.generated.model.*;
6 | import org.junit.jupiter.api.Test;
7 |
8 | import javax.xml.namespace.QName;
9 | import java.io.File;
10 | import java.io.IOException;
11 | import java.util.List;
12 | import java.util.stream.Collectors;
13 |
14 | import static io.process.analytics.tools.bpmn.generator.internal.FileUtils.fileContent;
15 | import static io.process.analytics.tools.bpmn.generator.internal.Semantic.getId;
16 | import static org.assertj.core.api.Assertions.assertThat;
17 |
18 | class CSVtoBPMNTest {
19 | @Test
20 | public void should_convert_csv_to_bpmn() throws IOException {
21 | String edge = readCsvFile("src/test/resources/csv/PatientsProcess/edge.csv");
22 | String node = readCsvFile("src/test/resources/csv/PatientsProcess/node.csv");
23 |
24 | TDefinitions definitions = new CSVtoBPMN().readFromCSV(node, edge);
25 | assertThat(definitions.getId()).isNotNull();
26 | Semantic semantic = new Semantic(definitions);
27 |
28 | List processes = semantic.getProcesses();
29 | assertThat(processes).hasSize(1);
30 | TProcess process = processes.get(0);
31 | assertThat(process.getId()).isNotNull();
32 | BpmnElements bpmnElements = semantic.getBpmnElements(process);
33 | List extends TFlowElement> flowNodes = bpmnElements.getFlowNodes();
34 | assertThat(flowNodes).hasSize(9);
35 | TFlowElement flowElement0 = flowNodes.get(0);
36 | assertThat(flowElement0.getId()).isEqualTo("bpmnElement_1");
37 | assertThat(flowElement0.getName()).isEqualTo("End");
38 | assertThat(flowElement0).isExactlyInstanceOf(TTask.class);
39 |
40 | List extends TSequenceFlow> sequenceFlows = bpmnElements.getSequenceFlows();
41 | assertThat(sequenceFlows).hasSize(13);
42 | TSequenceFlow sequenceFlow12 = sequenceFlows.get(12);
43 | assertThat(sequenceFlow12.getId()).isEqualTo("sequenceFlow_13");
44 | assertThat(getId(sequenceFlow12.getSourceRef())).isEqualTo("bpmnElement_9");
45 | assertThat(getId(sequenceFlow12.getTargetRef())).isEqualTo("bpmnElement_5");
46 | }
47 |
48 | @Test
49 | public void should_convert_csv_with_gateways() throws IOException {
50 | String edge = readCsvFile("src/test/resources/csv/PatientsProcess/gateway_edge_simple.csv");
51 | String node = readCsvFile("src/test/resources/csv/PatientsProcess/gateway_node_simple.csv");
52 |
53 | TDefinitions definitions = new CSVtoBPMN().readFromCSV(node, edge);
54 |
55 | Semantic semantic = new Semantic(definitions);
56 | BpmnElements bpmnElements = semantic.getBpmnElements(semantic.getProcesses().get(0));
57 | List extends TFlowElement> flowNodes = bpmnElements.getFlowNodes();
58 | assertThat(flowNodes).hasSize(5);
59 | assertThat(flowNodes).anyMatch(f -> f.getName().equals("End") && (f instanceof TEndEvent));
60 | assertThat(flowNodes).anyMatch(f -> f.getName().equals("Start") && (f instanceof TStartEvent));
61 | assertThat(flowNodes).anyMatch(f -> f.getName().equals("Task1") && (f instanceof TTask));
62 | assertThat(flowNodes).anyMatch(f -> f.getName().equals("UserTask") && (f instanceof TUserTask));
63 | assertThat(flowNodes).anyMatch(f -> f.getName().equals("Gateway1") && (f instanceof TGateway));
64 | }
65 |
66 | @Test
67 | public void should_set_incoming_and_outgoing_edges() throws IOException {
68 | String edge = readCsvFile("src/test/resources/csv/PatientsProcess/gateway_edge_simple.csv");
69 | String node = readCsvFile("src/test/resources/csv/PatientsProcess/gateway_node_simple.csv");
70 |
71 | TDefinitions definitions = new CSVtoBPMN().readFromCSV(node, edge);
72 |
73 | Semantic semantic = new Semantic(definitions);
74 | BpmnElements bpmnElements = semantic.getBpmnElements(semantic.getProcesses().get(0));
75 | List extends TFlowElement> flowNodes = bpmnElements.getFlowNodes();
76 | TGateway gateway1 = (TGateway) flowNodes.stream().filter(f -> f.getName().equals("Gateway1"))
77 | .collect(Collectors.toList()).get(0);
78 |
79 | assertThat(gateway1.getIncoming()).extracting(QName::getLocalPart).containsExactlyInAnyOrder("sequenceFlow_1");
80 | assertThat(gateway1.getOutgoing()).extracting(QName::getLocalPart).containsExactlyInAnyOrder("sequenceFlow_2", "sequenceFlow_3");
81 | }
82 |
83 | // =================================================================================================================
84 | // UTILS
85 | // =================================================================================================================
86 |
87 | // TODO the underlying method read lines then join. The CSVtoBPMN spit the string into lines! Useless work!
88 | private static String readCsvFile(String csvFilePath) throws IOException {
89 | return fileContent(new File(csvFilePath));
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/java/src/test/java/io/process/analytics/tools/bpmn/generator/internal/BPMNDiagramRichBuilderTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Bonitasoft S.A.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.process.analytics.tools.bpmn.generator.internal;
17 |
18 | import static io.process.analytics.tools.bpmn.generator.internal.SemanticTest.definitionsFromBpmnFile;
19 | import static org.assertj.core.api.Assertions.assertThat;
20 |
21 | import java.util.List;
22 |
23 | import javax.xml.namespace.QName;
24 |
25 | import org.junit.jupiter.api.Test;
26 |
27 | import io.process.analytics.tools.bpmn.generator.internal.generated.model.BPMNDiagram;
28 | import io.process.analytics.tools.bpmn.generator.internal.generated.model.BPMNPlane;
29 | import io.process.analytics.tools.bpmn.generator.internal.generated.model.TDefinitions;
30 |
31 | class BPMNDiagramRichBuilderTest {
32 |
33 | @Test
34 | public void initializeBPMNDiagram_when_collaboration_exist_in_bpmn_file() {
35 | BPMNDiagramRichBuilder builder = newBuildFromBpmnFile("src/test/resources/bpmn/01-startEvent.bpmn.xml");
36 |
37 | BPMNDiagram diagram = builder.initializeBPMNDiagram();
38 |
39 | BPMNPlane plane = check(diagram);
40 | checkBpmnElement(plane, "Collaboration_1cajy2f");
41 | }
42 |
43 | @Test
44 | public void initializeBPMNDiagram_when_collaboration_not_exist_in_bpmn_file() {
45 | BPMNDiagramRichBuilder builder = newBuildFromBpmnFile("src/test/resources/bpmn/02-startEvent_task_endEvent-without-collaboration.bpmn.xml");
46 |
47 | BPMNDiagram diagram = builder.initializeBPMNDiagram();
48 |
49 | BPMNPlane plane = check(diagram);
50 | checkBpmnElement(plane, "process_1");
51 | }
52 |
53 | @Test
54 | public void build_should_initialize_BPMNDiagram() {
55 | BPMNDiagramRichBuilder builder = newBuildFromBpmnFile("src/test/resources/bpmn/A.2.0.bpmn.xml");
56 |
57 | TDefinitions definitions = builder.build();
58 |
59 | // TODO duplication with XmlParserTest + check method for id
60 | // Shapes
61 | List diagram = definitions.getBPMNDiagram();
62 | assertThat(diagram)
63 | .hasSize(1)
64 | .extracting(BPMNDiagram::getId).containsOnly("BPMNDiagram_1");
65 | BPMNPlane plane = diagram.get(0).getBPMNPlane();
66 | assertThat(plane.getId()).isEqualTo("BPMNPlane_1");
67 | }
68 |
69 | // =================================================================================================================
70 | // UTILS
71 | // =================================================================================================================
72 |
73 | // always set like this
74 | private static BPMNPlane check(BPMNDiagram bpmnDiagram) {
75 | assertThat(bpmnDiagram.getId()).isEqualTo("BPMNDiagram_1");
76 | BPMNPlane bpmnPlane = bpmnDiagram.getBPMNPlane();
77 | assertThat(bpmnPlane.getId()).isEqualTo("BPMNPlane_1");
78 | return bpmnPlane;
79 | }
80 |
81 | private static void checkBpmnElement(BPMNPlane plane, String expectedId) {
82 | QName bpmnElement = plane.getBpmnElement();
83 | assertThat(bpmnElement.getLocalPart()).isEqualTo(expectedId);
84 | assertThat(bpmnElement.getNamespaceURI()).isEmpty();
85 | assertThat(bpmnElement.getPrefix()).isEmpty();
86 | }
87 |
88 | private static BPMNDiagramRichBuilder newBuildFromBpmnFile(String bpmnFilePath) {
89 | return new BPMNDiagramRichBuilder(definitionsFromBpmnFile(bpmnFilePath));
90 | }
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/java/src/test/java/io/process/analytics/tools/bpmn/generator/internal/SemanticTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Bonitasoft S.A.
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | * Unless required by applicable law or agreed to in writing, software
8 | * distributed under the License is distributed on an "AS IS" BASIS,
9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | * See the License for the specific language governing permissions and
11 | * limitations under the License.
12 | */
13 | package io.process.analytics.tools.bpmn.generator.internal;
14 |
15 | import static io.process.analytics.tools.bpmn.generator.internal.BpmnInOut.defaultBpmnInOut;
16 | import static org.assertj.core.api.Assertions.assertThat;
17 | import static org.assertj.core.api.Assertions.tuple;
18 |
19 | import java.io.File;
20 |
21 | import io.process.analytics.tools.bpmn.generator.internal.generated.model.*;
22 | import org.junit.jupiter.api.Test;
23 |
24 | public class SemanticTest {
25 |
26 | @Test
27 | public void detect_collaboration_when_exist_in_bpmn_file() {
28 | Semantic semantic = semanticFromBpmnFile("src/test/resources/bpmn/01-startEvent.bpmn.xml");
29 | assertThat(semantic.getCollaboration())
30 | .get()
31 | .hasFieldOrPropertyWithValue("id", "Collaboration_1cajy2f");
32 | }
33 |
34 | @Test
35 | public void detect_collaboration_when_not_exist_in_bpmn_file() {
36 | Semantic semantic = semanticFromBpmnFile(
37 | "src/test/resources/bpmn/02-startEvent_task_endEvent-without-collaboration.bpmn.xml");
38 | assertThat(semantic.getCollaboration()).isEmpty();
39 | }
40 |
41 | @Test
42 | public void detect_processes_in_bpmn_file() {
43 | Semantic semantic = semanticFromBpmnFile("src/test/resources/bpmn/01-startEvent.bpmn.xml");
44 | assertThat(semantic.getProcesses())
45 | .hasSize(1)
46 | .extracting(TProcess::getId).containsExactly("Process_1duwsyj");
47 | }
48 |
49 | @Test
50 | public void detect_bpmn_elements_in_bpmn_file() {
51 | Semantic semantic = semanticFromBpmnFile(
52 | "src/test/resources/bpmn/02-startEvent_task_endEvent-without-collaboration.bpmn.xml");
53 | // we know that there is a process (see other tests)
54 | TProcess process = semantic.getProcesses().get(0);
55 |
56 | Semantic.BpmnElements bpmnElements = semantic.getBpmnElements(process);
57 |
58 | assertThat(bpmnElements.getFlowNodes())
59 | .extracting(Object::getClass, TFlowElement::getId)
60 | .containsOnly(tuple(TStartEvent.class, "startEvent_1"),
61 | tuple(TTask.class, "task_1"),
62 | tuple(TEndEvent.class, "endEvent_1"));
63 | assertThat(bpmnElements.getSequenceFlows())
64 | .extracting(Object::getClass, TFlowElement::getId)
65 | .containsOnly(tuple(TSequenceFlow.class, "sequenceFlow_1"),
66 | tuple(TSequenceFlow.class, "sequenceFlow_2"));
67 | }
68 |
69 | public static TDefinitions definitionsFromBpmnFile(String bpmnFilePath) {
70 | return defaultBpmnInOut().readFromBpmn(new File(bpmnFilePath));
71 | }
72 |
73 | private static Semantic semanticFromBpmnFile(String bpmnFilePath) {
74 | return new Semantic(definitionsFromBpmnFile(bpmnFilePath));
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/java/src/test/java/io/process/analytics/tools/bpmn/generator/internal/XmlParserTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Bonitasoft S.A.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.process.analytics.tools.bpmn.generator.internal;
17 |
18 | import static io.process.analytics.tools.bpmn.generator.internal.FileUtils.fileContent;
19 | import static org.assertj.core.api.Assertions.assertThat;
20 |
21 | import java.io.File;
22 | import java.io.IOException;
23 | import java.util.List;
24 |
25 | import javax.xml.bind.JAXBElement;
26 |
27 | import org.junit.jupiter.api.Test;
28 |
29 | import io.process.analytics.tools.bpmn.generator.internal.generated.model.*;
30 |
31 | public class XmlParserTest {
32 |
33 | private final XmlParser xmlParser = new XmlParser();
34 |
35 | @Test
36 | public void unmarshall() throws IOException {
37 | String bpmnAsXml = fileContent(new File("src/test/resources/bpmn/01-startEvent.bpmn.xml"));
38 |
39 | TDefinitions definitions = xmlParser.unmarshall(bpmnAsXml);
40 |
41 | // Semantic
42 | List> rootElement = definitions.getRootElement();
43 | assertThat(rootElement)
44 | .hasSize(2)
45 | .extracting(JAXBElement::getValue)
46 | .extracting(TRootElement::getClass)
47 | .extracting(Class::getName)
48 | .containsExactly(TCollaboration.class.getName(),TProcess.class.getName());
49 |
50 | // Shapes
51 | List diagram = definitions.getBPMNDiagram();
52 | assertThat(diagram)
53 | .hasSize(1)
54 | .extracting(BPMNDiagram::getId).containsOnly("BPMNDiagram_1");
55 | BPMNPlane plane = diagram.get(0).getBPMNPlane();
56 | assertThat(plane.getId()).isEqualTo("BPMNPlane_1");
57 | }
58 |
59 | }
--------------------------------------------------------------------------------
/java/src/test/java/io/process/analytics/tools/bpmn/generator/model/GridTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Bonitasoft S.A.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.process.analytics.tools.bpmn.generator.model;
17 |
18 | import static io.process.analytics.tools.bpmn.generator.model.Position.position;
19 | import static io.process.analytics.tools.bpmn.generator.model.Shape.shape;
20 | import static org.assertj.core.api.Assertions.assertThat;
21 |
22 | import org.junit.jupiter.api.Test;
23 |
24 | class GridTest {
25 |
26 | private final Grid grid = new Grid();
27 | private final Shape nodeA = shape("a");
28 | private final Shape nodeB = shape("b");
29 | private final Shape nodeC = shape("c");
30 |
31 | @Test
32 | public void should_move_element_when_adding_row_after() {
33 | grid.add(position(nodeA, 0, 0));
34 | grid.add(position(nodeB, 0, 1));
35 | grid.add(position(nodeC, 0, 2));
36 |
37 |
38 | grid.addRowAfter(1);
39 |
40 | assertThat(grid.getPositions()).containsExactly(
41 | position(nodeA, 0, 0),
42 | position(nodeB, 0, 1),
43 | position(nodeC, 0, 3)
44 | );
45 | }
46 | @Test
47 | public void should_move_element_when_adding_row_before() {
48 | grid.add(position(nodeA, 0, 0));
49 | grid.add(position(nodeB, 0, 1));
50 | grid.add(position(nodeC, 0, 2));
51 |
52 |
53 | grid.addRowBefore(1);
54 |
55 | assertThat(grid.getPositions()).containsExactly(
56 | position(nodeA, 0, 0),
57 | position(nodeB, 0, 2),
58 | position(nodeC, 0, 3)
59 | );
60 | }
61 |
62 | @Test
63 | public void should_not_move_element_when_adding_row_after_all_existing_elements() {
64 | grid.add(position(nodeA, 0, 0));
65 | grid.add(position(nodeB, 0, 1));
66 | grid.add(position(nodeC, 0, 2));
67 |
68 |
69 | grid.addRowAfter(2);
70 |
71 | assertThat(grid.getPositions()).containsExactly(
72 | position(nodeA, 0, 0),
73 | position(nodeB, 0, 1),
74 | position(nodeC, 0, 2)
75 | );
76 | }
77 |
78 | }
--------------------------------------------------------------------------------
/java/src/test/resources/bpmn/01-startEvent.bpmn.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Flow_1bic2fy
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/java/src/test/resources/bpmn/02-startEvent_task_endEvent-without-collaboration.bpmn.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | task_1
6 |
7 |
8 | startEvent_1
9 | endEvent_1
10 |
11 |
12 | task_1
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/java/src/test/resources/bpmn/waypoints-avoid-edge-overlap-01-single_branch.bpmn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/process-analytics/bpmn-layout-generators/6bea69c8bdd1936eca949eb2ad8f40dc2985d831/java/src/test/resources/bpmn/waypoints-avoid-edge-overlap-01-single_branch.bpmn.png
--------------------------------------------------------------------------------
/java/src/test/resources/bpmn/waypoints-avoid-edge-overlap-01-single_branch.bpmn.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Flow_1vicax8
6 |
7 |
8 | Flow_1vicax8
9 | Flow_0h6tbri
10 | Flow_0uof6cs
11 |
12 |
13 |
14 | Flow_0h6tbri
15 | Flow_1ayzxfr
16 |
17 |
18 |
19 | Flow_1ayzxfr
20 | Flow_1g2c8c6
21 |
22 |
23 |
24 | Flow_1g2c8c6
25 | Flow_0uof6cs
26 | Flow_1oneadm
27 |
28 |
29 |
30 |
31 | Flow_1oneadm
32 | Flow_10qs96y
33 |
34 |
35 |
36 | Flow_10qs96y
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/java/src/test/resources/bpmn/waypoints-avoid-edge-overlap-02-2nd-branch-with-large-height.bpmn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/process-analytics/bpmn-layout-generators/6bea69c8bdd1936eca949eb2ad8f40dc2985d831/java/src/test/resources/bpmn/waypoints-avoid-edge-overlap-02-2nd-branch-with-large-height.bpmn.png
--------------------------------------------------------------------------------
/java/src/test/resources/bpmn/waypoints-avoid-edge-overlap-03-elements_in_front.bpmn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/process-analytics/bpmn-layout-generators/6bea69c8bdd1936eca949eb2ad8f40dc2985d831/java/src/test/resources/bpmn/waypoints-avoid-edge-overlap-03-elements_in_front.bpmn.png
--------------------------------------------------------------------------------
/java/src/test/resources/bpmn/waypoints-avoid-edge-overlap-04-multiple_empty_paths.bpmn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/process-analytics/bpmn-layout-generators/6bea69c8bdd1936eca949eb2ad8f40dc2985d831/java/src/test/resources/bpmn/waypoints-avoid-edge-overlap-04-multiple_empty_paths.bpmn.png
--------------------------------------------------------------------------------
/java/src/test/resources/bpmn/waypoints-positions-cycle_01_simple.bpmn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/process-analytics/bpmn-layout-generators/6bea69c8bdd1936eca949eb2ad8f40dc2985d831/java/src/test/resources/bpmn/waypoints-positions-cycle_01_simple.bpmn.png
--------------------------------------------------------------------------------
/java/src/test/resources/bpmn/waypoints-positions-cycle_01_simple.bpmn.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Flow_103eu6e
6 |
7 |
8 | Flow_103eu6e
9 | Flow_0c5bz8z
10 | Flow_1rmk1d7
11 |
12 |
13 |
14 | Flow_1rmk1d7
15 | Flow_1699vu8
16 |
17 |
18 |
19 | Flow_1699vu8
20 | Flow_16flag6
21 | Flow_0f6ssax
22 |
23 |
24 |
25 | Flow_16flag6
26 |
27 |
28 |
29 | Flow_0w1nknb
30 | Flow_0c5bz8z
31 |
32 |
33 |
34 | Flow_0f6ssax
35 | Flow_0w1nknb
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/java/src/test/resources/bpmn/waypoints-positions-cycle_02_gateways_in_cycle.bpmn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/process-analytics/bpmn-layout-generators/6bea69c8bdd1936eca949eb2ad8f40dc2985d831/java/src/test/resources/bpmn/waypoints-positions-cycle_02_gateways_in_cycle.bpmn.png
--------------------------------------------------------------------------------
/java/src/test/resources/bpmn/waypoints-positions-gateways.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/process-analytics/bpmn-layout-generators/6bea69c8bdd1936eca949eb2ad8f40dc2985d831/java/src/test/resources/bpmn/waypoints-positions-gateways.png
--------------------------------------------------------------------------------
/java/src/test/resources/bpmn/waypoints-positions-gateways_split_join.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/process-analytics/bpmn-layout-generators/6bea69c8bdd1936eca949eb2ad8f40dc2985d831/java/src/test/resources/bpmn/waypoints-positions-gateways_split_join.png
--------------------------------------------------------------------------------
/java/src/test/resources/csv/PatientsProcess/edge.csv:
--------------------------------------------------------------------------------
1 | "","id","from","to"
2 | "1",1,2,7
3 | "2",2,3,1
4 | "3",3,3,6
5 | "4",4,4,1
6 | "5",5,5,1
7 | "6",6,5,4
8 | "7",7,6,5
9 | "8",8,7,8
10 | "9",9,8,1
11 | "10",10,8,3
12 | "11",11,8,9
13 | "12",12,9,1
14 | "13",13,9,5
15 |
--------------------------------------------------------------------------------
/java/src/test/resources/csv/PatientsProcess/edgeSimple.csv:
--------------------------------------------------------------------------------
1 | "","id","from","to"
2 | "1",1,2,3
3 | "2",2,3,1
4 |
--------------------------------------------------------------------------------
/java/src/test/resources/csv/PatientsProcess/gateway_edge_simple.csv:
--------------------------------------------------------------------------------
1 | "","id","from","to"
2 | "1",1,2,5
3 | "2",2,5,3
4 | "3",3,5,4
5 | "4",4,3,1
6 | "5",5,4,1
7 |
8 |
--------------------------------------------------------------------------------
/java/src/test/resources/csv/PatientsProcess/gateway_node_simple.csv:
--------------------------------------------------------------------------------
1 | "","id","label","type"
2 | "1",1,"End","end_event"
3 | "2",2,"Start","start_event"
4 | "3",3,"Task1","task"
5 | "4",4,"UserTask","user_task"
6 | "5",5,"Gateway1","gateway"
7 |
--------------------------------------------------------------------------------
/java/src/test/resources/csv/PatientsProcess/gateways_edge.csv:
--------------------------------------------------------------------------------
1 | "","id","from_id","to_id"
2 | "1",1,2,7
3 | "2",2,4,1
4 | "3",3,6,5
5 | "4",4,7,8
6 | "5",5,3,1003
7 | "6",6,5,1005
8 | "7",7,8,1008
9 | "8",8,9,1009
10 | "9",9,1003,1
11 | "10",10,1003,6
12 | "11",11,1005,1
13 | "12",12,1005,4
14 | "13",13,1008,1
15 | "14",14,1008,3
16 | "15",15,1008,9
17 | "16",16,1009,1
18 | "17",17,1009,5
--------------------------------------------------------------------------------
/java/src/test/resources/csv/PatientsProcess/gateways_node.csv:
--------------------------------------------------------------------------------
1 | "","from_id","node","type"
2 | "1",1,"ARTIFICIAL_END","task"
3 | "2",2,"ARTIFICIAL_START","task"
4 | "3",3,"Blood test","task"
5 | "4",4,"Check-out","task"
6 | "5",5,"Discuss Results","task"
7 | "6",6,"MRI SCAN","task"
8 | "7",7,"Registration","task"
9 | "8",8,"Triage and Assessment","task"
10 | "9",9,"X-Ray","task"
11 | "21",1003,"gateways1","gateway"
12 | "41",1005,"gateways2","gateway"
13 | "61",1008,"gateways3","gateway"
14 | "91",1009,"gateways4","gateway"
15 |
--------------------------------------------------------------------------------
/java/src/test/resources/csv/PatientsProcess/node.csv:
--------------------------------------------------------------------------------
1 | "","id","label","type"
2 | "1",1,"End","task"
3 | "2",2,"Start","task"
4 | "3",3,"Blood test 237","task"
5 | "4",4,"Check-out 492","task"
6 | "5",5,"Discuss Results 495","task"
7 | "6",6,"MRI SCAN 236","task"
8 | "7",7,"Registration 500","task"
9 | "8",8,"Triage and Assessment 500","task"
10 | "9",9,"X-Ray 261","task"
11 |
--------------------------------------------------------------------------------
/java/src/test/resources/csv/PatientsProcess/nodeSimple.csv:
--------------------------------------------------------------------------------
1 | "","id","label","type"
2 | "1",1,"End","task"
3 | "2",2,"Start","task"
4 | "3",3,"Blood test 237","task"
5 |
--------------------------------------------------------------------------------
/java/src/test/resources/csv/VacationRequestBonita/edges.csv:
--------------------------------------------------------------------------------
1 | "","id","from_id","to_id","value"
2 | "1",1,1,2004,52
3 | "2",2,3,9,53
4 | "3",3,7,2008,3
5 | "4",4,9,10,53
6 | "5",5,10,2014,53
7 | "6",6,11,6,53
8 | "7",7,12,3,53
9 | "8",8,13,2,53
10 | "9",9,15,7,3
11 | "10",10,2,1002,1
12 | "11",11,5,1005,2
13 | "12",12,6,1006,50
14 | "13",13,8,1008,1
15 | "14",14,14,1014,2
16 | "15",15,1002,1,52
17 | "16",16,1002,2004,1
18 | "17",17,1005,11,53
19 | "18",18,1005,2008,2
20 | "19",19,1005,2012,1
21 | "20",20,1006,2015,1
22 | "21",21,1006,2008,50
23 | "22",22,1006,2012,2
24 | "23",23,1008,2014,2
25 | "24",24,1008,2008,1
26 | "25",25,1014,2014,1
27 | "26",26,1014,2015,2
28 | "27",27,1014,13,53
29 | "28",28,2004,12,1
30 | "29",29,2008,14,50
31 | "30",30,2012,15,2
32 | "31",31,2014,4,53
33 | "32",32,2015,8,2
34 |
--------------------------------------------------------------------------------
/java/src/test/resources/csv/VacationRequestBonita/nodes.csv:
--------------------------------------------------------------------------------
1 | "","from_id","node","type","value"
2 | "1",1,"Add event on employee calendar","task",52
3 | "2",2,"after approval branch","task",53
4 | "3",3,"after approval join","task",53
5 | "4",4,"ARTIFICIAL_END","end_event",56
6 | "5",5,"ARTIFICIAL_START","start_event",56
7 | "6",6,"Deduct requested days from available days","task",53
8 | "7",7,"End Reminder","task",3
9 | "8",8,"end when request cancelled","task",3
10 | "9",9,"Gateway1","task",53
11 | "10",10,"New Vacation Request End","task",53
12 | "11",11,"New Vacation Request Start","task",53
13 | "12",12,"Notify employee request approved","task",53
14 | "13",13,"Request approved?","task",53
15 | "14",14,"Review request","task",56
16 | "15",15,"Send reminder","task",3
17 | "16",1002,"gateway1","gateway",53
18 | "17",1005,"gateway2","gateway",56
19 | "18",1006,"gateway3","gateway",53
20 | "19",1008,"gateway4","gateway",3
21 | "20",1014,"gateway5","gateway",56
22 | "21",2004,"gateways_merge_1","gateway",56
23 | "22",2008,"gateways_merge_2","gateway",3
24 | "23",2012,"gateways_merge_3","gateway",53
25 | "24",2014,"gateways_merge_4","gateway",56
26 | "25",2015,"gateways_merge_5","gateway",3
27 |
--------------------------------------------------------------------------------
/java/src/test/resources/csv/VacationRequestBonita_v2/edges.csv:
--------------------------------------------------------------------------------
1 | "","id","from_id","to_id","value"
2 | "1",1,1,2009,52
3 | "2",2,5,2010,3
4 | "3",3,7,2002,53
5 | "4",4,8,4,53
6 | "5",5,9,7,53
7 | "6",6,11,5,3
8 | "7",7,3,1003,56
9 | "8",8,4,1004,53
10 | "9",9,6,1006,3
11 | "10",10,10,1010,56
12 | "11",11,1003,8,53
13 | "12",12,1003,2010,2
14 | "13",13,1003,2011,1
15 | "14",14,1004,2006,1
16 | "15",15,1004,2010,50
17 | "16",16,1004,2011,2
18 | "17",17,1006,2002,2
19 | "18",18,1006,2010,1
20 | "19",19,1010,1,52
21 | "20",20,1010,2002,1
22 | "21",21,1010,2006,2
23 | "22",22,1010,2009,1
24 | "23",23,2002,2,56
25 | "24",24,2006,6,3
26 | "25",25,2009,9,53
27 | "26",26,2010,10,56
28 | "27",27,2011,11,3
29 |
--------------------------------------------------------------------------------
/java/src/test/resources/csv/VacationRequestBonita_v2/nodes.csv:
--------------------------------------------------------------------------------
1 | "","from_id","node","type","value"
2 | "1",1,"Add event on employee calendar","task",52
3 | "2",2,"ARTIFICIAL_END","end_event",56
4 | "3",3,"ARTIFICIAL_START","start_event",56
5 | "4",4,"Deduct requested days from available days","task",53
6 | "5",5,"End Reminder","task",3
7 | "6",6,"end when request cancelled","task",3
8 | "7",7,"New Vacation Request End","task",53
9 | "8",8,"New Vacation Request Start","task",53
10 | "9",9,"Notify employee request approved","task",53
11 | "10",10,"Review request","task",56
12 | "11",11,"Send reminder","task",3
13 | "12",1003,"gateway1","gateway",56
14 | "13",1004,"gateway2","gateway",53
15 | "14",1006,"gateway3","gateway",3
16 | "15",1010,"gateway4","gateway",56
17 | "16",2002,"gateways_merge_1","gateway",56
18 | "17",2006,"gateways_merge_2","gateway",3
19 | "18",2009,"gateways_merge_3","gateway",53
20 | "19",2010,"gateways_merge_4","gateway",56
21 | "20",2011,"gateways_merge_5","gateway",3
22 |
--------------------------------------------------------------------------------
/java/src/test/resources/log4j2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------