Starting BProc process from EntityListener

Hello,

I am trying to start a BProc process in an AfterCommit event (EntityChangedEvent). Unfortunately I get the error:

15:05:13.252 ERROR o.f.c.e.i.interceptor.CommandContext    - Error while closing command context
org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: org.apache.ibatis.executor.ExecutorException: Error preparing statement.  Cause: java.lang.NullPointerException
### The error may exist in org/flowable/db/mapping/entity/ProcessDefinition.xml
### The error may involve org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntityImpl.selectLatestProcessDefinitionByKey
### The error occurred while executing a query
### SQL: select *     from ACT_RE_PROCDEF      where KEY_ = ? and           (TENANT_ID_ = ''  or TENANT_ID_ is null) and           DERIVED_FROM_ is null and           VERSION_ = (select max(VERSION_) from ACT_RE_PROCDEF where KEY_ = ? and (TENANT_ID_ = '' or TENANT_ID_ is null))
### Cause: org.apache.ibatis.executor.ExecutorException: Error preparing statement.  Cause: java.lang.NullPointerException
	at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30) ~[mybatis-3.5.3.jar:3.5.3]
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:149) ~[mybatis-3.5.3.jar:3.5.3]
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) ~[mybatis-3.5.3.jar:3.5.3]
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:76) ~[mybatis-3.5.3.jar:3.5.3]
	at org.flowable.common.engine.impl.db.DbSqlSession.selectOne(DbSqlSession.java:279) ~[flowable-engine-common-6.5.0.jar:6.5.0]
	at org.flowable.engine.impl.persistence.entity.data.impl.MybatisProcessDefinitionDataManager.findLatestProcessDefinitionByKey(MybatisProcessDefinitionDataManager.java:49) ~[flowable-engine-6.5.0.jar:6.5.0]
	at org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntityManagerImpl.findLatestProcessDefinitionByKey(ProcessDefinitionEntityManagerImpl.java:41) ~[flowable-engine-6.5.0.jar:6.5.0]
	at org.flowable.engine.impl.cmd.StartProcessInstanceCmd.getProcessDefinition(StartProcessInstanceCmd.java:209) ~[flowable-engine-6.5.0.jar:6.5.0]
	at org.flowable.engine.impl.cmd.StartProcessInstanceCmd.execute(StartProcessInstanceCmd.java:111) ~[flowable-engine-6.5.0.jar:6.5.0]
	at org.flowable.engine.impl.cmd.StartProcessInstanceCmd.execute(StartProcessInstanceCmd.java:52) ~[flowable-engine-6.5.0.jar:6.5.0]
	at org.flowable.engine.impl.interceptor.CommandInvoker$1.run(CommandInvoker.java:51) ~[flowable-engine-6.5.0.jar:6.5.0]
	at org.flowable.engine.impl.interceptor.CommandInvoker.executeOperation(CommandInvoker.java:93) ~[flowable-engine-6.5.0.jar:6.5.0]
	at org.flowable.engine.impl.interceptor.CommandInvoker.executeOperations(CommandInvoker.java:72) ~[flowable-engine-6.5.0.jar:6.5.0]
	at org.flowable.engine.impl.interceptor.CommandInvoker.execute(CommandInvoker.java:56) ~[flowable-engine-6.5.0.jar:6.5.0]
	at org.flowable.engine.impl.interceptor.BpmnOverrideContextInterceptor.execute(BpmnOverrideContextInterceptor.java:25) ~[flowable-engine-6.5.0.jar:6.5.0]
...

Full log: exception.txt (75,5 KB)

Here is the call:

@Component("apfueb_PfaendungChangedListener")
public class PfaendungChangedListener {
    ...
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void afterCommit(EntityChangedEvent<Pfaendung, UUID> event) {
        ...
        pfaendungRangService.reassign(pfaendung.getSchuldner()));
    }
    ...
}


@Service(PfaendungRangService.NAME)
@RegisterLockDescriptor(PfaendungRangService.NAME)
public class PfaendungRangServiceBean implements PfaendungRangService {
    ...
     @Override
    public int reassign(BapPerson schuldner) {
         ...
        pfaendungService.startBpmnProzess(pfaendung, "aktivierung-nachrangiger-pfaendung");
    }   
    ...
}


@Service(PfaendungService.NAME)
public class PfaendungServiceBean implements PfaendungService {
    ...
    @Override
    public void startBpmnProzess(Pfaendung pfaendung, String prozessId) {
        final Map<String, Object> processVariables = new HashMap<>();
        processVariables.put("pfaendung", dataManager.reload(pfaendung, "pfaendung.prozess"));
        processVariables.put("currentUser", currentUserService.getUser());
        bprocRuntimeService.startProcessInstanceByKey(
                prozessId,
                pfaendung.getId().toString(),
                processVariables
        );
    }
    ...
}

If I start the process via a screen it works fine. What am I doing wrong?

We are using the latest CUBA version 7.2.13 with the latest BProc on Java 11. Our database is a MySQL 8.

Greetings
Andreas

Hello, does no one have a solution?

Hi!

You should use TransactionalDataManager instead of DataManager during transactions.
Here is small example how it could be implemented:

@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void afterCommit(EntityChangedEvent<NewEntity, UUID> event) {

        try (Transaction transaction = transactionalDataManager.transactions().create()){
            Id<NewEntity, UUID> newEntityUUIDId = event.getEntityId();
            NewEntity newEntity = transactionalDataManager.load(newEntityUUIDId).one();
            Map<String, Object> processVariables = new HashMap<>();
            processVariables.put("name", newEntity.getName());
            processVariables.put("age", newEntity.getAge());
            bprocRuntimeService.startProcessInstanceByKey("process", processVariables);
            transaction.commit();
        } finally {
            transactionalDataManager.transactions().get().close();
        }
    }

Also you can use AfterCommitChangesEvent subscriber in your entity editor and call the bean method in subscriber. Here is an example how it could be implemented:

public class NewEntityEdit extends StandardEditor<NewEntity> {
    
    @Inject
    NewBProcBean bProcBean;

    @Subscribe
    public void onAfterCommitChanges(AfterCommitChangesEvent event) {
        bProcBean.startBPMN(getEditedEntity());
    }
}

The bean

@Component(NewBProcBean.NAME)
public class NewBProcBean {
    public static final String NAME = "ftb_NewBProcBean";

    @Inject
    BprocRuntimeService bprocRuntimeService;

    public void startBPMN(NewEntity entity){
        Map<String, Object> processVariables = new HashMap<>();
        processVariables.put("name", entity.getName());
        processVariables.put("age", entity.getAge());
        bprocRuntimeService.startProcessInstanceByKey("process", processVariables);
    }
}

More information about TransactionalDataManager and AfterCommitChangedEvent.

Regards,
Nadezhda.

1 Like

Hello @n.shatalova,

thank you very much, that was the solution.

Greetings
Andreas