Java Delegate and JPA Transactions

Hi

I have a Camunda engine running in a Spring Boot Application. I use a Java-Delegate to store some additional information to a database table using JPA. But this does not work.

I googled and I have tried out several approaches but I still run into problems with transaction management.

#approach 1:
Using an autowired JPA repository

public class ColorĹistener implements JavaDelegate, TaskListener {

@Autowired
private ColorRepository myColorRepository;

@Override
public void notify(DelegateTask delegateTask) {
	ElementColor elementColor = new ElementColor();
    elementColor.setColor(...);
  myColorRepository.save(elementColor);         // throws error

> org.springframework.transaction.IllegalTransactionStateException: 
>   Pre-bound JDBC Connection found! JpaTransactionManager does not support running within DataSourceTransactionManager 
>   if told to manage the DataSource itself. It is recommended to use a single JpaTransactionManager for all transactions 
>   on a single DataSource, no matter whether JPA or JDBC access.
> 	at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:359)
> 	at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373)
> 	at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:430)
> 	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:276)
> 	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
> 	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
> 	at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
> 	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
> 	at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133)
> 	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
> 	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
> 	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
> 	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
> 	at com.sun.proxy.$Proxy113.save(Unknown Source)

approach 2

Using an EntityManager

public class ColorĹistener implements JavaDelegate, TaskListener {

private EntityManager entityManager;

@PersistenceContext (unitName = "bpm-persistenceUnit")
public void setEntityManager(EntityManager entityManager) {
    this.entityManager = entityManager;
}

@Override
public void notify(DelegateTask delegateTask) {
	ElementColor elementColor = new ElementColor();
    elementColor.setColor(...);
  this.entityManager.persist(elementColor);           // works, but color not stored to DB
  this.entityManager.flush();                         // throws error

  javax.persistence.TransactionRequiredException: 
  Exception Description: No transaction is currently active
    at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionWrapper.throwCheckTransactionFailedException(EntityTransactionWrapper.java:87)
    at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionWrapper.checkForTransaction(EntityTransactionWrapper.java:50)
    at org.eclipse.persistence.internal.jpa.EntityManagerImpl.checkForTransaction(EntityManagerImpl.java:2052)
    at org.eclipse.persistence.internal.jpa.EntityManagerImpl.flush(EntityManagerImpl.java:874)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:347)
    at com.sun.proxy.$Proxy91.flush(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298)
    at com.sun.proxy.$Proxy91.flush(Unknown Source)

#approach 3

same as #2 but using explicit tx-managemen

try {
EntityTransaction etx = this.entityManager.getTransaction();
etx.begin();
this.entityManager.persist(elementColor);
this.entityManager.flush();
etx.commit();

} catch (Exception exc) {
exc.printStackTrace();
}

java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:248)
at com.sun.proxy.$Proxy91.getTransaction(Unknown Source)

I also tried to add
@Transactional(propagation = Propagation. …, transactionManager = “bpmTransactionManager”)
to the servcie method, but this does not help

Do you have any idea how to solve this problem?

Thanks and best regards,
Roland

Hi @Roland,
it actually must be rather straightforward. Have you checked this test? https://github.com/camunda/camunda-bpm-spring-boot-starter/blob/master/starter/src/test/java/org/camunda/bpm/spring/boot/starter/CamundaJpaAutoConfigurationIT.java

Hi @sdorokhova
thanks for reply. It’s working now. There were several problems.

  • Since we used multiple datasources, during bootstrap process several config files were started.
    In one of these files, the names of the datasources and transaction managers were not unique.
    So during runtime some of the artefacts were overriden.

After fixing these incorrect config we could access the repository

public class ColorĹistener implements JavaDelegate, TaskListener {

@Autowired
private ColorRepository myColorRepository;

  @Override

private void updateColor(String processDefinitionId, String processInstanceId, String elementKey) {

  	TransactionTemplate template = new TransactionTemplate(bpmPlatformTransactionManager);
  	template.execute(new TransactionCallbackWithoutResult() {
  		
  	    @Override
  	    protected void doInTransactionWithoutResult(TransactionStatus status) {
  	    	try {
  	           	 ElementColor elementColor = = natProcessDiagramColorRepository.findById(key);
  	           	...
  	    	} catch (Exception e) {
  	           	  e.printStackTrace();
  	        }
  	     }
  	});				
  	    
  }

}

1 Like