How to use custom beans in Flowable-rest 6.3.1

Hi

I’m trying to setup flowable-rest and would like to change the Spring bean configuration to add my own beans (the end goal is to implement a custom async history listener, but first I want to load properties from some external file).
In activiti I provided a activiti-custom-context.xml file to do this, but it seems that starting from flowable 6.3.1 this option is removed due to the migration to spring boot (https://github.com/flowable/flowable-engine/commit/ad5416d8085dbcd0baaeeace5fe64b6aa255ba8d#diff-e9e0a70cd7afdffcb9a8917b97ead3de).
I guess the documentation is not 100% up-to-date: https://docs.flowable.org/docs/userguide/index.html#_configuration_2 since it still refers to the flowable-custom-context.xml file?
I also read about the flowable.cfg.xml file and I tried configuring my beans in there.

I’m using the following configuration:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:jee="http://www.springframework.org/schema/jee" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
       http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <bean id="dbProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>file:/etc/flowable.conf</value>
            </list>
        </property>
        <property name="ignoreUnresolvablePlaceholders" value="true" />
        <property name="ignoreResourceNotFound" value="true" />
    </bean>

    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
        <property name="driverClass" value="${jdbc.driver}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="fasdasdfasfd"/>
        <property name="password" value="${jdbc.password}" />
    </bean>

    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <bean id="processEngineConfiguration" class="org.flowable.spring.SpringProcessEngineConfiguration">
        <property name="dataSource" ref="dataSource" />
        <property name="transactionManager" ref="transactionManager" />
        <property name="databaseSchemaUpdate" value="true" />
        <property name="mailServerHost" value="${smtp.host}" />
        <property name="mailServerPort" value="${smtp.port}" />
        <property name="jobExecutorActivate" value="false" />
        <property name="asyncExecutorEnabled" value="true" />
        <property name="asyncExecutorActivate" value="true" />
        <property name="enableDatabaseEventLogging" value="true" />
        <property name="history" value="audit" />
    </bean>

	<bean id="processEngine" class="org.flowable.spring.ProcessEngineFactoryBean">
	  <property name="processEngineConfiguration" ref="processEngineConfiguration" />
	</bean>

</beans>

I’m using flowable by extending the provided war using this maven config:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.flowable</groupId>
  <artifactId>flowable-rest</artifactId>
  <packaging>war</packaging>
  <version>0.1.0</version>
  <name>flowable</name>
  <properties>
	<maven.compiler.source>1.8</maven.compiler.source>
	<maven.compiler.target>1.8</maven.compiler.target>
	<flowableVersion>6.3.1</flowableVersion>
  </properties>
  <dependencies>
	<dependency>
	  <groupId>junit</groupId>
	  <artifactId>junit</artifactId>
	  <version>3.8.1</version>
	  <scope>test</scope>
	</dependency>
	<dependency>
	  <groupId>org.flowable</groupId>
	  <artifactId>flowable-engine</artifactId>
	  <version>${flowableVersion}</version>
	  <exclusions>
		<!-- The org.flowable:flowable-app-rest war already ships a different version of spring, which causes exception on some platforms (but not all...) -->
        <exclusion>
			<groupId>org.springframework</groupId>
          <artifactId>spring-core</artifactId>
        </exclusion>
      </exclusions>
	</dependency>
	<dependency>
	  <groupId>org.flowable</groupId>
	  <artifactId>flowable-app-rest</artifactId>
	  <version>${flowableVersion}</version>
	  <type>war</type>
	  <scope>runtime</scope>
	</dependency>
  </dependencies>
  <build>
	<plugins>
	  <plugin>
		<groupId>org.apache.maven.plugins</groupId>
		<artifactId>maven-war-plugin</artifactId>
		<version>3.2.2</version>
		<configuration>
		  <overlays>
			<overlay>
			  <groupId>org.flowable</groupId>
			  <artifactId>flowable-app-rest</artifactId>
			</overlay>
		  </overlays>
		  <failOnMissingWebXml>false</failOnMissingWebXml>
		</configuration>
	  </plugin>
	</plugins>
  </build>
</project>

So, my question is what file replaces the flowable-custom-context.xml file? Or is there a better way to add custom beans?

Thanks in advance!

Since 6.3.0 the Flowable Applications (flowable-rest) as well are based on Spring Boot 2.0. So in order to add your beans easiest would be have your own jar with Spring Boot auto configuration.

In that autoconfiguration you can provide a bean of type EngineConfigurationConfigurer<SpringProcessEngineConfiguration> and provide your customizations. Have a look at the ProcessEngineAutoConfiguration.

In theory you can also provide your own bean of SpringProcessEngineConfiguration

1 Like

Thanks for you reply, it worked.

I created a file src/main/java/org/flowable/spring/boot/ProcessEngineAutoConfiguration.java which contains:

package org.flowable.spring.boot;

import javax.sql.DataSource;
import java.util.Properties;
import java.io.FileInputStream;
import java.io.InputStream;
import org.flowable.engine.ProcessEngine;
import org.flowable.job.service.impl.asyncexecutor.AsyncExecutor;
import org.flowable.spring.ProcessEngineFactoryBean;
import org.flowable.spring.SpringProcessEngineConfiguration;
import org.flowable.spring.boot.app.AppEngineAutoConfiguration;
import org.flowable.spring.boot.app.AppEngineServicesAutoConfiguration;
import org.flowable.spring.boot.condition.ConditionalOnProcessEngine;
import org.flowable.spring.boot.process.ProcessAsync;
import org.flowable.spring.boot.process.ProcessAsyncHistory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.transaction.PlatformTransactionManager;

@Configuration
@ConditionalOnProcessEngine
@AutoConfigureAfter({
        FlowableTransactionAutoConfiguration.class,
        AppEngineAutoConfiguration.class,
})
@AutoConfigureBefore({
        AppEngineServicesAutoConfiguration.class,
        EndpointAutoConfiguration.class
})
@Import({
        FlowableJobConfiguration.class
})
public class ProcessEngineAutoConfiguration extends AbstractSpringEngineAutoConfiguration {

    public ProcessEngineAutoConfiguration() {
        super(new FlowableProperties());
    }

    @Bean
    @ConditionalOnMissingBean
    public SpringProcessEngineConfiguration springProcessEngineConfiguration(DataSource dataSource, PlatformTransactionManager platformTransactionManager,
                                                                             @ProcessAsync ObjectProvider<AsyncExecutor> asyncExecutorProvider,
                                                                             @ProcessAsyncHistory ObjectProvider<AsyncExecutor> asyncHistoryExecutorProvider) throws Exception {

        SpringProcessEngineConfiguration conf = new SpringProcessEngineConfiguration();


        Properties prop = new Properties();
        InputStream input = input = new FileInputStream("/etc/flowable.properties");
        prop.load(input);

        conf.setJdbcDriver(prop.getProperty("jdbc.driver"));
        conf.setJdbcUsername(prop.getProperty("jdbc.username"));
        conf.setJdbcPassword(prop.getProperty("jdbc.password"));
        conf.setJdbcUrl(prop.getProperty("jdbc.url"));
        conf.setMailServerHost(prop.getProperty("smtp.host"));
        conf.setMailServerPort(Integer.parseInt(prop.getProperty("smtp.port")));

        conf.setDatabaseSchemaUpdate("true");

        configureSpringEngine(conf, platformTransactionManager);
        return conf;
    }

    @Configuration
    @ConditionalOnBean(type = {
        "org.flowable.app.spring.SpringAppEngineConfiguration"
    })
    public static class ProcessEngineAppConfiguration extends BaseEngineConfigurationWithConfigurers<SpringProcessEngineConfiguration> {
        @Bean
        public ProcessEngine processEngine(SpringProcessEngineConfiguration configuration) throws Exception {
            ProcessEngineFactoryBean processEngineFactoryBean = new ProcessEngineFactoryBean();
            processEngineFactoryBean.setProcessEngineConfiguration(configuration);

            invokeConfigurers(configuration);

            return processEngineFactoryBean.getObject();
        }
    }
}

Without using the processEngine bean I kept getting exceptions about uninitialized engines, but this works fine. Of course I’m interested if there is anything I can do better :slight_smile:.

@LEDfan what you are doing now is overriding the Flowable ProcessEngineAutoConfiguration. I would try to avoid this.

Why do you need to override it? Is it to provide your own /etc/flowable.properties? Do you know that you can configure all the properties that you are doing right now through the Spring Boot externalised configuration?

All Flowable specific properties can be found here in the Flowable documentation.

For you those would be:

flowable.mail.server.host
flowable.mail.server.port
flowable.database-schema-update

The default for flowable.database-schema-update is already true.

As for the JDBC properties you can use the Spring Boot properties prefixed with spring.datasource. For you those would be:

spring.datasource.driver-class-name
spring.datasource.username
spring.datasource.password
spring.datasource.url

From your initial question I understood that you want to define your own custom beans. So if you just implement EngineConfigurationConfigurer<SpringProcessEngineConfiguration> it should work.

You can do something like:

@Configuration
@AutoConfigureAfter(ProcessEngineAutoConfiguration.class)
public class MyCustomAutoConfiguration {

    @Bean 
    public EngineConfigurationConfigurer<SpringProcessEngineConfiguration> customProcessEngineConfigurer() {
        return configuration -> {
            // do your own thing with the beans and configurations.
            // In theory you can even apply your custom loading of properties here. However, I highly suggest to use the Spring Boot Externalized Configuration
        };
    }
}

Cheers,
Filip

1 Like