{"id":27,"date":"2017-04-30T10:45:36","date_gmt":"2017-04-30T10:45:36","guid":{"rendered":"http:\/\/canchito-dev.com\/public\/blog\/?p=27"},"modified":"2021-05-02T13:49:53","modified_gmt":"2021-05-02T13:49:53","slug":"integrate-activiti-bpm-with-spring","status":"publish","type":"post","link":"http:\/\/www.canchito-dev.com\/public\/blog\/2017\/04\/30\/integrate-activiti-bpm-with-spring\/","title":{"rendered":"Integrate Activiti BPM with Spring"},"content":{"rendered":"<p style=\"text-align: justify;\"><div class=\"perfect-pullquote vcard pullquote-align-full pullquote-border-placement-left\" style=\"font-size:14px !important;\"><blockquote><p style=\"font-size:14px !important;\">In this post, you will learn how to integrate Activiti&#8217;s engine and REST API into your Spring application. At the same time, you will be able to adapt the Process Engine to your needs by modifying the database connection and the Async Job Executor.<\/p><\/blockquote><\/div><\/p>\n<div>\n  <a class=\"donate-with-crypto\"\n     href=\"https:\/\/commerce.coinbase.com\/checkout\/faf64f90-2e80-46ee-aeba-0fde14cbeb46\"><br \/>\n    Buy Me a Coffee<br \/>\n  <\/a><br \/>\n  <script src=\"https:\/\/commerce.coinbase.com\/v1\/checkout.js?version=201807\">\n  <\/script>\n<\/div>\n\n<h1 style=\"text-align: justify;\">Contribute Code<\/h1>\n<p style=\"text-align: justify;\">If you would like to become an active contributor to this project please follow these simple steps:<\/p>\n<ol>\n<li style=\"list-style-type: none;\">\n<ol>\n<li style=\"text-align: justify;\">Fork it<\/li>\n<li style=\"text-align: justify;\">Create your feature branch<\/li>\n<li style=\"text-align: justify;\">Commit your changes<\/li>\n<li style=\"text-align: justify;\">Push to the branch<\/li>\n<li style=\"text-align: justify;\">Create new Pull Request<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<p class=\"sect1\"><strong>Source code<\/strong> can be downloaded from <a href=\"https:\/\/github.com\/canchito-dev\/integrate-activiti-with-spring\" target=\"_blank\" rel=\"noopener noreferrer\">github<\/a>.<\/p>\n<h1 class=\"sect1\">What you\u2019ll need<\/h1>\n<ul>\n<li>About 20 minutes<\/li>\n<li>A favorite IDE<\/li>\n<li><a href=\"http:\/\/www.oracle.com\/technetwork\/java\/javase\/downloads\/index.html\" target=\"_blank\" rel=\"noopener noreferrer\">JDK 7<\/a>\u00a0or later.\u00a0It can be made to work with JDK6, but it will need configuration tweaks. Please check the Spring Boot documentation<\/li>\n<li>An empty Spring project. You can follow the steps from <a href=\"http:\/\/canchito-dev.com\/public\/blog\/2017\/04\/16\/spring-initializer\/\" target=\"_blank\" rel=\"noopener noreferrer\">here<\/a>.<\/li>\n<\/ul>\n<h1>Introduction<\/h1>\n<p style=\"text-align: justify;\"><a href=\"https:\/\/www.activiti.org\/\" target=\"_blank\" rel=\"noopener noreferrer\">Activiti<\/a> is an open source, light-weight process definition driven and Business Process Management engine. As you will see, it is easy to integrate with any Java technology or project.<\/p>\n<p style=\"text-align: justify;\">A process definition\u00a0is a\u00a0typical workflow made up of individual boxes called tasks, which specify what action needs to be performed. It is visualized as a flow-chart-like diagram based on the BPMN 2.0 standard. Thanks to BPMN, business can now understand their business\u00a0 procedures in a graphical notation.<\/p>\n<p style=\"text-align: justify;\">Activiti&#8217;s source code can be downloaded from <a href=\"https:\/\/github.com\/Activiti\/Activiti\" target=\"_blank\" rel=\"noopener noreferrer\">github<\/a>.\u00a0The project was founded and is sponsored by <a href=\"https:\/\/www.alfresco.com\/\" target=\"_blank\" rel=\"noopener noreferrer\">Alfresco<\/a>\u00a0and distributed under the Apache license, but enjoys contributions from all across the globe and industries.<\/p>\n<h1>Spring Boot Integration<\/h1>\n<p style=\"text-align: justify;\">Integrating Activiti&#8217;s engine into a Spring microservice is quite easy. Basically, you just need to add the needed dependencies and a database. Within minutes, you can have a production-ready service up and running with the capability to orchestrate human workflows to achieve a certain goal.<\/p>\n<h1>Getting Started<\/h1>\n<p style=\"text-align: justify;\">Once you have created an empty project and imported into your favorite IDE, it is time to modify the <code>pom.xml<\/code> file. If you have not created the project yet, you can follow the steps described in <a href=\"http:\/\/canchito-dev.com\/public\/blog\/2017\/04\/16\/spring-initializer\/\" target=\"_blank\" rel=\"noopener noreferrer\">here<\/a>.<\/p>\n<p style=\"text-align: justify;\">Let&#8217;s open the <code>pom.xml<\/code> file,\u00a0and add the dependencies needed to get Spring Boot, Activiti and a database. We\u2019ll use an H2 in memory database to keep things simple.<\/p>\n<p style=\"text-align: justify;\">First we add the version of Activiti that we will be using as a property. Notice that we will use the latest current version 5.22.0.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xml\" data-enlighter-theme=\"classic\">&lt;properties&gt;\r\n  &lt;project.build.sourceEncoding&gt;UTF-8&lt;\/project.build.sourceEncoding&gt;\r\n  &lt;project.reporting.outputEncoding&gt;UTF-8&lt;\/project.reporting.outputEncoding&gt;\r\n  &lt;java.version&gt;1.8&lt;\/java.version&gt;\r\n  &lt;activiti.version&gt;5.22.0&lt;\/activiti.version&gt;\r\n&lt;\/properties&gt;<\/pre>\n<p style=\"text-align: justify;\">Next, we add two dependencies. But do not remove the previously added ones.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xml\" data-enlighter-theme=\"classic\">&lt;dependencies&gt;\t\t\r\n  &lt;!-- Activiti BPM workflow engine --&gt;\r\n  &lt;dependency&gt;&lt;!-- Activiti Spring Boot Starter Basic --&gt;\r\n    &lt;groupId&gt;org.activiti&lt;\/groupId&gt;\r\n    &lt;artifactId&gt;activiti-spring-boot-starter-basic&lt;\/artifactId&gt;\r\n    &lt;version&gt;${activiti.version}&lt;\/version&gt;\r\n  &lt;\/dependency&gt;&lt;!-- Activiti Spring Boot Starter Basic --&gt;\r\n  \r\n  &lt;dependency&gt;\r\n    &lt;groupId&gt;com.h2database&lt;\/groupId&gt;\r\n    &lt;artifactId&gt;h2&lt;\/artifactId&gt;\r\n    &lt;scope&gt;runtime&lt;\/scope&gt;\r\n  &lt;\/dependency&gt;\r\n&lt;\/dependencies&gt;<\/pre>\n<p style=\"text-align: justify;\">That&#8217;s it. Yuo have successfully included Activiti into your project. Now let&#8217;s give it a test run. Wait a minute! When you try to execute the project, it fails! How come you ask?! This is the error you are seeing:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-theme=\"enlighter\" data-enlighter-linenumbers=\"false\">Error starting ApplicationContext. To display the auto-configuration report re-run your application with 'debug' enabled.\r\n2017-04-16 22:08:23.599 ERROR 10308 --- [           main] o.s.boot.SpringApplication               : Application startup failed\r\n\r\norg.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springProcessEngineConfiguration' defined in class path resource [org\/activiti\/spring\/boot\/DataSourceProcessEngineAutoConfiguration$DataSourceProcessEngineConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.activiti.spring.SpringProcessEngineConfiguration]: Factory method 'springProcessEngineConfiguration' threw exception; nested exception is java.io.FileNotFoundException: class path resource [processes\/] cannot be resolved to URL because it does not exist\r\n  at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599) ~[spring-beans-4.3.7.RELEASE.jar:4.3.7.RELEASE]\r\n  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1173) ~[spring-beans-4.3.7.RELEASE.jar:4.3.7.RELEASE]\r\n  ...\r\n  ...\r\n  ...\r\nCaused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.activiti.spring.SpringProcessEngineConfiguration]: Factory method 'springProcessEngineConfiguration' threw exception; nested exception is java.io.FileNotFoundException: class path resource [processes\/] cannot be resolved to URL because it does not exist\r\n  at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189) ~[spring-beans-4.3.7.RELEASE.jar:4.3.7.RELEASE]\r\n  at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588) ~[spring-beans-4.3.7.RELEASE.jar:4.3.7.RELEASE]\r\n  ... 17 common frames omitted\r\nCaused by: java.io.FileNotFoundException: class path resource [processes\/] cannot be resolved to URL because it does not exist\r\n  at org.springframework.core.io.ClassPathResource.getURL(ClassPathResource.java:187) ~[spring-core-4.3.7.RELEASE.jar:4.3.7.RELEASE]\r\n  at org.springframework.core.io.support.PathMatchingResourcePatternResolver.findPathMatchingResources(PathMatchingResourcePatternResolver.java:463) ~[spring-core-4.3.7.RELEASE.jar:4.3.7.RELEASE]\r\n  at org.springframework.core.io.support.PathMatchingResourcePatternResolver.getResources(PathMatchingResourcePatternResolver.java:292) ~[spring-core-4.3.7.RELEASE.jar:4.3.7.RELEASE]\r\n\r\n  ...\r\n  ...\r\n  ...<\/pre>\n<p style=\"text-align: justify;\">There is a nice feature that is enabled when Activiti is integrated with Spring. This feature automatically deploys process definitions found under <code>classpath:process\/<\/code>, every time the process engine is created. However, since Activiti&#8217;s version <em>5.19.0.2<\/em>, if there are no process definitions in that folder, the process engine cannot be started. Give it a shot, change Activiti&#8217;s version to<em> 5.19.0<\/em> and try to start it. We will change the version to <em>5.19.0<\/em> for now, and later own we will add \u00a0process definition and test version <em>5.22.0<\/em> again.<\/p>\n<p style=\"text-align: justify;\">You could already run this application using version <em>5.19.0<\/em>. However,\u00a0it won\u2019t do anything functionally but behind the scenes it already:<\/p>\n<ul>\n<li style=\"text-align: justify;\">Created an in-memory H2 database<\/li>\n<li style=\"text-align: justify;\">Created an Activiti process engine using that database<\/li>\n<li style=\"text-align: justify;\">Exposed all Activiti services as Spring Beans<\/li>\n<li style=\"text-align: justify;\">Configured the Activiti async job executor, mail server, etc.<\/li>\n<\/ul>\n<h1>Adding REST Support<\/h1>\n<p style=\"text-align: justify;\">Until now, we have embedded the Activiti&#8217;s engine into our application. But sometimes we need to we able to allow machine to machine communication (M2M). One way of doing this is by exchanging information via REST messages. So let&#8217;s add the following dependencies to our project:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xml\" data-enlighter-theme=\"classic\">&lt;dependency&gt;&lt;!-- Activiti Spring Boot Starter Rest Api --&gt;\r\n  &lt;groupId&gt;org.activiti&lt;\/groupId&gt;\r\n  &lt;artifactId&gt;activiti-spring-boot-starter-rest-api&lt;\/artifactId&gt;\r\n  &lt;version&gt;${activiti.version}&lt;\/version&gt;\r\n&lt;\/dependency&gt;&lt;!-- Activiti Spring Boot Starter Rest Api --&gt;<\/pre>\n<p style=\"text-align: justify;\">This dependency\u00a0takes the Activiti REST API (which is written in Spring MVC) and exposes this fully in our application. For a more detail information about the REST API, please visit <a href=\"https:\/\/www.activiti.org\/userguide\/index.html\" target=\"_blank\" rel=\"noopener noreferrer\">Activiti&#8217;s user guide<\/a>.<\/p>\n<p style=\"text-align: justify;\">At this point, if you run the application, you will see all the REST endpoints exposed. However, if you try to do a request, you will get an 401 &#8211; Unauthorized response. This is because all REST-resources require a valid Activiti-user to be authenticated by default, but none is automatically created when including the REST API dependency. So, let&#8217;s add a valid user to our application, by copying and pasting the below code into our main class.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"classic\">@Bean\r\nInitializingBean usersAndGroupsInitializer(final IdentityService identityService) {\r\n\r\n    return new InitializingBean() {\r\n        public void afterPropertiesSet() throws Exception {\r\n\r\n            Group group = identityService.newGroup(\"user\");\r\n            group.setName(\"users\");\r\n            group.setType(\"security-role\");\r\n            identityService.saveGroup(group);\r\n\r\n            User admin = identityService.newUser(\"admin\");\r\n            admin.setPassword(\"admin\");\r\n            identityService.saveUser(admin);\r\n\r\n        }\r\n    };\r\n}<\/pre>\n<p style=\"text-align: justify;\">This code snippet does two things:<\/p>\n<ol>\n<li style=\"text-align: justify;\">It creates the group called <em>users<\/em>, and sets it type to <em>security-role<\/em>.<\/li>\n<li style=\"text-align: justify;\">It add a user called <em>admin<\/em> to the previously created group with the password <em>admin<\/em>.<\/li>\n<\/ol>\n<p style=\"text-align: justify;\">Now, do the request again, but remember to include the <em>Basic Authentication<\/em> in you header, specifying the username and password that was just created. Remember not to include the above code in your production ready application. You do not want to add a back door!<\/p>\n<h1 style=\"text-align: justify;\">Changing the Data Source<\/h1>\n<p style=\"text-align: justify;\"><em><strong>NOTE:<\/strong> In this section, we will be creating a property class called\u00a0<code>ActivitiDataSourceProperties<\/code>. Nevertheless, its usage will not be obvious until further in the post, once we reach the section Overriding The <code>SpringProcessEngineConfiguration<\/code> Bean.<\/em><\/p>\n<p style=\"text-align: justify;\">An in-memory database like H2 is good for a testing environment. But once you move the application to a production ready environment, you will probably will be using other type of database like MySQL or Oracle.<\/p>\n<p style=\"text-align: justify;\">To change the database that Activiti must use, simple override\u00a0the default by providing a data source bean. To do this, we will perform two steps:<\/p>\n<ul style=\"text-align: justify;\">\n<li style=\"text-align: justify;\">Modify the data source properties in the <code>application.properties<\/code> file found in the <code>classpath<\/code>.<\/li>\n<li style=\"text-align: justify;\">Create a data source bean, which will override the default one.<\/li>\n<\/ul>\n<p style=\"text-align: justify;\">Start by opening the <code>application.properties<\/code> file found in the <code>classpath<\/code> and add the following properties. Do not worry, it is probable that the file is completely empty. As these properties are managed by the <code>DataSourceProperties<\/code> class, Spring enables an auto-complete feature.<\/p>\n<ul>\n<li style=\"text-align: justify;\"><strong>spring.datasource.driver-class-name:<\/strong> Fully qualified name of the JDBC driver. Auto-detected based on the URL by default.<\/li>\n<li style=\"text-align: justify;\"><strong>spring.datasource.password:<\/strong> Login password of the database.<\/li>\n<li style=\"text-align: justify;\"><strong>spring.datasource.url:<\/strong> JDBC url of the database.<\/li>\n<li style=\"text-align: justify;\"><strong>spring.datasource.username:<\/strong> Login username of the database.<\/li>\n<\/ul>\n<p style=\"text-align: justify;\">By adding this properties, we will be overriding the default values found in Spring&#8217;s <code>DataSourceProperties<\/code> class.<\/p>\n<p style=\"text-align: justify;\">Second, we need to override the default bean. We can create the new bean in the file where the main function is, for example. Copy and paste the following code:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"classic\">  @Autowired\r\n  private DataSourceProperties properties;\r\n  \r\n  @Bean(name = \"datasource.activiti\")\r\n  public DataSource activitiDataSource() {\r\n    return DataSourceBuilder.create(this.properties.getClassLoader())\r\n        .url(this.properties.getUrl())\r\n        .username(this.properties.getUsername())\r\n        .password(this.properties.getPassword())\r\n        .driverClassName(this.properties.getDriverClassName())\r\n            .build();\r\n  }<\/pre>\n<p style=\"text-align: justify;\">By autowiring the <code>DataSourceProperties<\/code>, Spring automatically will read the <code>application.properties<\/code> file and assigns the values that it finds within the file. In other words, it will look for properties which start with <em>&#8220;spring.datasource&#8221;<\/em> and that at the same time it finds a matching getter.<\/p>\n<p style=\"text-align: justify;\">Since we are using a properties class, we need to add an additional dependency:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xml\" data-enlighter-theme=\"classic\">&lt;dependency&gt;\r\n  &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\r\n  &lt;artifactId&gt;spring-boot-configuration-processor&lt;\/artifactId&gt;\r\n  &lt;optional&gt;true&lt;\/optional&gt;\r\n&lt;\/dependency&gt;<\/pre>\n<p style=\"text-align: justify;\">Here, we are using the Spring&#8217;s helper class <code>DataSourceBuilder<\/code>, which is a convenience class for building a data source\u00a0with common implementations and\u00a0properties.<\/p>\n<p style=\"text-align: justify;\">The data source that is constructed based on the default provided JDBC properties will have the default <a href=\"http:\/\/www.mybatis.org\/\" target=\"_blank\" rel=\"noopener noreferrer\">MyBatis<\/a> connection pool settings. The following attributes can optionally be set to tweak that connection pool (taken from the <a href=\"http:\/\/www.mybatis.org\/\" target=\"_blank\" rel=\"noopener noreferrer\">MyBatis<\/a> documentation):<\/p>\n<ul>\n<li style=\"text-align: justify;\"><strong>jdbcMaxActiveConnections<\/strong>: The number of active connections that the connection pool at maximum at any time can contain. Default is 10.<\/li>\n<li style=\"text-align: justify;\"><strong>jdbcMaxIdleConnections<\/strong>: The number of idle connections that the connection pool at maximum at any time can contain.<\/li>\n<li style=\"text-align: justify;\"><strong>jdbcMaxCheckoutTime<\/strong>: The amount of time in milliseconds a connection can be checked out from the connection pool before it is forcefully returned. Default is 20000 (20 seconds).<\/li>\n<li style=\"text-align: justify;\"><strong>jdbcMaxWaitTime<\/strong>: This is a low level setting that gives the pool a chance to print a log status and re-attempt the acquisition of a connection in the case that it is taking unusually long (to avoid failing silently forever if the pool is misconfigured) Default is 20000 (20 seconds).<\/li>\n<\/ul>\n<p style=\"text-align: justify;\">By default, these four properties are not exposed in the <code>ActivitiProperties<\/code> class, and that is why, you do not see them in the <code>application.properties<\/code> files. So, we will create our own properties class which will have getters and setters for these four properties.<\/p>\n<p style=\"text-align: justify;\">Create a package where are newly property classes will reside. I will called it <code>com.canchitodev.example.configuration.properties<\/code>. And inside, create a class which name will be <code>ActivitiDataSourceProperties<\/code>. Once you have all these, copy and paste the below code. Remember that the getters and setters are removed for simplicity.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"classic\">package com.canchitodev.example.configuration.properties;\r\n\r\nimport org.springframework.boot.context.properties.ConfigurationProperties;\r\n\r\n@ConfigurationProperties(prefix=\"activiti.datasource\")\r\npublic class ActivitiDataSourceProperties {\r\n  \r\n  private String url;\r\n  private String username;\r\n  private String password;\r\n  private String driverClassName;\r\n  private Integer jdbcMaxWaitTime=20000;\r\n  private Integer jdbcMaxCheckoutTime=20000;\r\n  private Integer jdbcMaxIdleConnections=10;\r\n  private Integer jdbcMaxActiveConnections=10;\r\n  private Boolean dbEnableEventLogging=true;\r\n  \r\n  \/\/ Getters and setters are removed for simplicity\r\n  @Override\r\n  public String toString() {\r\n    return \"ActivitiDataSourceProperties [url=\" + url + \", username=\" + username + \", password=\" + password\r\n        + \", driverClassName=\" + driverClassName + \", jdbcMaxWaitTime=\" + jdbcMaxWaitTime\r\n        + \", jdbcMaxCheckoutTime=\" + jdbcMaxCheckoutTime + \", jdbcMaxIdleConnections=\" + jdbcMaxIdleConnections\r\n        + \", jdbcMaxActiveConnections=\" + jdbcMaxActiveConnections + \", dbEnableEventLogging=\"\r\n        + dbEnableEventLogging + \"]\";\r\n  }\r\n}<\/pre>\n<p style=\"text-align: justify;\">The annotation\u00a0<code>@ConfigurationProperties(prefix=\"activiti.datasource\")<\/code> tells Spring that the\u00a0class <code>ActivitiDataSourceProperties<\/code>\u00a0will be a place holder for properties, and which properties are to be mapped to all those properties found in the <code>application.properties<\/code> file that start with <em>&#8220;activiti.datasource&#8221;<\/em>. As a result, Spring will set the value of the properties:<\/p>\n<ul>\n<li><strong>activiti.datasource.url:<\/strong>\u00a0JDBC URL of the database.<\/li>\n<li><strong>activiti.datasource.username:<\/strong>\u00a0Username to connect to the database.<\/li>\n<li><strong>activiti.datasource.password:<\/strong>\u00a0Password to connect to the database.<\/li>\n<li><strong>activiti.datasource.driver-class-name:<\/strong>\u00a0Implementation of the driver for the specific database type.<\/li>\n<li><strong>activiti.datasource.jdbc-max-wait-time:<\/strong>\u00a0This is a low level setting that gives the pool a chance to print a log status and re-attempt the acquisition of a connection in the case that it is taking unusually long (to avoid failing silently forever if the pool is misconfigured) Default is 20000 (20 seconds).<\/li>\n<li><strong>activiti.datasource.jdbc-max-checkout-time:<\/strong>\u00a0The amount of time in milliseconds a connection can be checked out from the connection pool before it is forcefully returned. Default is 20000 (20 seconds).<\/li>\n<li><strong>activiti.datasource.jdbc-max-idle-connections:<\/strong>\u00a0The number of idle connections that the connection pool at maximum at any time can contain.<\/li>\n<li><strong>activiti.datasource.jdbc-max-active-connections:<\/strong>\u00a0The number of active connections that the connection pool at maximum at any time can contain. Default is 10.<\/li>\n<\/ul>\n<p style=\"text-align: justify;\">The first 4 will not be used at the moment, but the rest can be copied into the <code>application.properties<\/code> file and assigned a value.<\/p>\n<p style=\"text-align: justify;\"><em><strong>NOTE<\/strong>: If you would like to learn more about properties, I recommend reading the post &#8220;<a href=\"https:\/\/spring.io\/blog\/2013\/10\/30\/empowering-your-apps-with-spring-boot-s-property-support\" target=\"_blank\" rel=\"noopener noreferrer\">Empowering your apps with Spring Boot&#8217;s property support<\/a>&#8221; by <a href=\"https:\/\/spring.io\/team\/gturnquist\" target=\"_blank\" rel=\"noopener noreferrer\">Greg Turnquist<\/a>.<\/em><\/p>\n<h1 style=\"text-align: justify;\">Configuring The Async Job Executor<\/h1>\n<p style=\"text-align: justify;\"><em><strong>NOTE:<\/strong> In this section, we will be creating a property class called ActivitiAsycExecutorProperties. Nevertheless, its usage will not be obvious until further in the post, once we reach the section Overriding The <code>SpringProcessEngineConfiguration<\/code> Bean.<\/em><\/p>\n<p style=\"text-align: justify;\">Since version 5.17, Activiti offers two ways for it to execute the jobs. The first one is the Job Executor which is a component that manages a couple of threads to fire timers and also asynchronous messages. By default, it is still used and activated when the process engine starts, but we will be disabling it. If you would like to read more about it, please refer to the advance section of <a href=\"https:\/\/www.activiti.org\/userguide\/index.html#_job_executor_design\" target=\"_blank\" rel=\"noopener noreferrer\">Activiti&#8217;s user guide<\/a>.<\/p>\n<p style=\"text-align: justify;\">The second one is the Async Job Executor.\u00a0The Async executor is a component that manages a thread pool to fire timers and other asynchronous tasks. Moreover it is a more performance and more database friendly way of executing asynchronous jobs in the Activiti Engine. It\u2019s therefore recommended to switch to the Async executor.\u00a0By default, the it\u00a0is not enabled.<\/p>\n<p style=\"text-align: justify;\"><strong>IMPORTANT:<\/strong> Only one executor can be enabled, as they both executors deal with timers and asynchronous jobs in the Activiti Engine.<\/p>\n<p style=\"text-align: justify;\">Activiti recommends using the Async Job Executor due to the following advantages:<\/p>\n<ul>\n<li style=\"text-align: justify;\">Less database queries because asynchronous jobs are executed without polling the database<\/li>\n<li style=\"text-align: justify;\">For non-exclusive jobs there\u2019s no chance to run into OptimisticLockingExceptions anymore<\/li>\n<li>\n<p style=\"text-align: justify;\">Exclusive jobs are now locked at process instance level instead of the cumbersome logic of queuing exclusive jobs in the Job Executor<\/p>\n<\/li>\n<\/ul>\n<p style=\"text-align: justify;\">The Async Job Executor can be configured to meet your needs:<\/p>\n<ul>\n<li style=\"text-align: justify;\"><strong>corePoolSize:<\/strong> The minimal number of threads that are kept alive in the thread pool for job execution. Default value is 2.<\/li>\n<li style=\"text-align: justify;\"><strong>maxPoolSize:<\/strong> The maximum number of threads that are kept alive in the thread pool for job execution. Default value is 10.<\/li>\n<li style=\"text-align: justify;\"><strong>keepAliveTime:<\/strong> The time (in milliseconds) a thread used for job execution must be kept alive before it is destroyed. Default setting is 0. Having a non-default setting of 0 takes resources, but in the case of many job executions it avoids creating new threads all the time. Default value is 5000.<\/li>\n<li style=\"text-align: justify;\"><strong>queueSize:<\/strong> The size of the queue on which jobs to be executed are placed. Default value is 100.<\/li>\n<li style=\"text-align: justify;\"><strong>maxTimerJobsPerAcquisition:<\/strong> The number of timer jobs that are fetched from the database in one query. Default value is 1.<\/li>\n<li style=\"text-align: justify;\"><strong>maxAsyncJobsDuePerAcquisition:<\/strong> The number of asynchronous jobs due that are fetched from the database in one query. Default value is 1.<\/li>\n<li style=\"text-align: justify;\"><strong>defaultAsyncJobAcquireWaitTimeInMillis:<\/strong> The time in milliseconds between asynchronous job due queries being executed. Default value is 10000.<\/li>\n<li style=\"text-align: justify;\"><strong>defaultTimerJobAcquireWaitTimeInMillis:<\/strong> The time in milliseconds between timer job queries being executed. Default value is 10000.<\/li>\n<li style=\"text-align: justify;\"><strong>timerLockTimeInMillis:<\/strong> The time in milliseconds that a timer job is locked before being retried again. The Activiti Engine considers the timer job to have failed after this period of time and will retry. Default value is 300000.<\/li>\n<li style=\"text-align: justify;\"><strong>asyncJobLockTimeInMillis:<\/strong> The time in milliseconds that an asynchronous job is locked before being retried again. The Activiti Engine considers the asynchronous job to have failed after this period of time and will retry. Default value is 300000.<\/li>\n<\/ul>\n<p style=\"text-align: justify;\">Inside the package <code>com.canchitodev.example.configuration.properties<\/code>, create a class which name will be <code>ActivitiAsynExecutorProperties<\/code>. Once you have all these, copy and paste the below code. Remember that the getters and setters are removed for simplicity.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"classic\">package com.canchitodev.example.configuration.properties;\r\n\r\nimport org.springframework.boot.context.properties.ConfigurationProperties;\r\n\r\n@ConfigurationProperties(prefix=\"activiti.async-executor\")\r\npublic class ActivitiAsycExecutorProperties {\r\n  \r\n  private Integer corePoolSize=2;\r\n  private Integer maxPoolSize=10;\r\n  private Integer keepAliveTime=5000;\r\n  private Integer queueSize=100;\r\n  private Integer maxTimerJobsPerAcquisition=1;\r\n  private Integer maxAsyncJobsDuePerAcquisition=1;\r\n  private Integer defaultAsyncJobAcquireWaitTimeInMillis=10000;\r\n  private Integer defaultTimerJobAcquireWaitTimeInMillis=10000;\r\n  private Integer timerLockTimeInMillis=300000;\r\n  private Integer asyncJobLockTimeInMillis=300000;\r\n  \r\n  \/\/ Getters and setters are removed for simplicity\r\n  \r\n  @Override\r\n  public String toString() {\r\n    return \"ActivitiAsycExecutorProperties [corePoolSize=\" + corePoolSize + \", maxPoolSize=\" + maxPoolSize\r\n        + \", keepAliveTime=\" + keepAliveTime + \", queueSize=\" + queueSize + \", maxTimerJobsPerAcquisition=\"\r\n        + maxTimerJobsPerAcquisition + \", maxAsyncJobsDuePerAcquisition=\" + maxAsyncJobsDuePerAcquisition\r\n        + \", defaultAsyncJobAcquireWaitTimeInMillis=\" + defaultAsyncJobAcquireWaitTimeInMillis\r\n        + \", defaultTimerJobAcquireWaitTimeInMillis=\" + defaultTimerJobAcquireWaitTimeInMillis\r\n        + \", timerLockTimeInMillis=\" + timerLockTimeInMillis + \", asyncJobLockTimeInMillis=\"\r\n        + asyncJobLockTimeInMillis + \"]\";\r\n  }\r\n}<\/pre>\n<p style=\"text-align: justify;\">The annotation\u00a0<code>@ConfigurationProperties(prefix=\"activiti.async-executor\")<\/code> tells Spring that the\u00a0class <code>ActivitiAsynExecutorProperties<\/code>\u00a0will be a place holder for properties, and which properties are to be mapped to all those properties found in the <code>application.properties<\/code> file that start with <em>&#8220;activiti.async-executor&#8221;<\/em>.<\/p>\n<p style=\"text-align: justify;\"><strong>NOTE<\/strong>: If you would like to learn more about properties, I recommend reading the post <em>&#8220;<a href=\"https:\/\/spring.io\/blog\/2013\/10\/30\/empowering-your-apps-with-spring-boot-s-property-support\" target=\"_blank\" rel=\"noopener noreferrer\">Empowering your apps with Spring Boot&#8217;s property support<\/a>&#8220;<\/em> by <a href=\"https:\/\/spring.io\/team\/gturnquist\" target=\"_blank\" rel=\"noopener noreferrer\">Greg Turnquist<\/a>.<\/p>\n<h1 style=\"text-align: justify;\">Overriding the <code>SpringProcessEngineConfiguration<\/code> Bean<\/h1>\n<p style=\"text-align: justify;\">Now that we have created all the properties that we need, we can now proceed to modifying Activiti&#8217;s process engine. For simplicity, we will be doing all these modifications on the class where the main function is. In my case, the class\u00a0<code>IntegrateActivitiWithSpringApplication<\/code> found in package\u00a0<code>com.canchitodev.example<\/code> is where the main method is found.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"classic\">@SpringBootApplication\r\n@EnableConfigurationProperties(value={ActivitiAsycExecutorProperties.class, ActivitiDataSourceProperties.class})\r\npublic class IntegrateActivitiWithSpringApplication {\r\n  \r\n  @Autowired\r\n  private DataSourceProperties dataSourceproperties;\r\n  \r\n  @Autowired\r\n  private ActivitiAsycExecutorProperties activitiAsycExecutorProperties;\r\n  \r\n  @Autowired\r\n  private ActivitiDataSourceProperties activitiDataSourceProperties;\r\n\r\n  public static void main(String[] args) {\r\n    SpringApplication.run(IntegrateActivitiWithSpringApplication.class, args);\r\n  }\r\n  ...\r\n  ...\r\n  ...<\/pre>\n<p style=\"text-align: justify;\">\u00a0This fragment of code from the class <code>IntegrateActivitiWithSpringApplication<\/code> shows a couple of key components:<\/p>\n<ul>\n<li style=\"text-align: justify;\"><code>@EnableConfigurationProperties<\/code> leverages <code>ActivitiAsyncExecutorProperties<\/code> and <code>ActivitiDataSourceProperties<\/code>\u00a0as a source of properties and makes them available to the entire class.<\/li>\n<li style=\"text-align: justify;\">We are autowiring\u00a0<code>ActivitiAsyncExecutorProperties<\/code>\u00a0and\u00a0<code>ActivitiDataSourceProperties<\/code>\u00a0so that an instance of them is automatically created.<\/li>\n<\/ul>\n<p>Further below, we will add the function which will modify the process engine configuration using the properties that we created in section <em>Changing the Data Source<\/em> and <em>Changing the Async job Executor<\/em>.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"classic\">...\r\n...\r\n@Bean\r\npublic BeanPostProcessor activitiSpringProcessEngineConfigurer() {\r\n    return new BeanPostProcessor() {\r\n\r\n        @Override\r\n        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {\r\n            if (bean instanceof SpringProcessEngineConfiguration) {\r\n            \t\/\/ If it is the SpringProcessEngineConfiguration, we want to add or modify some configuration.\r\n                  SpringProcessEngineConfiguration config = (SpringProcessEngineConfiguration) bean;\r\n                  \r\n                  \/\/ Database\r\n                  config.setJdbcMaxActiveConnections(activitiDataSourceProperties.getJdbcMaxActiveConnections());\r\n                  config.setJdbcMaxIdleConnections(activitiDataSourceProperties.getJdbcMaxIdleConnections());\r\n                  config.setJdbcMaxCheckoutTime(activitiDataSourceProperties.getJdbcMaxCheckoutTime());\r\n                  config.setJdbcMaxWaitTime(activitiDataSourceProperties.getJdbcMaxWaitTime());\r\n                  config.setEnableDatabaseEventLogging(activitiDataSourceProperties.getDbEnableEventLogging());\r\n                  \r\n                  \/\/ Async Job Executor\r\n                  DefaultAsyncJobExecutor asyncExecutor = new DefaultAsyncJobExecutor();\r\n                  asyncExecutor.setAsyncJobLockTimeInMillis(activitiAsycExecutorProperties.getAsyncJobLockTimeInMillis());\r\n                  asyncExecutor.setCorePoolSize(activitiAsycExecutorProperties.getCorePoolSize());\r\n                  asyncExecutor.setDefaultAsyncJobAcquireWaitTimeInMillis(activitiAsycExecutorProperties.getDefaultAsyncJobAcquireWaitTimeInMillis());\r\n                  asyncExecutor.setDefaultTimerJobAcquireWaitTimeInMillis(activitiAsycExecutorProperties.getDefaultTimerJobAcquireWaitTimeInMillis());\r\n                  asyncExecutor.setKeepAliveTime(activitiAsycExecutorProperties.getKeepAliveTime());\r\n                  asyncExecutor.setMaxAsyncJobsDuePerAcquisition(activitiAsycExecutorProperties.getMaxAsyncJobsDuePerAcquisition());\r\n                  asyncExecutor.setMaxPoolSize(activitiAsycExecutorProperties.getMaxPoolSize());\r\n                  asyncExecutor.setMaxTimerJobsPerAcquisition(activitiAsycExecutorProperties.getMaxTimerJobsPerAcquisition());\r\n                  asyncExecutor.setQueueSize(activitiAsycExecutorProperties.getQueueSize());\r\n                  asyncExecutor.setTimerLockTimeInMillis(activitiAsycExecutorProperties.getTimerLockTimeInMillis());\r\n                  config.setAsyncExecutor(asyncExecutor);\r\n            }\r\n            return bean;\r\n        }\r\n\r\n        @Override\r\n        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\r\n            return bean;\r\n        }           \r\n    };\r\n}\r\n...\r\n...<\/pre>\n<p style=\"text-align: justify;\">Finally, open the <code>application.properties<\/code> file and add the following properties:<\/p>\n<ul style=\"text-align: justify;\">\n<li style=\"text-align: justify;\"><strong>spring.activiti.async-executor-activate:<\/strong> Instructs the Activiti Engine to startup the Async Executor thread pool at startup. Can be true (activate) of false (suspend)<\/li>\n<li style=\"text-align: justify;\"><strong>spring.activiti.async-executor-enabled:<\/strong> Enables the Async executor instead of the old Job executor. Can be true (enable) of false (disable)<\/li>\n<li style=\"text-align: justify;\"><strong>spring.activiti.check-process-definitions:<\/strong> Whether to automatically deploy resources. Can be true (deploy) of false (not deploy)<\/li>\n<li style=\"text-align: justify;\"><strong>spring.activiti.history-level:<\/strong> Following history levels can be configured:\n<ul>\n<li style=\"text-align: justify;\"><em>none:<\/em> skips all history archiving. This is the most performant for runtime process execution, but no historical information will be available<\/li>\n<li style=\"text-align: justify;\"><em>activity:<\/em> archives all process instances and activity instances. At the end of the process instance, the latest values of the top level process instance variables will be copied to historic variable instances. No details will be archived<\/li>\n<li style=\"text-align: justify;\"><em>audit:<\/em> This is the default. It archives all process instances, activity instances, keeps variable values continuously in sync and all form properties that are submitted so that all user interaction through forms is traceable and can be audited<\/li>\n<li style=\"text-align: justify;\"><em>full:<\/em> This is the highest level of history archiving and hence the slowest. This level stores all information as in the audit level plus all other possible details, mostly this are process variable updates<\/li>\n<\/ul>\n<\/li>\n<li style=\"text-align: justify;\"><strong>spring.activiti.job-executor-activate:<\/strong> Instructs the Activiti Engine to startup the Job Executor. Can be true (activate) of false (suspend)<\/li>\n<\/ul>\n<p style=\"text-align: justify;\">By setting the property <strong>spring.activiti.check-process-definitions<\/strong>\u00a0to false, we can now change back to Activiti&#8217;s version <em>5.22<\/em> without getting an error when running our application, as we have instructed Activiti not to deploy the resources automatically.<\/p>\n\n<h1 style=\"text-align: justify;\">Summary<\/h1>\n<p style=\"text-align: justify;\">In this post, you will learned:<\/p>\n<ul>\n<li style=\"text-align: justify;\">How to integrate Activiti&#8217;s engine and REST API into your Spring application.<\/li>\n<li style=\"text-align: justify;\">Use Activiti with an in-memory H2 database and\/or with other databases.<\/li>\n<li style=\"text-align: justify;\">Create configuration property classes, which were used for modifying Activiti&#8217;s data source and Async Job Executor behavior.<\/li>\n<li style=\"text-align: justify;\">Configured Activiti&#8217;s process engine to fit your needs.<\/li>\n<\/ul>\n<p style=\"text-align: justify;\">Hope you enjoyed this post as much as I did writing it. Please leave your comments and feedback.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this post, you will learn how to integrate Activiti&#8217;s engine and REST API into your Spring application. At the same time, you will be able to adapt the Process Engine to your needs by modifying the database connection and the Async Job Executor.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_exactmetrics_skip_tracking":false,"_exactmetrics_sitenote_active":false,"_exactmetrics_sitenote_note":"","_exactmetrics_sitenote_category":0,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[4,15,3],"tags":[9,18,20,19,10,11,5],"class_list":["post-27","post","type-post","status-publish","format-standard","hentry","category-activiti-bpm","category-rest","category-spring","tag-actitivi","tag-bpm","tag-bpmn","tag-business-process-management","tag-open-source","tag-rest","tag-spring"],"aioseo_notices":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p8EwXo-r","jetpack-related-posts":[{"id":471,"url":"http:\/\/www.canchito-dev.com\/public\/blog\/2020\/06\/27\/flowable-custom-engine-configuration\/","url_meta":{"origin":27,"position":0},"title":"Customizing Flowable Engine","author":"canchitodev","date":"June 27, 2020","format":false,"excerpt":"In this article, we will go into detail on how to customize Flowable's engine. Three changes to the engine will be done: (1) Change the database connection by modifying the data source and adding custom data source properties. (2)Use a strong UUID generator. (3)Implement a custom event handler.","rel":"","context":"In &quot;BPM&quot;","block_context":{"text":"BPM","link":"http:\/\/www.canchito-dev.com\/public\/blog\/category\/bpm\/"},"img":{"alt_text":"CANCHITO-DEV: Spring Initializr","src":"https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr-1024x674.png?resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr-1024x674.png?resize=350%2C200 1x, https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr-1024x674.png?resize=525%2C300 1.5x"},"classes":[]},{"id":477,"url":"http:\/\/www.canchito-dev.com\/public\/blog\/2020\/06\/27\/use-flowable-apps-with-a-custom-rest-api\/","url_meta":{"origin":27,"position":1},"title":"Use Flowable Apps with a Custom REST API","author":"canchitodev","date":"June 27, 2020","format":false,"excerpt":"In this post, you will learn how configure Flowable's apps to use your custom Spring Boot REST API as a backend engine. All this, in a dockerized environment.","rel":"","context":"In &quot;BPM&quot;","block_context":{"text":"BPM","link":"http:\/\/www.canchito-dev.com\/public\/blog\/category\/bpm\/"},"img":{"alt_text":"CANCHITO-DEV: Process engine deployments in Flowable Admin","src":"https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/process-engine-deployments.png?resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/process-engine-deployments.png?resize=350%2C200 1x, https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/process-engine-deployments.png?resize=525%2C300 1.5x, https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/process-engine-deployments.png?resize=700%2C400 2x, https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/process-engine-deployments.png?resize=1050%2C600 3x"},"classes":[]},{"id":372,"url":"http:\/\/www.canchito-dev.com\/public\/blog\/2020\/06\/07\/create-custom-service-tasks-for-flowable\/","url_meta":{"origin":27,"position":2},"title":"Create Custom Service Tasks for Flowable","author":"canchitodev","date":"June 7, 2020","format":false,"excerpt":"In\u00a0this\u00a0tutorial,\u00a0we\u00a0will\u00a0be\u00a0implementing\u00a0a\u00a0custom\u00a0service\u00a0task\u00a0in\u00a0Flowable\u00a0","rel":"","context":"In &quot;BPM&quot;","block_context":{"text":"BPM","link":"http:\/\/www.canchito-dev.com\/public\/blog\/category\/bpm\/"},"img":{"alt_text":"CANCHITO-DEV: Spring Initializr","src":"https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr.png?resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr.png?resize=350%2C200 1x, https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr.png?resize=525%2C300 1.5x, https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr.png?resize=700%2C400 2x, https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr.png?resize=1050%2C600 3x, https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/initializr.png?resize=1400%2C800 4x"},"classes":[]},{"id":370,"url":"http:\/\/www.canchito-dev.com\/public\/blog\/2020\/05\/12\/integrate-flowable-into-your-spring-boot-application\/","url_meta":{"origin":27,"position":3},"title":"Integrate Flowable into your Spring Boot Application","author":"canchitodev","date":"May 12, 2020","format":false,"excerpt":"In\u00a0this\u00a0tutorial,\u00a0we\u00a0will\u00a0be\u00a0integrating\u00a0Flowable's\u00a0BPM\u00a0engine\u00a0into\u00a0our\u00a0Spring\u00a0Boot\u00a0application.","rel":"","context":"In &quot;BPM&quot;","block_context":{"text":"BPM","link":"http:\/\/www.canchito-dev.com\/public\/blog\/category\/bpm\/"},"img":{"alt_text":"CANCHITO-DEV: Flowable Test Start Process","src":"https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/start_process.png?resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/start_process.png?resize=350%2C200 1x, https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/start_process.png?resize=525%2C300 1.5x, https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/start_process.png?resize=700%2C400 2x, https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/start_process.png?resize=1050%2C600 3x, https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/start_process.png?resize=1400%2C800 4x"},"classes":[]},{"id":356,"url":"http:\/\/www.canchito-dev.com\/public\/blog\/2019\/07\/05\/run-flowable-bpm-using-docker-and-mysql\/","url_meta":{"origin":27,"position":4},"title":"Run Flowable BPM using Docker and MySQL","author":"canchitodev","date":"July 5, 2019","format":false,"excerpt":"In this article, you will learn how to compile Flowable source code using MySQL as database source, and generate valid Docker images. Once you have the images, we will use Docker Compose for defining and running a multi-container Docker applications.","rel":"","context":"In &quot;BPM&quot;","block_context":{"text":"BPM","link":"http:\/\/www.canchito-dev.com\/public\/blog\/category\/bpm\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":322,"url":"http:\/\/www.canchito-dev.com\/public\/blog\/2018\/09\/09\/canchito-workflow-manager-cwm\/","url_meta":{"origin":27,"position":5},"title":"Canchito Workflow Manager (CWM)","author":"canchitodev","date":"September 9, 2018","format":false,"excerpt":"Flowable BPM turned into a workflow manager with features such as file transfer via FTP and Samba, integration with Amazon Web Service, file transcodification and analysis using FFmpeg and MediaInfo, and more..","rel":"","context":"In &quot;BPM&quot;","block_context":{"text":"BPM","link":"http:\/\/www.canchito-dev.com\/public\/blog\/category\/bpm\/"},"img":{"alt_text":"CANCHITO-DEV: Task Queue Service","src":"https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2018\/09\/canchito_dev_task_queue_service.png?resize=350%2C200","width":350,"height":200},"classes":[]}],"jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"http:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/posts\/27","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/comments?post=27"}],"version-history":[{"count":30,"href":"http:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/posts\/27\/revisions"}],"predecessor-version":[{"id":553,"href":"http:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/posts\/27\/revisions\/553"}],"wp:attachment":[{"href":"http:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/media?parent=27"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/categories?post=27"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/tags?post=27"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}