Database connection from a TaskListener

Hello all!

Is there any way to obtain a database connection from a TaskListener instance (flowable 6.2)?

You can get the current connection via an internal class: org.flowable.engine.impl.util.CommandContextUtil.getDbSqlSession()…getSqlSession().getConnection()

However, that is very low-level … what’s the use case you’re trying to solve?

Good evening, Joram!

Thank you for your answer! You answer is exactly I’ve looked for.
And I’m sorry for delay with my answer.

I suppose write some aditional information each time after some human-task have been executed.

I’m trying to imagine where a listener should obtain a database connection from.
It’s seems logical for me that I can obtain connection from the same source as the engine.
Your example code doesn’t seems too low-level for me but, in such case, only embarrassing me thing is transaction management.

I don’t know what is a right approach in this context.
Should I use third-party (in sense independence from the Flowable core classes) connection prowider may be?

I think you could also use a custom mapping with other tables created in flowable schema.

http://www.flowable.org/docs/userguide-5/index.html#advanced.custom.sql.queries

Hi!

This is a example:

Create new table in your flowable schema:

CREATE TABLE `per_salary` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(45) DEFAULT NULL,
  `pay` float DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id_UNIQUE` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8

And add some rows…

Create a custom mapper connection: custom-mybatis-mappers-flowable.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="processEngineConfiguration"
    class="org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration">

    <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/flowableTest" />
    <property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
    <property name="jdbcUsername" value="example" />
    <property name="jdbcPassword" value="example" />

    <!-- job executor configurations -->
    <property name="asyncExecutorActivate" value="false" />
    
    <property name="databaseSchemaUpdate" value="true" />
    
    <!-- The custom mybatis mappers -->
    <property name="customMybatisMappers">
        <set>
            <value>com.fegor.flowable.test.mapper.MyTestMapper</value>
        </set>
    </property>
  </bean>
</beans>

Create your mapper: customSalaryMapper.xml

<?xml version="1.0" encoding="UTF-8" ?> 

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.fegor.flowable.SalaryMapper">
 
  <resultMap id="customSalaryResultMap" type="com.fegor.flowable.mapper.Salary">
    <id property="id" column="ID" jdbcType="INTEGER"/>
    <result property="name" column="NAME" jdbcType="VARCHAR"/>
    <result property="pay" column="PAY" jdbcType="FLOAT"/>
  </resultMap>

  <sql id="selectCustomSalaryColumns">
		PER.ID, PER.NAME, PER.PAY
	</sql>
	
	<select id="selectCustomSalaryList" parameterType="string" resultMap="customSalaryResultMap">
		select <include refid="selectCustomSalaryColumns"/> from PER_SALARY PER
	</select>
</mapper>

Create a entity: Salary.java

package com.fegor.flowable.mapper;

public class Salary {

	protected int id;
	protected String name;
	protected float pay;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public float getPay() {
		return pay;
	}
	public void setPay(float pay) {
		this.pay = pay;
	}
}

Create file for test mapper: MyTestMapper.java

package com.fegor.flowable.test.mapper;

import java.util.List;
import java.util.Map;

import org.apache.ibatis.annotations.Select;

public interface MyTestMapper {
    @Select("SELECT ID as id, NAME as name, PAY as pay FROM PER_SALARY")
    List<Map<String, Object>> selectSalaries();
}

And create your test file: MapperSalaryTest.java

package com.fegor.flowable.test.mapper;

import java.util.List;
import java.util.Map;

import org.flowable.engine.common.impl.cmd.CustomSqlExecution;
import org.flowable.engine.impl.cmd.AbstractCustomSqlExecution;
import org.flowable.engine.impl.test.ResourceFlowableTestCase;

public class MapperSalaryTest extends ResourceFlowableTestCase {

    public MapperSalaryTest() {
        super("/custom-mybatis-mappers-flowable.cfg.xml");
    }

    public void testSelectSalaryColumns() {
        CustomSqlExecution<MyTestMapper, List<Map<String, Object>>> customSqlExecution = new AbstractCustomSqlExecution<MyTestMapper, List<Map<String, Object>>>(MyTestMapper.class) {

        	public List<Map<String, Object>> execute(MyTestMapper customMapper) {
                return customMapper.selectSalaries();
            }
        };

        List<Map<String, Object>> salaries = managementService.executeCustomSql(customSqlExecution);
        assertEquals(5, salaries.size());
        
        for (int i = 0; i < salaries.size(); i++) {
            Map<String, Object> salary = salaries.get(i);
            assertNotNull(salary.get("id"));
            assertNotNull(salary.get("name"));
            assertNotNull(salary.get("pay"));
        }
    }
}

Regards.

Thank you very much!