Activiti BPMN notions
BPM (Business Process Management)
- Lifecycle stages:
- Design - by analyst and managers -> BPMN graph
- Model - developers and sysadmins -> add logic
- Execute - on a machine - get results
- Monitor - check the data from the machine
- Optimize - improve and go back to model
graph LR; A(start); B[order pizza]; C[bake pizza]; D[eat pizza]; E(finish) A --> B; B --> C; C --> D; D --> E;
Alfresco Activiti
Open source workflow in Java
- engine
- database
- REST API
- Spring framework (JPA, CDI, LDAP, JMX)
Process overview
All this can be called by REST
graph LR; A[Model xml]; B[Process definition structure]; C[Process instance]; A --> |Deploy in Activiti| B B --> |Triggers and user actionsi| C
Designing a model (xml)
Elements
- Start events
- Boundary events
- Intermediate events
- End events
- Subprocess (normal line box)
- Event subprocess (not continuous line box)
- Call activiti (bold line box): may create new instance -> external call
- Tasks (work units)
- Gateways
- Sequence flow
Events
- Blank: API call
- Timer (clock)
- Message (postcardl) : local
- *Signal (triangle):global
- Cancel (cross)
- Error (lightning): in error no case, not an exception, the right idea is to catch the exception and launch this event
Tasks
- User task (you can specif the user role)
- Service task (my Java code, call SOAP)
- Script task (launch a script, js or groovy, internal logic)
- There are also BusinessRuleTask, ReceiveTask, ManualTask, MailTask, CamelTask, MuleTask
Gateways
- Exclusive (EX-OR, only one line on split, only waits for one)
- Parallel (AND, several lines on split, waits for everyone to finish)
- Inclusive (EX-AND, wait to continue)
- Event-based - generates new process instance
Sequence flow
- Normal
- Default (crossed arrow)
- Message flow (discontinuous)
- Pools and lanes (e.g. vendor, client) -> to optimize
Best practices
- Unique names
- Avoid crossing flows
- Modularize models
- Naming conventions (verb + object)
- Use comments
- Avoid deadlocks and multimerges
- Split flow with gateways
- Avoid split and join at the same point
- Avoid splitting tasks after events: get the result first
- Void ecursive subprocess (beware infinite loops)
- Consistent usage of Start and En events (only one start point)
❗ Note: an actor may have several roles (e.g. amazon has a picker and a packager in its storage place, but the same person can pick and package). Hence you can have a pool with 2 lanes.
Comunication with Activiti
- Go to activiti backend and extend (bad!)
- Use REST (good)
REST
- Model
- Deployments
- Process definition
- Process instances
- Executions
- Tasks
- Froms
- History
- DB Tables
- Jobs
- Users and groups
⚠️ Add\service
as a prefix to every REST call on the Activiti guide, and use camel case names for ids, so it’s directly mapped to Java.
The Activiti database
Tables:
- ACT_AVT: events
- ACT_GE_XXX: binaries, don’t touch
- ACT_HI_XXX: history (read only, or that’s supposed. Don’t touch!!)
- ACT_ID_XXX: users and groups
- ACT_RU_XXX: runtime
- IDENTITY_LINK: task X is assigned by user Y
- EVENT_SUBSCR: event subscriber, listeners: task X will be done in 60 minutes
- EXECUTION: be carefull with joins.
- JOB: planned tasks (QuartzScheduler will execute a task) -> Quartz’s queue
- TASK: they are timed
- ACT_PROCDEF_INFO: the xml model parsed is stored here
⚠️ Don’t modify the schema! Upgrades can be horrible.
* Set associations in a different database.
* Be careful to be consistent.
* Activiti should be the master (don’t overwrite it with the associated DB data)
UIs
Activiti explorer
It’s heavy on PROD. You only deploy this on demand. You usually connect to the database.UI elements
- Query
- DB
- Deployments: be carefull as it does “waterfall deletions”: delete a deployemnt and you’ll phisically destroy everything
Process
- Instances (check active instances)
- Process definitions (models) -> tenant: similar to environment, but you can only use it with REST
- Model workspace : you can edit and deploy from here
⚠️ Tenants can only be modified via REST API by adding an input form and changing the value for “script”
⚠️ Use this app only for queries and very carefully, it’s easy to end in accidental cleansing fire.
⚠️ Activiti usually doens’t send back an answer after put (maybe 204). You should do a get after that.
⚠️ Error code 409 notifies conlicts (e.g. problems with concurrency and exclusion -> someone else already did that, so you can remove it from your cache)Eclipse
- It’s a plugin: Activiti BPMN Designer Update Site, you
- Connects to code
- Sets up tests
Camunda
- Big models
Properties
- engine properties
data 1
2
3
4# demo data
cretate.demo.users = true
cretate.demo.definitions = true
cretate.demo.models report = true - db.properties: don’t forget about the connector
1
2
3
4
5jdbc.type = mysql
jdbc.driver = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/activiti?autoReconnect=true
username = root
password = - log4j.properties
1
2
3
4
5
6log4j.rootLogger=INFO, CA
# ConsoleAppender
log4j.appender.CA=org.apache.log4j.ConsoleAppender
log4j.appender.CA.layout=org.apache.log4j.PatternLayout
log4j.appender.CA.layout.ConversionPattern= %d{hh:mm:ss,SSS} [%t] %-5p %c %x - %m%n
Methodology
3 options:
set up your_code inside Activiti -> set your code in the lib activiti in the war, mainly for REST
- Fast: activiti provides
- You set up your models in the jar or a external zip
- Easier versioning
set up Activiti inside your_code -> create your own endpoints (horrible idea)
- Modifier Activiti itself, and overwrites it (the horror!!)
- you set it up “the hardcore way”, you are overwriting it
Use Activiti as a library -> reuse DB instances, your own models
- Set is as a dependency
- You extend it
Install on eclipse
- Get 2 wars (activiti-explorer and activit-rest)
- Copy them in a Tomcat (webapps folder)
- Deploy tomcat so it creates the projects
- Compile your project on eclipse (Activiti project, clean install)
- Copy:
- lib: copy jars in both projects
- classes: copy properties in both projects
Implementation of the Java code
1 | public class ClientRest implements JavaDelegate or extends BaseEntityEventListener{ |